1 2<!DOCTYPE html> 3<html> 4<head> 5 <meta charset="utf-8" /> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, maximum-scale=1.0" /> 7 <meta name="format-detection" content="telephone=no" /> 8 <meta property="og:locale" content="en_US" /> 9 <meta property="og:type" content="website" /> 10 <meta property="og:title" content="STRATTEGY - Plainfield, IL" /> 11 <meta property="og:url" content="https://strattegyinc.com/" /> 12 <meta property="og:image" content="https://du9m0k402rjmo.cloudfront.net/images/P_41272/97f38f38-a992-43d1-bc14-d08287fc0e6f.jpg" /> 13 <meta property="og:description" content="Strattegy is a leading window tinting provider based in Plainfiled, proudly serving the surrounding areas with excellence and professionalism. Specializing in automotive, commercial, and residential window tinting, we deliver superior results with every application. Our experienced team uses premium materials and precise installation techniques to ensure long-lasting performance, enhanced privacy, reduced glare, and protection from harmful UV rays. Whether youâre looking to upgrade your vehicle, improve energy efficiency in your home, or enhance your commercial space, we provide customized solutions tailored to your needs. 14 15Formerly known as Tint to U, we are now Strattegy! While our name has changed, we are still the same owners delivering the same great service and trusted quality our customers rely on. Make Strattegy your first choice for professional window tinting in Orland Park. Call us today at 815-782-8560." /> 16 <meta name="description" content="Strattegy is a leading window tinting provider based in Plainfiled, proudly serving the surrounding areas with excellence and professionalism. Specializing in automotive, commercial, and residential window tinting, we deliver superior results with every application. Our experienced team uses premium materials and precise installation techniques to ensure long-lasting performance, enhanced privacy, reduced glare, and protection from harmful UV rays. Whether youâre looking to upgrade your vehicle, improve energy efficiency in your home, or enhance your commercial space, we provide customized solutions tailored to your needs. 17 18Formerly known as Tint to U, we are now Strattegy! While our name has changed, we are still the same owners delivering the same great service and trusted quality our customers rely on. Make Strattegy your first choice for professional window tinting in Orland Park. Call us today at 815-782-8560." /> 19 <meta name="title" content="STRATTEGY - Plainfield IL" /> 20 <meta name="keywords" content="Window Tint,Window Tinting,Window Film,Window Film Applications,Security Window Tinting" /> 21 <title>STRATTEGY - Plainfield, IL</title> 22
22<script src="/Scripts/Profile/googleAnalytics.js" type="text/javascript"></script>
vendor: 112 bytes, lines 22-25
22 23 <script type="text/javascript" src="https://www.google.com/recaptcha/api.js" async defer></script> 24 25
25<script src="https://code.jquery.com/jquery-3.5.0.min.js" integrity="sha256-xNzN2a4ltkB44Mc/Jz3pT4iU1cmeR0FkXs4pru/JxaQ=" crossorigin="anonymous"></script>
25 26 27
27<script>window.jQuery || document.write('
27<script src="/scripts/templates/jquery-3.5.0.min.js"><\/script>')</script>
27 28 29
29<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
29 30 31
31<script>if (typeof (Popper) === 'undefined') { document.write('
31<script src="/scripts/templates/popper.min.js"><\/script>') }</script>
31 32 33 <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous"> 34 35 <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous"> 36 37
37<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-mrcBkRTg0HmTfecoh1I+48Ptm7cAe18uN+3GsS5SXXGSwzpjIhJZkxEJ5jYaZmE" crossorigin="anonymous"></script>
37 38 39
39<script>if (typeof ($.fn.modal) === 'undefined') { document.write('
39<script src="/scripts/templates/bootstrap.min.js"><\/script>') }</script>
39 40 41
41<script src="/Scripts/Templates/googleMaps.js" type="text/javascript"></script>
41 42 <link href="/Content/Templates/custom-bootstrap.css" type="text/css" rel="stylesheet" /> 43
43<script src="/Scripts/bootbox.min.js" type="text/javascript"></script>
43 44
44<script src="/Scripts/Profile/jquery.barrating.1.1.4.js" type="text/javascript"></script>
44 45
45<script src="/Scripts/Templates/cleave.min.js" type="text/javascript"></script>
45 46
46<script src="/Scripts/Templates/cleave-phone.us.js" type="text/javascript"></script>
46 47
47<script src="/Scripts/Templates/slick.min.js" type="text/javascript"></script>
47 48 <link href="/Content/Templates/slick.css" type="text/css" rel="stylesheet" /> 49 <link href="/Content/Templates/slick-theme.css" type="text/css" rel="stylesheet" /> 50
50<script src="/Scripts/Templates/googleMapsMultiLocation.js" type="text/javascript"></script>
vendor: 66 bytes, lines 50-51
50 51 <script src="https://www.google.com/recaptcha/api.js?render=
516LcokacUAAAAAH_snk3O5bpdYwjpC5XAuXNLrJLH
vendor: 40 bytes, lines 51-52
51" type="text/javascript"></script> 52
52<script src="https://player.vimeo.com/api/player.js" type="text/javascript"></script>
52 53 54 <link href="/Content/Templates/chatbot.css" type="text/css" rel="stylesheet" /> 55 56 <meta name="viewport" content="width=device-width, user-scalable=yes,initial-scale=1, maximum-scale=2" /> 57 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> 58 59 60 <link href="/Content/Templates/platinum_fonts.css" type="text/css" rel="stylesheet" /> 61 62 <style> 63 :root { 64 --body_font: Montserrat; 65 --header_font: Oxygen; 66 --text_color: 255, 255, 255, 1; 67 --text_color_rgba: rgba(var(--text_color)); 68 --customer_color: #000000; 69 --slogan_font_size: 2.5rem; 70 --slogan_text_color: #BA1D11; 71 --faq_question_text_color: #000000; 72 --post_text_color: 255, 255, 255, 1; 73 --post_text_color_rgba: rgba(var(--post_text_color)); 74 --text-transform: capitalize; 75 --scroll-padding-top: 0px; /* Initial value */ 76 } 77 </style> 78 <link href="/Content/Templates/platinum_1.css" type="text/css" rel="stylesheet" /> 79 80 <link rel="canonical" href="https://strattegyinc.com/"> 81 82
83<script type="application/ld+json"> 84{ 85 "@context": "https://schema.org", 86 "@graph": [ 87 { 88 "@type": "LocalBusiness", 89 "@id": "https://strattegyinc.com/#localbusiness", 90 "name": "STRATTEGY", 91 "url": "https://strattegyinc.com/", 92 "description": "Strattegy is a leading window tinting provider based in Plainfiled, proudly serving the surrounding areas with excellence and professionalism. Specializing in automotive, commercial, and residential window tinting, we deliver superior results with every application. Our experienced team uses premium materials and precise installation techniques to ensure long-lasting performance, enhanced privacy, reduced glare, and protection from harmful UV rays. Whether youâre looking to upgrade your vehicle, improve energy efficiency in your home, or enhance your commercial space, we provide customized solutions tailored to your needs. Formerly known as Tint to U, we are now Strattegy! While our name has changed, we are still the same owners delivering the same great service and trusted quality our customers rely on. Make Strattegy your first choice for professional window tinting in Orland Park. Call us today at 815-782-8560.", 93 "image": "https://du9m0k402rjmo.cloudfront.net/images/P_41272/97f38f38-a992-43d1-bc14-d08287fc0e6f.jpg", 94 "logo": "https://du9m0k402rjmo.cloudfront.net/images/P_41272/97f38f38-a992-43d1-bc14-d08287fc0e6f.jpg", 95 "address": { 96 "@type": "PostalAddress", 97 "streetAddress": "23824 W. Andrew Rd, Unit 102", 98 "addressLocality": "Plainfield", 99 "addressRegion": "IL", 100 "postalCode": "60585", 101 "addressCountry": "US" 102 }, 103 "telephone": "(815) 782-8560", 104 "email": "[email protected]", 105 "geo": { 106 "@type": "GeoCoordinates", 107 "latitude": 41.6601771, 108 "longitude": -88.1999355 109 }, 110 "openingHoursSpecification": [ 111 { 112 "@type": "OpeningHoursSpecification", 113 "dayOfWeek": "Monday", 114 "opens": "09:00", 115 "closes": "17:00" 116 }, 117 { 118 "@type": "OpeningHoursSpecification", 119 "dayOfWeek": "Wednesday", 120 "opens": "09:00", 121 "closes": "17:00" 122 }, 123 { 124 "@type": "OpeningHoursSpecification", 125 "dayOfWeek": "Friday", 126 "opens": "09:00", 127 "closes": "17:00" 128 } 129 ], 130 "paymentAccepted": "American Express, Android Pay, Apple Pay, Personal Checks, Debit Cards, Discover, MasterCard, Visa", 131 "sameAs": [ 132 "https://www.yelp.com/biz/tint-to-u-plainfield", 133 "https://www.facebook.com/TintToUGlass/" 134 ] 135 }, 136 { 137 "@type": "WebSite", 138 "@id": "https://strattegyinc.com/#website", 139 "url": "https://strattegyinc.com/", 140 "name": "STRATTEGY", 141 "description": "Strattegy is a leading window tinting provider based in Plainfiled, proudly serving the surrounding areas with excellence and professionalism. Specializing in automotive, commercial, and residential window tinting, we deliver superior results with every application. Our experienced team uses premium materials and precise installation techniques to ensure long-lasting performance, enhanced privacy, reduced glare, and protection from harmful UV rays. Whether youâre looking to upgrade your vehicle, improve energy efficiency in your home, or enhance your commercial space, we provide customized solutions tailored to your needs. Formerly known as Tint to U, we are now Strattegy! While our name has changed, we are still the same owners delivering the same great service and trusted quality our customers rely on. Make Strattegy your first choice for professional window tinting in Orland Park. Call us today at 815-782-8560.", 142 "potentialAction": { 143 "@type": "SearchAction", 144 "target": "https://strattegyinc.com/?s={search_term_string}", 145 "query-input": "required name=search_term_string" 146 } 147 }, 148 { 149 "@type": "WebPage", 150 "@id": "https://strattegyinc.com/#webpage", 151 "url": "https://strattegyinc.com/", 152 "name": "STRATTEGY - Plainfield, IL", 153 "description": "Strattegy is a leading window tinting provider based in Plainfiled, proudly serving the surrounding areas with excellence and professionalism. Specializing in automotive, commercial, and residential window tinting, we deliver superior results with every application. Our experienced team uses premium materials and precise installation techniques to ensure long-lasting performance, enhanced privacy, reduced glare, and protection from harmful UV rays. Whether youâre looking to upgrade your vehicle, improve energy efficie
153ncy in your home, or enhance your commercial space, we provide customized solutions tailored to your needs. Formerly known as Tint to U, we are now Strattegy! While our name has changed, we are still the same owners delivering the same great service and trusted quality our customers rely on. Make Strattegy your first choice for professional window tinting in Orland Park. Call us today at 815-782-8560.", 154 "isPartOf": { 155 "@id": "https://strattegyinc.com/#website" 156 }, 157 "about": { 158 "@id": "https://strattegyinc.com/#localbusiness" 159 }, 160 "primaryImageOfPage": { 161 "@type": "ImageObject", 162 "url": "https://du9m0k402rjmo.cloudfront.net/images/P_41272/97f38f38-a992-43d1-bc14-d08287fc0e6f.jpg" 163 }, 164 "breadcrumb": { 165 "@type": "BreadcrumbList", 166 "itemListElement": [ 167 { 168 "@type": "ListItem", 169 "position": 1, 170 "name": "Home", 171 "item": "https://strattegyinc.com/" 172 } 173 ] 174 } 175 }, 176 { 177 "@type": "Service", 178 "@id": "https://strattegyinc.com/#service", 179 "name": "Our Services", 180 "provider": { 181 "@id": "https://strattegyinc.com/#localbusiness" 182 }, 183 "serviceType": [ 184 "Free Estimates", 185 "2-Car Door Window Tinting", 186 "4-Car Door Window Tinting", 187 "Installation", 188 "Window Tinting", 189 "Commercial Window Tinting", 190 "Residential Window Tinting", 191 "Fleet Graphic & Services", 192 "Keep your fleet looking professional, compliant, and job-ready with our full lineup of custom vehicle enhancement and safety solutions:", 193 "⢠Fleet Graphics - Custom-designed vinyl graphics for trucks, vans, and trailers", 194 "⢠Construction Based Strobe Lighting & Warning Systems", 195 "⢠Bed Liners", 196 "⢠Bed covers", 197 "⢠Floor Mats", 198 "⢠Dash Cameras" 199 ], 200 "description": "Professional services offered by STRATTEGY" 201 }, 202 { 203 "@type": "Service", 204 "@id": "https://strattegyinc.com/#service1", 205 "name": "Automotive Window Tinting", 206 "provider": { 207 "@id": "https://strattegyinc.com/#localbusiness" 208 }, 209 "serviceType": "Automotive Window Tinting", 210 "description": "Protect and enhance your vehicle with professional automotive window tinting from Strattegy in Plainfield. Our expert team installs high-quality window films that reduce glare, block harmful UV rays, and improve comfort year-round. From front door tinting to full 4-door packages, we deliver precise, seamless installation for a sleek, factory-quality finish. Tinting protects your interior from fading and cracking, adds privacy, and improves the overall appearance of your vehicle. With premium materials and expert craftsmanship, Strattegy ensures long-lasting results that combine style, protection, and performance every time." 211 }, 212 { 213 "@type": "Service", 214 "@id": "https://strattegyinc.com/#service2", 215 "name": "Residential Window TInting", 216 "provider": { 217 "@id": "https://strattegyinc.com/#localbusiness" 218 }, 219 "serviceType": "Residential Window TInting", 220 "description": "Enhance your homeâs comfort, style, and energy efficiency with Strattegyâs residential window tinting services in Plainfield. Our premium window films reduce glare, block harmful UV rays, and help regulate indoor temperatures year-round. Tinting protects furniture, flooring, and décor from sun damage while increasing privacy without sacrificing natural light. Choose from solar control, decorative, or specialty films to complement your homeâs design and meet your unique needs. With meticulous installation and attention to detail, Strattegy provides long-lasting results that enhance comfort, improve energy efficiency, and deliver professional-quality finishes homeowners can rely on." 221 }, 222 { 223 "@type": "Service", 224 "@id": "https://strattegyinc.com/#service3", 225 "name": "Commercial Window Tinting", 226 "provider": { 227 "@id": "https://strattegyinc.com/#localbusiness" 228 }, 229 "serviceType": "Commercial Window Tinting", 230 "description": "Improve efficiency, comfort, and appearance with Strattegyâs commercial window tinting services in Plainfield. Our commercial films help reduce heat, glare, and energy costs while adding privacy and security to your workspace. We provide solar control films, safety and security films, anti-graffiti solutions, and custom options tailored to your business needs. Our experienced team installs every project with precision, ensuring durability, professional finishes, and long-term performance. From small office
230s to large commercial spaces, Strattegy helps businesses maintain a polished, comfortable environment while protecting assets and enhancing both functionality and aesthetics." 231 }, 232 { 233 "@type": "Service", 234 "@id": "https://strattegyinc.com/#service4", 235 "name": "Fleet Graphics & Services", 236 "provider": { 237 "@id": "https://strattegyinc.com/#localbusiness" 238 }, 239 "serviceType": "Fleet Graphics & Services", 240 "description": "Keep your fleet looking professional, compliant, and job-ready with our full lineup of custom vehicle enhancement and safety solutions: ⢠Fleet Graphics - Custom-designed vinyl graphics for trucks, vans, and trailers ⢠Construction Based Strobe Lighting & Warning Systems ⢠Bed Liners ⢠Bed covers ⢠Floor Mats ⢠Dash Cameras Donât see what you're looking for? Give us a call and let us chat! - Weâre happy to customize solutions to fit your exact needs." 241 }, 242 { 243 "@type": "FAQPage", 244 "@id": "https://strattegyinc.com/#faqpage", 245 "url": "https://strattegyinc.com/#faq", 246 "name": "Frequently Asked Questions", 247 "description": "Frequently asked questions about STRATTEGY", 248 "mainEntity": [ 249 { 250 "@type": "Question", 251 "name": "What types of window tinting services do you offer?", 252 "acceptedAnswer": { 253 "@type": "Answer", 254 "text": "We specialize in automotive, residential, and commercial window tinting, using high-quality films designed for heat rejection, UV protection, and enhanced privacy." 255 } 256 }, 257 { 258 "@type": "Question", 259 "name": "How long does it take to tint a vehicle?", 260 "acceptedAnswer": { 261 "@type": "Answer", 262 "text": "Most vehicle tinting jobs are completed within 1 to 2 hours, depending on the number of windows and whether any old tint needs to be removed." 263 } 264 }, 265 { 266 "@type": "Question", 267 "name": "How dark can I tint my windows legally in Illinois?", 268 "acceptedAnswer": { 269 "@type": "Answer", 270 "text": "Illinois law requires that front side windows allow at least 35% of visible light through. Rear and back windows can be darker, depending on the vehicle type. We stay current with state regulations and will help you choose a tint that looks great and stays compliant." 271 } 272 }, 273 { 274 "@type": "Question", 275 "name": "Do you offer warranties on your tinting services?", 276 "acceptedAnswer": { 277 "@type": "Answer", 278 "text": "We offer limited warranties on our tinting services, which cover issues like bubbling, peeling, and fading for a set period. Warranty terms vary by film typeâplease ask us for details when booking." 279 } 280 }, 281 { 282 "@type": "Question", 283 "name": "Will window tint affect my GPS, radio, or cell signal?", 284 "acceptedAnswer": { 285 "@type": "Answer", 286 "text": "No. We use non-metallic, signal-safe films that do not interfere with electronic devices, ensuring your GPS, radio, and mobile connectivity remain unaffected." 287 } 288 } 289 ] 290 } 291 ] 292} 293</script>
293</head> 294<body> 295 <div id="bootstrapCssTest" class="d-none"></div> 296
296<script> 297 $(function () { 298 299 if ($('#bootstrapCssTest').is(':visible')) { 300 $("head").prepend('<link rel="stylesheet" href="/content/templates/bootstrap.min.css">'); 301 } 302 }); 303 </script>
303 304 305 306 307 308<input type="hidden" id="areaMarkers" /> 309<input type="hidden" id="selectedServiceId" value="" /> 310 311<!-- NAVBAR --> 312<div class="container-fullwidth fixed-top"> 313 314 315 316 317 318<header id="headernav" class="content-header custom-background-color d-flex flex-wrap align-items-center justify-content-between py-0 px-2"> 319 320 321 <div class="nav-phone-social pb-1 d-flex flex-wrap justify-content-center"> 322 <div class="my-1 header-address d-flex flex-wrap justify-content-center"> 323 <div class="nav-phone text-center nav-header-item-no-spacing mx-1"><a id="PhoneNav" class="text-font-color phone-nav-mobile" href="tel:8157828560"><i class="fas fa-phone fa-inverse fa-xs fa-rotate-90 mr-1"></i>(815) 782-8560</a></div> 324 <div class="nav-phone text-center nav-header-item-no-spacing mx-1 px-1"><a id="eMailNav" class="text-font-color phone-nav-mobile text-lowercase" href="mailto:[email protected]" target="_blank"><i class="fas fa-envelope fa-inverse fa-sm mr-1"></i>[email protected]</a></div> 325 </div> 326 </div> 327 328 329 <div class="nav-phone-social pb-1 d-flex flex-wrap justify-content-center"> 330 <div class="nav-social mx-1 px-1"> 331 <div class="mx-auto text-center d-flex flex-wrap justify-content-center"> 332 <div class="mt-1 mb-1 ml-2 mr-2"> 333 <a class="text-font-color social-link-footer" href="https://www.facebook.com/TintToUGlass/" target="_blank" id="facebook-social-footer" title="Facebook"> 334 <i class="fab fa-facebook-f fa-lg"></i> 335 </a> 336 </div> 337 <div class="mt-1 mb-1 ml-2 mr-2"> 338 <a class="text-font-color social-link-footer" href="https://www.yelp.com/biz/tint-to-u-plainfield" target="_blank" id="yelp-social-footer" title="Yelp"> 339 <i class="fab fa-yelp fa-lg"></i> 340 </a> 341 </div> 342 </div> 343 </div> 344 </div> 345</header> 346 347 348<nav class="bg-default-color bg-light navbar navbar-light navbar-expand-xl pt-1"> 349 350 <div class="nav-image bg-default-color bg-light flex-column text-center nav-image-desktop"> 351 <a href="#home-section" class="navbar-brand ml-3" id="HomeNav" onclick="DisplayPage('#homePage')"> 352 <img src="https://du9m0k402rjmo.cloudfront.net/images/P_41272/97f38f38-a992-43d1-bc14-d08287fc0e6f.jpg" alt="navbar logo" class="d-line-block align-top nav-logo-medium" /> 353 </a> 354 </div> 355 356 <button class="navbar-toggler nav-menu collapsed" type="button" data-toggle="collapse" data-target="#navbarToggler" aria-controls="navbarToggler" aria-expanded="false" aria-label="Toggle navigation"> 357 <span class="navbar-toggler-icon"></span> 358 <span class="my-1 mx-2 close">X</span> 359 </button> 360 361 <div class="collapse navbar-collapse flex-column mx-auto" id="navbarToggler"> 362 363 <div class="d-none d-xl-block nav-section"> 364 <div class="navbar-nav d-flex flex-wrap align-items-center"> 365 366 367<div class="col nav-item text-center nav-header-item mx-auto text-nowrap"> <a href="#" id="HomePageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#homePage')">Home</a> 368</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap"> <a href="#" id="AboutPageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#aboutPage')">About</a> 369</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap"> <a href="#" id="PhotosNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#imageryPage')">Gallery</a> 370</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap"> <a href="#" id="ServicesPageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#servicesPage')">Services</a> 371</div>
371<div class="col nav-item text-center nav-header-item mx-auto text-nowrap"> <a href="#" id="testimonialsPageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#testimonialsPage')">Testimonials</a> 372</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap"> <a href="#" id="FaqPageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#faqPage')">FAQ</a> 373</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap"> <a href="#" id="ContactPageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#contactPage')">Contact</a> 374</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap"> <a href="#" id="DocumentPageNavigationLink" class="nav-link header-font p-3 dropdown-toggle" data-toggle="dropdown">More Info</a> 375 <ul class="dropdown-menu fade-up"> 376 <li><a target="_blank" href="https://strattegyinc.com/optimamedia/products/P_41272/98e4d04b-bdee-4024-8ffa-9dbfeb57d21c.jpg" class="dropdown-item">Price List</a></li> 377 <li><a target="_blank" href="https://strattegyinc.com/optimamedia/products/P_41272/3f59b49e-91dc-4a0d-ae92-ee3adc1da456.jpg" class="dropdown-item">Post Install</a></li> 378 </ul> 379</div><div class="col nav-item text-center nav-header-item mx-auto text-nowrap"> <a href="#" id="LocationsPageNavigationLink" class="nav-link header-font p-3" onclick="DisplayPage('#locationsPage')">Locations</a> 380</div> </div> 381 </div> 382 383 <div class="d-xs-block d-xl-none"> 384 <ul class="navbar-nav mx-auto mr-auto mt-2 mt-xl-0 mb-2"> 385 386 387<li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap"> <a href="#" id="HomePageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#homePage')">Home</a> 388</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap"> <a href="#" id="AboutPageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#aboutPage')">About</a> 389</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap"> <a href="#" id="PhotosNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#imageryPage')">Gallery</a> 390</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap"> <a href="#" id="ServicesPageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#servicesPage')">Services</a> 391</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap"> <a href="#" id="testimonialsPageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#testimonialsPage')">Testimonials</a> 392</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap"> <a href="#" id="FaqPageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#faqPage')">FAQ</a> 393</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap"> <a href="#" id="ContactPageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#contactPage')">Contact</a> 394</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap"> <a href="#" id="DocumentPageNavigationLink" class="nav-link header-font pl-3 dropdown-toggle" data-toggle="dropdown">More Info</a> 395 <ul class="dropdown-menu"> 396 <li><a target="_blank" href="https://strattegyinc.com/optimamedia/products/P_41272/98e4d04b-bdee-4024-8ffa-9dbfeb57d21c.jpg" class="dropdown-item">Price List</a></li> 397 <li><a target="_blank" href="https://strattegyinc.com/optimamedia/products/P_41272/3f59b49e-91dc-4a0d-ae92-ee3adc1da456.jpg" class="dropdown-item">Post Install</a></li> 398 </ul> 399</li><li class="nav-header-item-no-spacing mr-1 ml-1 text-nowrap"> <a href="#" id="LocationsPageNavigationLink" class="nav-link header-font pl-3" onclick="DisplayPage('#locationsPage')">Locations</a> 400</li> </ul> 401 </div> 402 </div> 403</nav> 404</div> 405 406<div id="pages" class="pages-left-medium"> 407 <!--Home Page Information--> 408 <div class="content collapse show bg-alt-color" id="homePage"> 409 410<div class="d-flex flex-wrap"> 411 412 <div class="w-100 mx-auto home-banner"> 413 <div id="homepagebanner" class="parallax w-100 aspect-ratio-16x9"> 414 <div class="img-fluid banner-image"><object data="https://fast.wistia.com/embed/medias/t2cdx8ovzc?fitStrategy=cover&endVideoBehavior=loop&controlsVisibleOnLoad=false&autoPlay=true&volumeControl=false&muted=true&playbar=false&smallPlayButton=false&settingsControl=false&control-bar-right=false" style="width: 100%; height: 100%;" onload="jQuery('.w-css-reset').hide(); jQuery('.w-bottom-bar').hide(); jQuery('.w-ui-container').remove(); "></object></div> 415 416 <div class="home-content"> 417 <div class="d-flex flex-wrap justify-content-center align-items-center px-2"></div> 418 </div> 419 </div> 420 </div> 421 <div class="d-flex align-items-center justify-content-center col-12 text-center mx-auto p-3 slogan" id="slogan"> 422 Orland Park & Plainfieldâs Premier Window Tint Company 423 </div> 424 425 <div class="w-100 w-lg-80 w-sm-90 w-md-90 mx-auto p-2"> 426 <div class="d-flex flex-row flex-wrap justify-content-center text-left py-2"> 427 <div class="col-md mx-auto text-center pt-2"> 428 <img alt="Image" src="https://du9m0k402rjmo.
428cloudfront.net/images/P_41272/3ac0b3ec-3364-4667-bdad-262c487a6fd0.png" class="img-fluid mx-auto text-center" /> 429 </div> 430 <div class="col-md pt-2"> 431 <div class="mx-auto mb-2 section-information"> 432 <div class="strike"> 433 <span class="text-center header-item">About Us</span> 434 </div> 435 </div> 436 <div class="mx-auto mb-2 description-speakable" style="white-space: pre-line">Strattegy is a leading window tinting provider based in Plainfiled, proudly serving the surrounding areas with excellence and professionalism. Specializing in automotive, commercial, and residential window tinting, we deliver superior results with every application. Our experienced team uses premium materials and precise installation techniques to ensure long-lasting performance, enhanced privacy, reduced glare, and protection from harmful UV rays. Whether youâre looking to upgrade your vehicle, improve energy efficiency in your home, or enhance your commercial space, we provide customized solutions tailored to your needs. 437 438Formerly known as Tint to U, we are now Strattegy! While our name has changed, we are still the same owners delivering the same great service and trusted quality our customers rely on. Make Strattegy your first choice for professional window tinting in Orland Park. Call us today at 815-782-8560.</div> 439 </div> 440 </div> 441 </div> 442 443 <div class="w-100 w-lg-80 w-sm-90 w-md-90 mx-auto p-2" id="photos-content"> 444 <div class="mx-auto mb-2 section-information"> 445 <div class="strike"> 446 <span class="text-center header-item">Highlights</span> 447 </div> 448 </div> 449 <div class="d-flex flex-row flex-wrap justify-content-center py-2"> 450 <div class="w-100 w-lg-30 w-md-30 w-sm-30 mx-auto"> 451 <div class="d-flex flex-wrap"> 452 <div class="col p-2"> 453<a href="#" id="photos-image-element1" class="thumbnail mx-auto d-block"> <img src="https://du9m0k402rjmo.cloudfront.net/images/P_41272/5ce5cc46-5d8d-4f43-a3bf-b0b992f334ac.png" alt="" class="img-fluid d-block rounded mx-auto photo-image" /> 454 <div class="text-center pt-2" style="color:black">Automotive Window Tinting</div> 455 </a> </div> 456 </div> 457 </div> 458 <div class="w-100 w-lg-30 w-md-30 w-sm-30 mx-auto"> 459 <div class="d-flex flex-wrap"> 460 <div class="col p-2"> 461<a href="#" id="photos-image-element2" class="thumbnail mx-auto d-block"> <img src="https://du9m0k402rjmo.cloudfront.net/images/P_41272/3e56865f-ea65-48b4-af20-6ebcd004a159.png" alt="" class="img-fluid d-block rounded mx-auto photo-image" /> 462 <div class="text-center pt-2" style="color:black">Residential & Commerical Window Tinting</div> 463 </a> </div> 464 </div> 465 </div> 466 <div class="w-100 w-lg-30 w-md-30 w-sm-30 mx-auto"> 467 <div class="d-flex flex-wrap"> 468 <div class="col p-2"> 469<a href="#" id="photos-image-element3" class="thumbnail mx-auto d-block"> <img src="https://du9m0k402rjmo.cloudfront.net/images/P_41272/021e52d0-8de3-47e3-b65f-521c5c879253.png" alt="" class="img-fluid d-block rounded mx-auto photo-image" /> 470 <div class="text-center pt-2" style="color:black">Fleet Graphics & Services</div> 471 </a> </div> 472 </div> 473 </div> 474 </div> 475 </div> 476 477</div> 478 479 </div> 480 481 <!--About Page Information--> 482 <div class="content collapse bg-alt-color" id="aboutPage"></div> 483 484 <!--Services Page Information--> 485 <div class="content collapse bg-alt-color" id="servicesPage"></div> 486 487 <!--Testimonial Page Information--> 488 <div class="content collapse bg-alt-color" id="testimonialsPage"></div> 489
490 <!-- REVIEW MODAL --> 491 <div id="reviewFormParentContainer"></div> 492 493 <!--Contact Page Information--> 494 <div class="content collapse bg-alt-color" id="contactPage"></div> 495 496 <!--Imagery Page Information--> 497 <div class="content collapse bg-alt-color" id="imageryPage"></div> 498 499 <!--Posts Page Information--> 500 501 <!--Locations Page Information--> 502 <div class="content collapse bg-alt-color" id="locationsPage"></div> 503 504 <!--FAQ Page Information--> 505 <div class="content collapse bg-alt-color" id="faqPage"></div> 506 507 <!--Additional Content Page Information--> 508 <div class="content collapse bg-alt-color" id="contentPage"></div> 509 510</div> 511 512<!--FOOTER Information--> 513<footer id="footer-container" class="footer custom-background-color"> 514 515 516<div class="container-fluid pt-1"> 517 <div class="row pl-3 pr-3"> 518 <div id="footer-address" class="col-sm-3 col-md-4 col-lg-3 mx-auto d-flex flex-wrap footer-content"> 519 <div class="justify-content-left text-font-color"> 520 <div class="footer-header mb-2 mt-2 text-left text-nowrap">Contact Information</div> 521 <div class="content-large">STRATTEGY</div> 522 <div class="mt-1 content-medium"> 52323824 W. Andrew Rd Unit 102 </div> 524 <div class="content-medium">Plainfield, IL 60585</div> 525 <div class="mt-2 mb-2"> 526 <div class="mx-auto content-medium"> 527 <strong>Phone:</strong> <a id="footer_phoneLink" href="tel:8157828560" class="text-font-color footer-link">(815) 782-8560</a> 528 </div> 529 <div class="mx-auto content-medium"> 530 <strong>Email:</strong> <a id="footer_ContactEmail" title="[email protected]" class="text-font-color break-word-hyphen" href="mailto:[email protected]">info<wbr>@strattegyinc<wbr>.com</a> 531 </div> 532 </div> 533 </div> 534 </div> 535 <div id="footer-hours" class='col-sm-3 col-md-4 col-lg-3 mx-auto footer-content d-flex flex-wrap justify-content-center'> 536 <div class="justify-content-left text-font-color"> 537 <div class="footer-hours-detail business-info-footer"> 538 <div class="row"> 539 <div class="col-12 footer-header mt-2 mb-2 text-nowrap">Our Hours</div> 540 </div> 541 <div class="row"> 542 <div class="col-12 content-medium pt-1 pb-1">Holiday Hours May Vary. Please Call For Details.</div> 543 </div> 544 <div class="row content-medium pt-1 pb-1"> 545 <div class="col-6"> 546 <div class="mr-3 font-weight-bold"> 547 Monday 548 </div> 549 </div> 550 <div class="col-6"> 551 <div class="contact-hours ml-1 text-nowrap"> 552 9:00 AM - 5:00 PM 553 </div> 554 </div> 555 </div> 556 557 558 <div class="row content-medium pt-1 pb-1"> 559 <div class="col-6"> 560 <div class="mr-3 font-weight-bold"> 561 Wednesday 562 </div> 563 </div> 564 <div class="col-6"> 565 <div class="contact-hours ml-1 text-nowrap"> 566 9:00 AM - 5:00 PM 567 </div> 568 </div> 569 </div> 570 571 572 <div class="row content-medium pt-1 pb-1"> 573 <div class="col-6"> 574 <div class="mr-3 font-weight-bold"> 575 Friday 576 </div> 577 </div> 578 <div class="col-6"> 579 <div class="contact-hours ml-1 text-nowrap"> 580 9:00 AM - 5:00 PM 581 </div> 582 </div> 583 </div> 584 585 586 </div> 587 </div> 588 </div> 589 <div id="footer-certificationandassociation" class="col-sm-3 col-md-4 col-lg-3 mx-auto footer-content d-flex flex-wrap"> 590 <div class="justify-content-left text-font-color">
591 <div id="associationsHeader" class="footer-header text-left mb-2 mt-2 text-nowrap">Associations</div> 592 <div id="associations">International Window Film Association (IWFA)</div> 593 </div> 594 </div> 595 <div id="footer-sitenav" class='col-sm-3 col-md-4 col-lg-3 mx-auto footer-content d-flex flex-wrap justify-content-center'> 596 <div class="justify-content-left text-font-color"> 597 <div class="footer-header text-left mb-2 mt-2 text-nowrap">Site Navigation</div> 598 599 600<div class="text-left content-medium mx-auto text-nowrap pb-1"> <a href="#" id="HomePageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#homePage')">Home</a> 601</div><div class="text-left content-medium mx-auto text-nowrap pb-1"> <a href="#" id="AboutPageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#aboutPage')">About</a> 602</div><div class="text-left content-medium mx-auto text-nowrap pb-1"> <a href="#" id="PhotosNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#imageryPage')">Gallery</a> 603</div><div class="text-left content-medium mx-auto text-nowrap pb-1"> <a href="#" id="ServicesPageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#servicesPage')">Services</a> 604</div><div class="text-left content-medium mx-auto text-nowrap pb-1"> <a href="#" id="testimonialsPageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#testimonialsPage')">Testimonials</a> 605</div><div class="text-left content-medium mx-auto text-nowrap pb-1"> <a href="#" id="FaqPageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#faqPage')">FAQ</a> 606</div><div class="text-left content-medium mx-auto text-nowrap pb-1"> <a href="#" id="ContactPageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#contactPage')">Contact</a> 607</div><div class="text-left content-medium mx-auto text-nowrap pb-1"> <a href="#" id="DocumentPageNavigationLink" class="text-font-color footer-link dropdown-toggle" data-toggle="dropdown">More Info</a> 608 <ul class="dropdown-menu fade-up"> 609 <li><a target="_blank" href="https://strattegyinc.com/optimamedia/products/P_41272/98e4d04b-bdee-4024-8ffa-9dbfeb57d21c.jpg" class="dropdown-item">Price List</a></li> 610 <li><a target="_blank" href="https://strattegyinc.com/optimamedia/products/P_41272/3f59b49e-91dc-4a0d-ae92-ee3adc1da456.jpg" class="dropdown-item">Post Install</a></li> 611 </ul> 612</div><div class="text-left content-medium mx-auto text-nowrap pb-1"> <a href="#" id="LocationsPageNavigationLink" class="text-font-color footer-link" onclick="DisplayPage('#locationsPage')">Locations</a> 613</div> <div class="text-left content-medium mx-auto text-nowrap"> 614 <a href="/Accessibility?domain=strattegyinc" target="_blank" class="text-font-color footer-link"> 615 Text-Only Site Version 616 </a> 617 </div> 618 </div> 619 </div> 620 </div> 621</div> 622 623<div class="d-flex flex-wrap text-center justify-content-center pb-3 pl-3 pr-3"> 624 <div class="d-flex text-center text-nowrap tos pt-1 w-100 justify-content-center"> 625 <a class="text-font-color" href="/Home/TermsOfUse" id="tosLink" target="_blank">Terms of Use</a><div id="footerdash"> | </div><a class="text-font-color" href="/Home/PrivacyPolicy" id="ppLink" target="_blank">Privacy Policy</a> 626 </div> 627 <div class="d-flex text-center pt-2 w-100 justify-content-center" style="font-size: 0.75rem; color: #999;"> 628 © 2026 American Marketing & Publishing, L.L.C. All rights reserved. Names, logos, and other marks displayed are the property of their respective owners. 629 </div> 630 </div> 631</footer> 632 633 <div class="accessibility-img py-2 px-2"> 634 <div class="d-flex flex-wrap justify-content-center align-items-center text-center"> 635 <a href="/Accessibility?domain=strattegyinc" target="_blank" class="dark"> 636 <img src="/Content/Templates/images/accessibility_icon.png" height="60" width="42" /> 637 </a> 638 </div> 639 </div> 640 641 642 643 644<div class="chatbot-toggle-container"> 645 <button id="chatbot-toggle"> 646 <img src="/Content/Templates/images/chat_icon.png" height="60" width="60" /> 647 </button> 648</div> 649 650<!-- Chat Window --> 651<div id="chat-window"> 652 <!-- Chat Header --> 653 <div class="chat-header"> 654 <div class="chat-header-content"> 655 <h3 class="chat-header-title">STRATTEGY Assistant</h3> 656 </div>
657 <button id="close-chat" class="chat-close-btn" aria-label="Close chat"> 658 <i class="fas fa-times"></i> 659 </button> 660 </div> 661 662 <!-- Chat Messages --> 663 <div id="chat-messages"> 664 <div class="chat-message-container"> 665 <div class="chat-message"> 666 Hi there! How can we help you today? 667 </div> 668 </div> 669 </div> 670 671 <div id="disclaimer-info"> 672 <div class="disclaimer-content"> 673 <div class="disclaimer-text"> 674 AI Responses not guaranteed; verify before reliance 675 </div> 676 </div> 677 </div> 678 679 <!-- Cost Display --> 680 <div id="cost-info"> 681 <div class="cost-info-row"> 682 <div class="cost-info-left"> 683 <i class="fas fa-dollar-sign fa-xs cost-icon"></i> 684 <span id="cost-display">Cost: $0.00000</span> 685 </div> 686 <span id="percentage-display">0.0% of $0.02</span> 687 </div> 688 <div class="cost-progress-bar"> 689 <div id="cost-progress"></div> 690 </div> 691 </div> 692 693 <!-- Chat Input --> 694 <div class="chat-input-container"> 695 <form id="chat-form"> 696 <input type="text" id="chat-input" placeholder="Type your message..." /> 697 <button type="submit" id="send-message"> 698 <i class="fas fa-paper-plane"></i> 699 </button> 700 </form> 701 <div id="character-count">0/250</div> 702 <div id="character-limit-message" style="display: none; color: #dc2626; font-size: 12px; margin-top: 4px;"> 703 Your message is too long. Please limit your question to 250 characters or less. 704 </div> 705 </div> 706</div> 707 708<!-- Contact Form Window --> 709<div id="contact-form-window"> 710 <div class="contact-form-header"> 711 <h3 class="contact-form-title">Contact Form</h3> 712 <button id="close-contact-form" class="contact-form-close-btn" aria-label="Close contact form"> 713 <i class="fas fa-times"></i> 714 </button> 715 </div> 716 717 <div class="contact-form-content"> 718 <form id="chatbot-contact-form"> 719 <input type="hidden" id="chat_captcha_alt" name="chat_captcha_alt" value="aMrx81BQRnqSca+sW1761iMjWaOzgEGZ3FJ117ZW6B1cTFzULVwLML0IisQkDuaz" /> 720 <input type="hidden" id="chat_g-Recaptcha-Response-Contact" name="chat_g-Recaptcha-Response-Contact" value="" /> 721 <input type="hidden" name="chat_aid" value="be59beb5-2284-49a0-929a-dc47969b6691" /> 722 <input type="hidden" name="chat_contactSubject" value="FrontDesk™ Contact Form" /> 723 <input type="hidden" name="chat_contactAddress" value="" /> 724 <input type="hidden" name="chat_contactZip" value="" /> 725 <input type="hidden" name="chat_contactCity" value="" /> 726 <input type="hidden" name="chat_contactState" value="" /> 727 728 <div class="ai-liability mt-1 mb-1">(Messages sent through this site are subject to third party moderation and are not encrypted or secure. We always try to respond as soon as possible, but off-hours inquiries may take us a little longer to reply.)</div> 729 730 <div class="form-group"> 731 <label for="chat_contactName" class="form-label">Name *</label> 732 <input type="text" id="chat_contactName" name="chat_contactName" class="form-input" required /> 733 </div> 734 735 <div class="form-group"> 736 <label for="chat_contactEmail" class="form-label">Email *</label> 737 <input type="email" id="chat_contactEmail" name="chat_contactEmail" class="form-input" required /> 738 </div> 739 740 <div class="form-group"> 741 <label for="chat_contactPhone" class="form-label">Phone</label> 742 <input type="tel" id="chat_contactPhone" name="chat_contactPhone" class="form-input" /> 743 </div> 744 745 <div class="form-group"> 746 <label for="chat_contactMessage" class="form-label">Message *</label> 747 <textarea id="chat_contactMessage" name="chat_contactMessage" rows="4" class="form-textarea" required></textarea> 748 </div> 749 750 <div id="classicCaptcha" class="d-flex flex-column"> 751 <div class="g-recaptcha ml-auto mb-3 captcha-responsive" data-sitekey="6LeprWcUAAAAAF533Xd5p6kCrnRs0z4ceJieYgeO"></div> 752 </div> 753 754 <!-- Sticky footer section with reCAPTCHA disclaimer and submit button --> 755 <div class="form-sticky-footer"> 756 <div class="grecaptcha-info"> 757 This site is protected by reCAPTCHA and the Google 758 <a href="https://policies.google.com/privacy">Privacy Policy</a> and 759 <a href="https://policies.google.com/terms">Terms of Service</a> apply. 760 </div> 761 <button type="submit" id="contact-submit-btn" class="form-submit-btn">Submit</button> 762 </div> 763 </form> 764 </div> 765</div> 766
767<script> 768 // Wrap entire chatbot functionality in a namespace to prevent conflicts 769 window.ChatbotModule = (function() { 770 'use strict'; 771 772 // Private variables 773 let isOpen = false; 774 let contactFormOpen = false; 775 let messages = [ 776 { role: 'assistant', content: 'Hi there! How can we help you today?' } 777 ]; 778 let isLoading = false; 779 let showContactForm = false; 780 let limitReached = false; 781 let apiCost = 0; 782 const maxCost = 0.5; 783 const maxQuestionLength = 250; 784 785 // Private element references 786 let $chatbotToggle; 787 let $chatWindow; 788 let $contactFormWindow; 789 let $closeChat; 790 let $closeContactForm; 791 let $chatMessages; 792 let $chatForm; 793 let $chatInput; 794 let $sendMessage; 795 let $characterCount; 796 let $costDisplay; 797 let $percentageDisplay; 798 let $costProgress; 799 let $contactForm; 800 801 // Initialize element references 802 function initializeElements() { 803 $chatbotToggle = $('#chatbot-toggle'); 804 $chatWindow = $('#chat-window'); 805 $contactFormWindow = $('#contact-form-window'); 806 $closeChat = $('#close-chat'); 807 $closeContactForm = $('#close-contact-form'); 808 $chatMessages = $('#chat-messages'); 809 $chatForm = $('#chat-form'); 810 $chatInput = $('#chat-input'); 811 $sendMessage = $('#send-message'); 812 $characterCount = $('#character-count'); 813 $costDisplay = $('#cost-display'); 814 $percentageDisplay = $('#percentage-display'); 815 $costProgress = $('#cost-progress'); 816 $contactForm = $('#chatbot-contact-form'); 817 } 818 819 // Initialize 820 function init() { 821 // Initialize element references 822 initializeElements(); 823 824 // Load cost from localStorage 825 const savedCost = localStorage.getItem('api_cost'); 826 if (savedCost) { 827 apiCost = parseFloat(savedCost); 828 829 // Check if cost limit is reached 830 if (apiCost >= maxCost) { 831 limitReached = true; 832 updateChatInputState(); 833 } 834 } 835 836 // Initialize character count display 837 updateCharacterCount(); 838 839 document.documentElement.style.setProperty('--adaptive-text-color', '#374151'); 840 document.documentElement.style.setProperty('--image-invert', 'none'); 841 842 setTimeout(updateTextColors, 100); 843 844 // Ensure chatbot stays on top even when modals are opened 845 $(document).on('shown.bs.modal', function (e) { 846 // Temporarily boost chatbot z-index when modals are shown 847 $('.chatbot-toggle-container').css('z-index', '2147483647'); 848 $('#chat-window').css('z-index', '2147483646'); 849 $('#contact-form-window').css('z-index', '2147483645'); 850 }); 851 852 // Set up event listeners 853 setupEventListeners(); 854 } 855 856 // Event Listeners with namespacing 857 function setupEventListeners() { 858 // Remove any existing chatbot event listeners to prevent duplicates 859 $chatbotToggle.off('.chatbot'); 860 $closeChat.off('.chatbot'); 861 $closeContactForm.off('.chatbot'); 862 $chatForm.off('.chatbot'); 863 $chatInput.off('.chatbot'); 864 $contactForm.off('.chatbot'); 865 866 // Toggle chat window 867 $chatbotToggle.on('click.chatbot', function(e) { 868 e.preventDefault(); 869 e.stopPropagation(); 870 toggleChat(); 871 }); 872 873 $closeChat.on('click.chatbot', function(e) { 874 e.preventDefault(); 875 e.stopPropagation(); 876 closeChat(); 877 }); 878 879 $closeContactForm.on('click.chatbot', function(e) { 880 e.preventDefault(); 881 e.stopPropagation(); 882 hideContactForm(); 883 }); 884 885 // Send message 886 $chatForm.on('submit.chatbot', function (e) { 887 e.preventDefault(); 888 e.stopPropagation(); 889 890 // Check if submit button is disabled 891 if ($sendMessage.prop('disabled') || $sendMessage.hasClass('disabled')) { 892 return false; 893 } 894 895 sendMessage(); 896 }); 897 898 // Character count - update on every keystroke 899 $chatInput.on('input.chatbot', function(e) { 900 // Only handle if this is specifically the chatbot input 901 if ($(this).attr('id') === 'chat-input') { 902 updateCharacterCount(); 903 } 904 }); 905 906 // Also check on keyup to catch paste events 907 $chatInput.on('keyup.chatbot paste.chatbot', function(e) { 908 // Only handle if this is specifically the chatbot input 909 if ($(this).attr('id') === 'chat-input') { 910 setTimeout(updateCharacterCount, 10); 911 } 912 }); 913 914 // Handle "Enter" key for sending messages 915 $chatInput.on('keydown.chatbot', function (e) { 916 // Only handle if this is specifically the chatbot input 917 if ($(this).attr('id') !== 'chat-input') { 918 return; 919 } 920 921 if (e.key === 'Enter' && !e.shiftKey && !limitReached) { 922 e.preventDefault(); 923 e.stopImmediatePropagation(); 924 925 // Check if submit button is disabled 926 if ($sendMessage.prop('disabled') || $sendMessage.hasClass('disabled')) { 927 return false; 928 } 929 930 sendMessage(); 931 return; 932 } 933 }); 934 935 // Contact form submission 936 $contactForm.on('submit.chatbot', function (e) { 937 e.preventDefault(); 938 e.stopPropagation(); 939 submitContactForm(); 940 }); 941 } 942 943 // Toggle chat window 944 function toggleChat() { 945 if (!isOpen) { 946 // Opening the chat 947 isOpen = true; 948 949 // Hide toggle button on both mobile and desktop 950 $('.chatbot-toggle-container').addClass('hide-toggle'); 951 952 // First show the window (still off-screen) 953 $chatWindow.show(); 954 955 // Force a reflow to ensure the transition will work 956 $chatWindow[0].offsetHeight; 957 958 // Then add the class that triggers the slide-in animation 959 setTimeout(function () { 960 $chatWindow.addClass('show'); 961 scrollToBottom(); 962 }, 10); 963 } else { 964 // Closing the chat 965 isOpen = false; 966 967 // Show toggle button again 968 $('.chatbot-toggle-container').removeClass('hide-toggle'); 969 970 // Remove the show class to trigger slide-out animation 971 $chatWindow.removeClass('show'); 972 973 // Hide the window after the animation completes 974 setTimeout(function () { 975 $chatWindow.hide(); 976 }, 300); // Match the CSS transition duration 977 978 // Also hide contact form if open 979 if (contactFormOpen) { 980 hideContactForm(); 981 } 982 } 983 } 984 985 // Close chat window 986 function closeChat() { 987 if (isOpen) { 988 isOpen = false; 989 990 // Show toggle button again 991 $('.chatbot-toggle-container').removeClass('hide-toggle'); 992 993 // Trigger slide-out animation 994 $chatWindow.removeClass('show'); 995 996 // Hide after animation 997 setTimeout(function () { 998 $chatWindow.hide(); 999 }, 300); 1000 1001 if (contactFormOpen) { 1002 hideContactForm(); 1003 } 1004 } 1005 } 1006 1007 // Update character count and submit button state 1008 function updateCharacterCount() { 1009 const count = $chatInput.val().length; 1010 const remaining = maxQuestionLength - count; 1011 const $limitMessage = $('#character-limit-message'); 1012 1013 if (count > maxQuestionLength) { 1014 // Over limit - disable submit button and show message 1015 $characterCount.text(`${count}/${maxQuestionLength} (${Math.abs(remaining)} over limit)`).css('color', '#dc2626'); 1016 $limitMessage.text(`Your message is too long. Please limit your question to ${maxQuestionLength} characters or less. Your message is currently ${count} characters.`).show(); 1017 $chatInput.addClass('over-limit'); 1018 1019 // Disable submit button with proper styling 1020 $sendMessage.prop('disabled', true).addClass('disabled'); 1021 $sendMessage.css({ 1022 'background-color': '#9ca3af', 1023 'color': '#6b7280', 1024 'cursor': 'not-allowed', 1025 'opacity': '0.5', 1026 'pointer-events': 'none' 1027 }); 1028 1029 } else if (remaining <= 20) { 1030 // Close to limit - show warning but allow submit 1031 $characterCount.text(`${count}/${maxQuestionLength}`).css('color', '#f59e0b'); 1032 $limitMessage.hide(); 1033 $chatInput.removeClass('over-limit'); 1034 1035 // Enable submit button and reset styling 1036 $sendMessage.prop('disabled', false).removeClass('disabled'); 1037 $sendMessage.css({ 1038 'background-color': '', 1039 'color': '', 1040 'cursor': '', 1041 'opacity': '', 1042 'pointer-events': '' 1043 }); 1044 1045 } else {
1046 // Within limit - normal state 1047 $characterCount.text(`${count}/${maxQuestionLength}`).css('color', '#6b7280'); 1048 $limitMessage.hide(); 1049 $chatInput.removeClass('over-limit'); 1050 1051 // Enable submit button and reset styling 1052 $sendMessage.prop('disabled', false).removeClass('disabled'); 1053 $sendMessage.css({ 1054 'background-color': '', 1055 'color': '', 1056 'cursor': '', 1057 'opacity': '', 1058 'pointer-events': '' 1059 }); 1060 } 1061 } 1062 1063 // Send message 1064 function sendMessage() { 1065 const message = $chatInput.val().trim(); 1066 if (!message || isLoading || limitReached) return; 1067 1068 // Double check character limit including whitespace 1069 if (message.length > maxQuestionLength) { 1070 appendMessage('assistant', `Your message is too long. Please limit your question to ${maxQuestionLength} characters or less. Your message is currently ${message.length} characters.`); 1071 return; 1072 } 1073 1074 // Add user message to chat 1075 messages.push({ role: 'user', content: message }); 1076 appendMessage('user', message); 1077 1078 // Clear input 1079 $chatInput.val(''); 1080 updateCharacterCount(); 1081 1082 // Send to API 1083 fetchChatResponse(messages); 1084 } 1085 1086 // Fetch chat response from API 1087 function fetchChatResponse(messages) { 1088 isLoading = true; 1089 showLoadingIndicator(); 1090 1091 $.ajax({
1092 url: '/Home/Chat', 1093 type: 'POST', 1094 contentType: 'application/json', 1095 data: JSON.stringify({ 1096 Messages: messages, 1097 ProfileId: '41272' 1098 }), 1099 headers: { 1100 'RequestVerificationToken': $('input[name="__RequestVerificationToken"]').val() 1101 }, 1102 success: function (response) { 1103 hideLoadingIndicator(); 1104 1105 if (response.error) { 1106 appendMessage('assistant', `Error: ${response.error}`); 1107 console.error('API Error:', response.error); 1108 isLoading = false; 1109 return; 1110 } 1111 1112 // Update cost 1113 apiCost = response.Cost; 1114 localStorage.setItem('api_cost', apiCost.toString()); 1115 1116 // Check if limit reached 1117 if (response.LimitReached) { 1118 limitReached = true; 1119 showContactFormWindow(); 1120 appendMessage('assistant', 'Our AI chat has reached its capacity. Please use the contact form to get in touch directly with us.'); 1121 } else { 1122 // Check if response contains contact form trigger 1123 if (response.Message.includes('<start_contact_form>')) { 1124 const cleanResponse = response.Message.replace('<start_contact_form>', ''); 1125 appendMessage('assistant', cleanResponse); 1126 showContactFormWindow(); 1127 } else { 1128 appendMessage('assistant', response.Message); 1129 } 1130 1131 // Add response to messages array 1132 messages.push({ role: 'assistant', content: response.Message }); 1133 } 1134 1135 isLoading = false; 1136 updateChatInputState(); 1137 }, 1138 error: function (xhr, status, error) { 1139 hideLoadingIndicator(); 1140 appendMessage('assistant', 'Sorry, I encountered an error. Please try again later.'); 1141 console.error('AJAX Error:', error); 1142 isLoading = false; 1143 } 1144 }); 1145 } 1146 1147 // Append message to chat 1148 function appendMessage(role, content) { 1149 content = convertMarkdownLinksToHTML(content); 1150 const rootStyles = getComputedStyle(document.documentElement); 1151 const customerColor = rootStyles.getPropertyValue('--customer_color').trim(); 1152 const adaptivefontColor = rootStyles.getPropertyValue('--adaptive-text-color').trim(); 1153 1154 const messageClass = role === 'user' ? 'flex-end' : 'flex-start'; 1155 const bgColor = role === 'user' ? customerColor : 'white'; 1156 const textColor = role === 'user' ? adaptivefontColor : '#374151'; 1157 const borderRadius = role === 'user' ? 'border-bottom-right-radius: 0;' : 'border-bottom-left-radius: 0;'; 1158 const border = role === 'user' ? '' : 'border: 1px solid #e5e7eb;'; 1159 1160 const messageHtml = ` 1161 <div style="display: flex; justify-content: ${messageClass}; margin-bottom: 16px;"> 1162 <div style="max-width: 75%; padding: 12px; border-radius: 8px; background-color: ${bgColor}; ${border} ${borderRadius} color: ${textColor}; word-wrap: break-word; overflow-wrap: break-word;"> 1163 ${content} 1164 </div> 1165 </div> 1166 `; 1167 1168 $chatMessages.append(messageHtml); 1169 scrollToBottom(); 1170 } 1171 1172 // Show loading indicator 1173 function showLoadingIndicator() { 1174 const loadingHtml = ` 1175 <div id="loading-indicator" style="display: flex; justify-content: flex-start; margin-bottom: 16px;"> 1176 <div style="max-width: 75%; padding: 12px; border-radius: 8px; background-color: white; border: 1px solid #e5e7eb; color: #374151; display: flex; gap: 4px;"> 1177 <div class="loading-dot" style="width: 8px; height: 8px; background-color: #9ca3af; border-radius: 50%;"></div> 1178 <div class="loading-dot" style="width: 8px; height: 8px; background-color: #9ca3af; border-radius: 50%;"></div> 1179 <div class="loading-dot" style="width: 8px; height: 8px; background-color: #9ca3af; border-radius: 50%;"></div> 1180 </div> 1181 </div> 1182 `; 1183 1184 $chatMessages.append(loadingHtml); 1185 animateLoadingDots(); 1186 scrollToBottom(); 1187 1188 // Disable input while loading 1189 $chatInput.prop('disabled', true); 1190 $sendMessage.prop('disabled', true); 1191 } 1192 1193 // Animate loading dots 1194 function animateLoadingDots() { 1195 if (!$("#loading-indicator").length) return; 1196 1197 $(".loading-dot").each(function (index) { 1198 var $dot = $(this); 1199 setTimeout(function () { 1200 $dot.animate({ opacity: 0.3 }, 300) 1201 .animate({ opacity: 1 }, 300); 1202 }, index * 200); 1203 }); 1204 1205 setTimeout(function () { 1206 animateLoadingDots(); 1207 }, 900); 1208 } 1209 1210 // Hide loading indicator 1211 function hideLoadingIndicator() { 1212 $('#loading-indicator').remove(); 1213 1214 // Enable input after loading (unless limit reached) 1215 if (!limitReached) { 1216 $chatInput.prop('disabled', false); 1217 updateCharacterCount(); // This will set the correct submit button state 1218 } 1219 } 1220 1221 // Scroll to bottom of chat 1222 function scrollToBottom() { 1223 $chatMessages.scrollTop($chatMessages[0].scrollHeight); 1224 } 1225 1226 // Update cost display 1227 function updateCostDisplay() { 1228 $("#cost-info").show(); 1229 $costDisplay.text(`Cost: $${apiCost.toFixed(5)}`); 1230 1231 const percentage = (apiCost / maxCost) * 100; 1232 $percentageDisplay.text(`${percentage.toFixed(1)}% of $${maxCost.toFixed(2)}`); 1233 1234 $costProgress.css('width', `${percentage}%`); 1235
1236 // Change progress bar color if near limit 1237 if (percentage > 80) { 1238 $costProgress.css("background-color", "#dc2626"); 1239 } else { 1240 $costProgress.css("background-color", "#4f46e5"); 1241 } 1242 1243 // Update chat input state 1244 updateChatInputState(); 1245 } 1246 1247 // Update chat input state based on limit 1248 function updateChatInputState() { 1249 if (limitReached) { 1250 $chatInput.prop('disabled', true); 1251 $sendMessage.prop('disabled', true); 1252 $chatInput.attr('placeholder', 'Chat Unavailable.'); 1253 } else { 1254 $chatInput.prop('disabled', false); 1255 updateCharacterCount(); // This will set the correct submit button state 1256 $chatInput.attr('placeholder', 'Type your message...'); 1257 } 1258 } 1259 1260 // Show contact form 1261 function showContactFormWindow() { 1262 if (!contactFormOpen) { 1263 contactFormOpen = true; 1264 1265 // Hide toggle button when contact form opens 1266 $('.chatbot-toggle-container').addClass('hide-toggle'); 1267 1268 if (isMobile()) { 1269 // On mobile, slide out chat and slide in contact form 1270 $chatWindow.removeClass('show'); 1271 setTimeout(function () { 1272 $chatWindow.hide(); 1273 $contactFormWindow.show(); 1274 // Force reflow 1275 $contactFormWindow[0].offsetHeight; 1276 // Add show class for slide animation 1277 setTimeout(function () { 1278 $contactFormWindow.addClass('show'); 1279 $('.contact-form-content').scrollTop(0); 1280 }, 10); 1281 }, 300); 1282 } else { 1283 // Desktop - slide chat to left and slide in contact form 1284 $chatWindow.animate({ right: '390px' }, 300); 1285 $contactFormWindow.show(); 1286 setTimeout(function () { 1287 $contactFormWindow.animate({ right: '20px' }, 300); 1288 }, 50); 1289 } 1290 } 1291 } 1292 1293 // Hide contact form - slides out and chat returns to original position 1294 function hideContactForm() { 1295 if (contactFormOpen) { 1296 contactFormOpen = false; 1297 1298 if (isMobile()) { 1299 // Slide out contact form 1300 $contactFormWindow.removeClass('show'); 1301 1302 setTimeout(function () { 1303 $contactFormWindow.hide(); 1304 // Show chat window again if it was open 1305 if (isOpen) { 1306 $chatWindow.show(); 1307 // Force reflow 1308 $chatWindow[0].offsetHeight; 1309 setTimeout(function () { 1310 $chatWindow.addClass('show'); 1311 }, 10); 1312 } else { 1313 // If chat is not open, show toggle button 1314 $('.chatbot-toggle-container').removeClass('hide-toggle'); 1315 } 1316 }, 300); 1317 } else { 1318 // Desktop - animate back 1319 $contactFormWindow.animate({ right: '-370px' }, 300, function () { 1320 $contactFormWindow.hide(); 1321 }); 1322 $chatWindow.animate({ right: '20px' }, 300); 1323 1324 // Only show toggle if both windows are closed 1325 if (!isOpen) { 1326 $('.chatbot-toggle-container').removeClass('hide-toggle'); 1327 } 1328 } 1329 } 1330 } 1331
1332 // Submit contact form 1333 function submitContactForm() { 1334 const name = $('#chat_contactName').val(); 1335 const email = $('#chat_contactEmail').val(); 1336 const phone = $('#chat_contactPhone').val(); 1337 const message = $('#chat_contactMessage').val(); 1338 1339 // Basic validation 1340 if (!name || !email || !message) { 1341 alert('Please fill out all required fields.'); 1342 return; 1343 } 1344 1345 // Email validation 1346 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; 1347 if (!emailRegex.test(email)) { 1348 alert('Please enter a valid email address.'); 1349 return; 1350 } 1351 1352 // Message length validation 1353 if (message.length < 10) { 1354 alert('Your message must be at least 10 characters long.'); 1355 return; 1356 } 1357 1358 // Disable form during submission 1359 $('#contact-submit-btn').prop('disabled', true).text('Sending...'); 1360 1361 var form = $("#chatbot-contact-form"); 1362 1363 // Execute reCAPTCHA before submitting 1364 grecaptcha.ready(function() { 1365 grecaptcha.execute('6LcokacUAAAAAH_snk3O5bpdYwjpC5XAuXNLrJLH', {action: 'contact_us'}).then(function(token) { 1366 // Set the reCAPTCHA token 1367 $("#chat_g-Recaptcha-Response-Contact").val(token); 1368 1369 // Submit the form with reCAPTCHA token 1370 $.ajax({
1371 url: "/Home/ChatContactPost", 1372 type: 'POST', 1373 data: form.serialize(), 1374 success: function (response) { 1375 if (typeof response === 'string' && response.indexOf('{"message":') != -1) { 1376 var jsonData = JSON.parse(response); 1377 if (jsonData.success) { 1378 appendMessage('assistant', 'Thanks for providing your information! We will get back to you soon.'); 1379 hideContactForm(); 1380 1381 // Reset the form 1382 $('#chat_contactName').val(''); 1383 $('#chat_contactEmail').val(''); 1384 $('#chat_contactPhone').val(''); 1385 $('#chat_contactMessage').val(''); 1386 } else { 1387 alert(jsonData.message || 'There was an error processing your request.'); 1388 } 1389 } else if (response.success) { 1390 appendMessage('assistant', 'Thanks for providing your information! We will get back to you soon.'); 1391 hideContactForm(); 1392 1393 // Reset the form 1394 $('#chat_contactName').val(''); 1395 $('#chat_contactEmail').val(''); 1396 $('#chat_contactPhone').val(''); 1397 $('#chat_contactMessage').val(''); 1398 1399 } else { 1400 alert(response.message || 'There was an error processing your request.'); 1401 } 1402 1403 $('#contact-submit-btn').prop('disabled', false).text('Submit'); 1404 }, 1405 error: function (xhr, status, error) { 1406 alert('Failed to submit your information. Please try again.'); 1407 console.error('AJAX Error:', error); 1408 $('#contact-submit-btn').prop('disabled', false).text('Submit'); 1409 } 1410 }); 1411 }); 1412 }); 1413 } 1414 1415 function convertMarkdownLinksToHTML(text) { 1416 return text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, linkText, url) => { 1417 // Add target="_blank" for http/https links 1418 if (url.startsWith('http://') || url.startsWith('https://')) { 1419 return `<a href="${url}" target="_blank" rel="noopener noreferrer">${linkText}</a>`; 1420 } 1421 // Keep tel: and mailto: links as-is 1422 return `<a href="${url}">${linkText}</a>`; 1423 }); 1424 } 1425 1426 function getLuminance(hex) { 1427 // Remove # if present 1428 hex = hex.replace('#', ''); 1429 1430 // Convert hex to RGB 1431 const r = parseInt(hex.substr(0, 2), 16) / 255; 1432 const g = parseInt(hex.substr(2, 2), 16) / 255; 1433 const b = parseInt(hex.substr(4, 2), 16) / 255; 1434 1435 // Calculate relative luminance 1436 const rLum = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4); 1437 const gLum = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4); 1438 const bLum = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4); 1439 1440 return 0.2126 * rLum + 0.7152 * gLum + 0.0722 * bLum; 1441 } 1442 1443 function isLightColor(hex) { 1444 const luminance = getLuminance(hex); 1445 return luminance > 0.5; // Threshold for light vs dark 1446 } 1447 1448 function updateTextColors() { 1449 const rootStyles = getComputedStyle(document.documentElement); 1450 let customerColor = rootStyles.getPropertyValue('--customer_color').trim(); 1451 1452 // Check if customer color is not set or is empty 1453 if (!customerColor || customerColor === '') { 1454 const defaultColor = '#f3f3f3'; 1455 1456 // Set the default customer color 1457 document.documentElement.style.setProperty('--customer_color', defaultColor); 1458 customerColor = defaultColor; 1459 } 1460 1461 const isLight = isLightColor(customerColor); 1462 const textColor = isLight ? '#000000b3' : '#ffffff'; 1463 1464 const $chatbotToggle = $('#chatbot-toggle'); 1465 if (isLight) { 1466 $chatbotToggle.removeClass('dark-background').addClass('light-background'); 1467 } else { 1468 $chatbotToggle.removeClass('light-background').addClass('dark-background'); 1469 } 1470 1471 // Update the CSS custom property 1472 document.documentElement.style.setProperty('--adaptive-text-color', textColor); 1473 } 1474 1475 function isMobile() { 1476 return window.innerWidth <= 768; 1477 } 1478 1479 // Public interface 1480 return { 1481 init: init 1482 }; 1483 })(); 1484 1485 // Initialize the chatbot module when document is ready 1486 $(document).ready(function () { 1487 if (window.ChatbotModule) {
1488 window.ChatbotModule.init(); 1489 } 1490 }); 1491</script>
1491 1492<div id="loadingImg" class="loader" style="display:none !important"> 1493 <i class="fas fa-circle"></i> 1494 <i class="fas fa-circle"></i> 1495 <i class="fas fa-circle"></i> 1496</div> 1497
1498<script type="text/javascript"> 1499 var isMobile = false; 1500 var isTablet = false; 1501 var itemsVisible = false; // false indicates that items are initially hidden 1502 var pageSize = 5; 1503 var pageIndex = 0; 1504 var hasbanner = false; 1505 var keepPostUp = false; 1506 var listOfSites = ""; 1507 var testimonialPageBackgroundColor = '#000000'; 1508 var numOfPosts = 0; 1509 var postsPageIndex = 0; 1510 var geocode = null; 1511 var selectedServiceId = null; 1512 var servicesRendered = false; 1513 var aboutRendered = false; 1514 var testimonialsRendered = false; 1515 var contactRendered = false; 1516 var photosRendered = false; 1517 var faqRendered = false; 1518 var locationsRendered = false; 1519 var additionalContentRendered = false; 1520 var isSubmittingReview = false; //global flag to track submission 1521 1522 $(document).ready(function () { 1523 if ($("#contact_us_phone").length > 0) { 1524 var cleave = new Cleave('#contact_us_phone', { 1525 phone: true, 1526 phoneRegionCode: 'US' 1527 }); 1528 } 1529 1530 checkMobile(); 1531 checkTablet(); 1532 checkHashRoute(); 1533 PauseVideoPlayer(); 1534 1535 if(hasbanner){ 1536 GetPostsBanner(); 1537 } 1538 1539 $(window).on('hashchange', function(){ 1540 checkHashRoute(); 1541 }); 1542 1543 var navMain = $("#navbarToggler"); 1544 navMain.on("click", "a", null, function () { 1545 navMain.collapse('hide'); 1546 }); 1547 1548 document.addEventListener("visibilitychange", function () { 1549 if (document["hidden"]) { 1550 PauseVideoPlayer(); 1551 } 1552 }); 1553 1554 $(window).scroll(function () { 1555 var scroll = $(window).scrollTop(); 1556 if (('False' == 'False') || ('False' == 'True' && window.outerWidth > 767.98)) { 1557 if (scroll > 150){ 1558 $(".content").addClass("page-section-adjust"); 1559 $(".nav-logo").addClass("nav-logo-adjust"); 1560 $(".nav-location").addClass("nav-item-adjust"); 1561 } 1562 else if(scroll <= 150){ 1563 $(".content").removeClass("page-section-adjust"); 1564 $(".nav-logo").removeClass("nav-logo-adjust"); 1565 $(".nav-location").removeClass("nav-item-adjust"); 1566 } 1567 } 1568 }); 1569 1570 $(document).on("click", "#btnContactPost", function (e) { 1571 $("#btnContactPost").prop('disabled', true); 1572 $("#btnContactPost").css('font-weight', 'normal'); 1573 contactUsPost(e); 1574 }); 1575 1576 var analyticsCategory = "Desktop"; 1577 if (isMobile == true) { 1578 analyticsCategory = "Mobile"; 1579 if ($(window).width() < 576) { 1580 if ($("#headernav").hasClass('justify-content-between')) { 1581 $("#headernav").removeClass('justify-content-between'); 1582 } 1583 if (!$("#headernav").hasClass('justify-content-center')) { 1584 $("#headernav").addClass('justify-content-center'); 1585 } 1586 if ($("#footer-address").hasClass('justify-content-center')) { 1587 $("#footer-address").removeClass('justify-content-center'); 1588 } 1589 if ($("#footer-hours").hasClass('justify-content-center')) { 1590 $("#footer-hours").removeClass('justify-content-center'); 1591 } 1592 if ($("#footer-sitenav").hasClass('justify-content-center')) { 1593 $("#footer-sitenav").removeClass('justify-content-center'); 1594 } 1595 } 1596 } 1597 1598 if (testimonialPageBackgroundColor != null && testimonialPageBackgroundColor != '' && testimonialPageBackgroundColor != "#F5F5F5") { 1599 //set footer background color 1600 $('.custom-background-color').css('background-color', testimonialPageBackgroundColor); 1601 } 1602 else { 1603 //set footer background color to white 1604 var white = "#FFFFFF"; 1605 $('.custom-background-color').css('background-color', white); 1606 } 1607 1608 $("#HomePageNavigationLink").click(function(e){
1609 $('html, body').animate({ scrollTop: 0 }, 'fast'); 1610 }); 1611 1612 $(".business-name").click(function(e){ 1613 $('html, body').animate({ scrollTop: 0 }, 'fast'); 1614 }); 1615 1616 if(numOfPosts > 0){ 1617 GetPostsData(0); 1618 } 1619 1620 $(document).on('click', "#nextPosts", function (e) { 1621 ScrollForPosts(e); 1622 GetPostsData(1); 1623 }); 1624 1625 $(document).on('click', "#prevPosts", function (e) { 1626 ScrollForPosts(e); 1627 GetPostsData(-1); 1628 }); 1629 1630 $(document).on('click', "#postReview", function (e) { 1631 e.preventDefault(); 1632 e.stopPropagation(); 1633 1634 if (isSubmittingReview) { 1635 console.log('Review submission already in progress - blocking duplicate submission'); 1636 return false; 1637 } 1638 1639 var $button = $(this); 1640 var $form = $("#postReviewForm"); 1641 var $modal = $("#reviewFormSection"); 1642 1643 isSubmittingReview = true; 1644 console.log('Starting review submission'); 1645 1646 setProcessingState($button, $form, true); 1647 1648 var alertType = "success"; 1649 1650 if(validateReview("#postReview")) { 1651 console.log('Review validation passed'); 1652 ShowLoading(); 1653 1654 grecaptcha.ready(function() { 1655 grecaptcha.execute('6LcokacUAAAAAH_snk3O5bpdYwjpC5XAuXNLrJLH', {action: 'testimonial_review'}).then(function(token) { 1656 $("#g-Recaptcha-Response-Review").attr("value", token); 1657 1658 var rating = null; 1659 var selectElement = document.getElementById('starRating'); 1660 var selectRating = selectElement ? selectElement.value : null; 1661 var selectedOption = $('#starRating option:selected').val(); 1662 var barRating = null; 1663 var reviewerAlias = $('#review_alias').val() || ''; 1664 var reviewHeading = $('#review_heading').val() || ''; 1665 var antiForgeryToken = $('input[name="__RequestVerificationToken"]').val(); 1666 var recaptchaToken = $('#g-Recaptcha-Response-Review').val(); 1667 var timeToPost = $('#phoneNumber_alternative').val(); 1668 1669 var reviewText = $('#review').val() || ''; 1670 var profileId = 41272; 1671 1672 console.log('Trying to get rating value...'); 1673 1674 var selectRating = $('#starRating')[0] ? $('#starRating')[0].value : null; 1675 console.log('Select element direct value:', selectRating); 1676 1677 var jqueryRating = $('#starRating').val(); 1678 console.log('jQuery val() result:', jqueryRating, typeof jqueryRating); 1679 1680 if (typeof $('#starRating').barrating === 'function') { 1681 try { 1682 var barResult = $('#starRating').barrating('show'); 1683 1684 if (barResult && typeof barResult === 'string') { 1685 barRating = barResult; 1686 } else if (barResult && typeof barResult === 'number') { 1687 barRating = barResult.toString(); 1688 } 1689 } catch (e) { 1690 console.log('Error getting barrating value:', e); 1691 } 1692 } 1693 1694 var selectedOption = $('#starRating option:selected').val(); 1695 console.log('Selected option value:', selectedOption); 1696 1697 var jqueryResult = $('#starRating').val(); 1698 var jqueryRating = null; 1699 1700 if (jqueryResult && typeof jqueryResult === 'string') { 1701 jqueryRating = jqueryResult; 1702 } else if (jqueryResult && typeof jqueryResult === 'number') { 1703 jqueryRating = jqueryResult.toString(); 1704 } 1705 1706 if (barRating && barRating !== "" && barRating !== "0") { 1707 rating = barRating; 1708 } else if (selectRating && selectRating !== "" && selectRating !== "0") { 1709 rating = selectRating; 1710 } else if (selectedOption && selectedOption !== "" && selectedOption !== "0") { 1711 rating = selectedOption; 1712 } else if (jqueryRating && jqueryRating !== "" && jqueryRating !== "0") { 1713 rating = jqueryRating; 1714 } 1715 1716 if (rating && typeof rating !== 'string') { 1717 console.log('WARNING: Rating is not a string, converting:', rating, typeof rating);
1718 rating = String(rating); 1719 } 1720 1721 if (rating && typeof rating === 'object') { 1722 console.error('CRITICAL ERROR: Rating is still an object!', rating); 1723 rating = null; 1724 } 1725 1726 console.log('Validation check - rating found:', rating, typeof rating); 1727 console.log('Final rating value:', rating, typeof rating); 1728 1729 console.log('Form values before sending:'); 1730 console.log('- Review text:', reviewText); 1731 console.log('- Rating:', rating); 1732 console.log('- Profile ID:', profileId); 1733 console.log('- Reviewer alias:', reviewerAlias); 1734 console.log('- Review heading:', reviewHeading); 1735 console.log('- Anti-forgery token:', antiForgeryToken ? 'Present' : 'Missing'); 1736 1737 // Build form data 1738 var formDataArray = [ 1739 { name: 'profile_id', value: profileId }, 1740 { name: 'review', value: reviewText }, 1741 { name: 'review_rating', value: rating }, 1742 { name: 'reviewer_alias', value: reviewerAlias }, 1743 { name: 'review_heading', value: reviewHeading }, 1744 { name: '__RequestVerificationToken', value: antiForgeryToken }, 1745 { name: 'g-Recaptcha-Response-Review', value: recaptchaToken }, 1746 { name: 'phoneNumber_alternative', value: timeToPost }, 1747 { name: '_t', value: new Date().getTime() } 1748 ]; 1749 1750 var formData = formDataArray 1751 .filter(item => item.value !== undefined && item.value !== null && item.value !== '') 1752 .map(item => encodeURIComponent(item.name) + '=' + encodeURIComponent(item.value)) 1753 .join('&'); 1754 1755 console.log('Manual form data built:', formData); 1756 1757 $.ajax({
1758 url: "/Home/ReviewPost", 1759 type: "POST", 1760 data: formData, 1761 contentType: "application/x-www-form-urlencoded; charset=UTF-8", 1762 dataType: "json", 1763 success: function(data) { 1764 console.log('Review submission response:', data); 1765 1766 if (!data.message || data.message.trim() === '') { 1767 data.message = data.success ? 1768 'Thank you for your review! It has been submitted successfully.' : 1769 'There was an issue submitting your review. Please check all fields and try again.'; 1770 } 1771 1772 alertType = data.success ? "success" : "warning"; 1773 1774 if (!data.success) { 1775 recaptchaReviewIncomplete(); 1776 showClassicCaptcha("review"); 1777 } 1778 1779 $form.find('.alert').remove(); 1780 1781 var alertHtml = '<div class="alert alert-' + alertType + ' alert-dismissible" role="alert">' + 1782 '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' + 1783 '<span aria-hidden="true">×</span></button>' + 1784 data.message + '</div>'; 1785 1786 $form.prepend(alertHtml); 1787 1788 $modal.find('.modal-body').scrollTop(0); 1789 1790 if(alertType === "success") { 1791 // Auto-hide modal after showing success message 1792 setTimeout(function () { 1793 $modal.modal('hide'); 1794 ClearReviewFields(); 1795 }, 3000); 1796 } 1797 1798 // Fade out alert after delay 1799 setTimeout(function() { 1800 $form.find('.alert').fadeOut(500, function() { 1801 $(this).remove(); 1802 }); 1803 }, 6000); 1804 }, 1805 error: function(xhr, status, error) { 1806 console.error('AJAX Error:', status, error); 1807 console.error('Response Text:', xhr.responseText); 1808 1809 $form.find('.alert').remove(); 1810 var errorHtml = '<div class="alert alert-danger alert-dismissible" role="alert">' + 1811 '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' + 1812 '<span aria-hidden="true">×</span></button>' + 1813 'An error occurred while submitting your review. Please try again.</div>'; 1814 $form.prepend(errorHtml); 1815 1816 $modal.find('.modal-body').scrollTop(0); 1817 }, 1818 complete: function() { 1819 // Reset states 1820 console.log('Resetting processing state'); 1821 setProcessingState($button, $form, false); 1822 HideLoading(); 1823 isSubmittingReview = false; 1824 console.log('Review submission completed'); 1825 } 1826 }); 1827 1828 }).catch(function(error) { 1829 console.error('reCAPTCHA Error:', error); 1830 1831 $form.find('.alert').remove(); 1832 var captchaErrorHtml = '<div class="alert alert-danger alert-dismissible" role="alert">
1832' + 1833 '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' + 1834 '<span aria-hidden="true">×</span></button>' + 1835 'Security verification failed. Please refresh the page and try again.</div>'; 1836 $form.prepend(captchaErrorHtml); 1837 1838 $modal.find('.modal-body').scrollTop(0); 1839 setProcessingState($button, $form, false); 1840 HideLoading(); 1841 isSubmittingReview = false; 1842 }); 1843 }); 1844 } else { 1845 console.log('Review validation failed'); 1846 1847 var missingFields = []; 1848 if (!$('#review').val() || $('#review').val().trim() === '') { 1849 missingFields.push('review text'); 1850 } 1851 1852 var rating = null; 1853 var selectRating = $('#starRating')[0] ? $('#starRating')[0].value : null; 1854 var jqueryRating = $('#starRating').val(); 1855 var selectedOption = $('#starRating option:selected').val(); 1856 var barRating = null; 1857 1858 if (typeof $('#starRating').barrating === 'function') { 1859 try { 1860 barRating = $('#starRating').barrating('show'); 1861 } catch (e) { 1862 // Ignore error 1863 } 1864 } 1865 1866 if (barRating && barRating !== "" && barRating !== "0") { 1867 rating = barRating; 1868 } else if (selectRating && selectRating !== "" && selectRating !== "0") { 1869 rating = selectRating; 1870 } else if (selectedOption && selectedOption !== "" && selectedOption !== "0") { 1871 rating = selectedOption; 1872 } else if (typeof jqueryRating === 'string' && jqueryRating !== "" && jqueryRating !== "0") { 1873 rating = jqueryRating; 1874 } 1875 1876 console.log('Validation check - rating found:', rating); 1877 1878 if (!rating || rating === "" || rating === "0") { 1879 missingFields.push('rating'); 1880 } 1881 1882 var validationMessage = 'Please fill out the following required fields: ' + missingFields.join(' and ') + '.'; 1883 console.log('Validation message:', validationMessage); 1884 1885 $form.find('.alert').remove(); 1886 var validationHtml = '<div class="alert alert-warning alert-dismissible" role="alert">' + 1887 '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' + 1888 '<span aria-hidden="true">×</span></button>' + 1889 validationMessage + '</div>'; 1890 $form.prepend(validationHtml); 1891 1892 $modal.find('.modal-body').scrollTop(0); 1893 setProcessingState($button, $form, false); 1894 isSubmittingReview = false; 1895 1896 return false; 1897 } 1898 }); 1899 1900 $('#reviewFormSection').on('hidden.bs.modal', function () { 1901 console.log('Modal hidden - resetting submission state'); 1902 isSubmittingReview = false; 1903 setProcessingState($("#postReview"), $("#postReviewForm"), false); 1904 $(this).find('.alert').remove(); 1905 }); 1906 1907 $('#reviewFormSection').on('show.bs.modal', function () { 1908 console.log('Modal shown - ensuring clean state'); 1909 isSubmittingReview = false; 1910 setProcessingState($("#postReview"), $("#postReviewForm"), false); 1911 1912 $("#postReview").prop('disabled', false); 1913 $("#postReview").css('font-weight', 'bold'); 1914 1915 setTimeout(function () { 1916 console.log('=== STAR RATING DEBUG ==='); 1917 console.log('Star rating element:', $('#starRating')[0]); 1918 console.log('Star rating jQuery object:', $('#starRating')); 1919 console.log('Star rating direct value:', $('#starRating')[0] ? $('#starRating')[0].value : 'N/A'); 1920 console.log('Star rating jQuery val():', $('#starRating').val()); 1921 console.log('Star rating selected option:', $('#starRating option:selected').val()); 1922 console.log('Barrating plugin available:', typeof $('#starRating').barrating === 'function'); 1923 if (typeof $('#starRating').barrating === 'function') { 1924 try { 1925 console.log('Barrating current value:', $('#starRating').barrating('show')); 1926 } catch (e) { 1927 console.log('Error getting barrating value:', e); 1928 } 1929 } 1930 console.log('=== END STAR RATING DEBUG ==='); 1931 }, 100); 1932 }); 1933 1934 // Prevent modal from closing during submission 1935 $('#reviewFormSection').on('hide.bs.modal', function (e) { 1936 if (isSubmittingReview) { 1937 console.log('Preventing modal close during submission'); 1938 e.preventDefault(); 1939 return false; 1940 } 1941 }); 1942 1943 $('a').on('click', function () { 1944 if (this.id !== "undefined" && this.id !== "") { 1945 gtag('event', 'Link Click', { 1946 'event_category': analyticsCategory, 1947 'event_label': this.id 1948 }); 1949 } 1950 }); 1951 1952 $('#PhoneNav').on('click', function () { 1953 gtag('event', 'Link Click', { 1954 'event_category': analyticsCategory, 1955 'event_label': "CustomerBusinessPhoneLinkPlatinum1" 1956 }); 1957 }); 1958 $('.phoneLinkInput').on('click', function () { 1959 gtag('event', 'Link Click', { 1960 'event_category': analyticsCategory, 1961 'event_label': "CustomerBusinessPhoneLinkPlatinum1-1" 1962 }); 1963 }); 1964 $('#contactPhoneLink').on('click', function () { 1965 gtag('event', 'Link Click', { 1966 'event_category': analyticsCategory, 1967 'event_label': "CustomerBusinessPhoneLinkPlatinum1-2" 1968 }); 1969 }); 1970 $('#contactPrimaryPhoneLink').on('click', function () { 1971 gtag('event', 'Link Click', { 1972 'event_category': analyticsCategory, 1973 'event_label': "CustomerBusinessPhoneLinkPlatinum1-3" 1974 }); 1975 }); 1976 $('#contactSecondaryPhoneLink').on('click', function () { 1977 gtag('event', 'Link Click', { 1978 'event_category': analyticsCategory, 1979 'event_label': "CustomerBusinessPhoneLinkPlatinum1-4" 1980 }); 1981 }); 1982 $('#contactMobilePhoneLink').on('click', function () { 1983 gtag('event', 'Link Click', { 1984 'event_category': analyticsCategory, 1985 'event_label': "CustomerBusinessPhoneLinkPlatinum1-5" 1986 }); 1987 }); 1988 $('#contactFaxPhoneLink').on('click', function () { 1989 gtag('event', 'Link Click', { 1990 'event_category': analyticsCategory, 1991 'event_label': "CustomerBusinessPhoneLinkPlatinum1-6" 1992 }); 1993 }); 1994 $('#contactTollfreePhoneLink').on('click', function () { 1995 gtag('event', 'Link Click', { 1996 'event_category': analyticsCategory, 1997 'event_label': "CustomerBusinessPhoneLinkPlatinum1-7" 1998 }); 1999 }); 2000 $('#contactPhoneC1').on('click', function () { 2001 gtag('event', 'Link Click', { 2002 'event_category': analyticsCategory, 2003 'event_label': "CustomerContactPhoneLinkPlatinum1-8" 2004 }); 2005 }); 2006 $('#contactPhoneC2').on('click', function () { 2007 gtag('event', 'Link Click', { 2008 'event_category': analyticsCategory, 2009 'event_label': "CustomerContactPhoneLinkPlatinum1-9" 2010 }); 2011 }); 2012 $('#contactPhoneC3').on('click', function () { 2013 gtag('event', 'Link Click', { 2014 'event_category': analyticsCategory, 2015 'event_label': "CustomerContactPhoneLinkPlatinum1-10" 2016 }); 2017 }); 2018 $('#contactPhoneC4').on('click', function () { 2019 gtag('event', 'Link Click', { 2020 'event_category': analyticsCategory, 2021 'event_label': "CustomerContactPhoneLinkPlatinum1-11" 2022 }); 2023 }); 2024 $('#contactPhoneC5').on('click', function () { 2025 gtag('event', 'Link Click', { 2026 'event_category': analyticsCategory, 2027 'event_label': "CustomerContactPhoneLinkPlatinum1-12" 2028 }); 2029 }); 2030 $('#contactEmail').on('click', function () { 2031 gtag('event', 'Link Click', { 2032 'event_category': analyticsCategory, 2033 'event_label': "CustomerBusinessEmailLinkPlatinum1" 2034 }); 2035 }); 2036 $('#writeReviewBt').on('click', function () { 2037 gtag('event', 'Button Click', { 2038 'event_category': analyticsCategory, 2039 'event_label': "WriteReviewButtonPlatinum1" 2040 }); 2041 }); 2042 $(document).on('click', '#postReview', function () { 2043 gtag('event', 'Button Click', { 2044 'event_category': analyticsCategory, 2045 'event_label': "PostReviewButtonPlatinum1" 2046 }); 2047 }); 2048 $('#nextReview').on('click', function () { 2049 gtag('event', 'Button Click', { 2050 'event_category': analyticsCategory, 2051 'event_label': "ShowNextReviewsButtonPlatinum1" 2052 }); 2053 }); 2054 $('#prevReview').on('click', function () { 2055 gtag('event', 'Button Click', { 2056 'event_category': analyticsCategory, 2057 'event_label': "ShowPreviousReviewsButtonPlatinum1" 2058 }); 2059 }); 2060 $('#google-social').on('click', function () { 2061 gtag('event', 'Link Click', { 2062 'event_category': analyticsCategory, 2063 'event_label': "CustomerGoogleSocialLinkPlatinum1-1" 2064 }); 2065 }); 2066 $('#facebook-social').on('click', function () { 2067 gtag('event', 'Link Click', { 2068 'event_category': analyticsCategory, 2069 'event_label': "CustomerFacebookSocialLinkPlatinum1-1" 2070 }); 2071 }); 2072 $('#yelp-social').on('click', function () { 2073 gtag('event', 'Link Click', { 2074 'event_category': analyticsCategory, 2075 'event_label': "CustomerYelpSocialLinkPlatinum1-1" 2076 }); 2077 }); 2078 $('#twitter-social').on('click', function () { 2079 gtag('event', 'Link Click', { 2080 'event_category': analyticsCategory, 2081 'event_label': "CustomerTwitterSocialLinkPlatinum1-1" 2082 }); 2083 }); 2084 $('#linkedin-social').on('click', function () { 2085 gtag('event', 'Link Click', { 2086 'event_category': analyticsCategory, 2087 'event_label': "CustomerLinkedinSocialLinkPlatinum1-1" 2088 }); 2089 }); 2090 $('#instagram-social').on('click', function () { 2091 gtag('event', 'Link Click', { 2092 'event_category': analyticsCategory,
2093 'event_label': "CustomerInstagramSocialLinkPlatinum1-1" 2094 }); 2095 }); 2096 $('#google-social-footer').on('click', function () { 2097 gtag('event', 'Link Click', { 2098 'event_category': analyticsCategory, 2099 'event_label': "CustomerGoogleSocialLinkPlatinum1-2" 2100 }); 2101 }); 2102 $('#facebook-social-footer').on('click', function () { 2103 gtag('event', 'Link Click', { 2104 'event_category': analyticsCategory, 2105 'event_label': "CustomerFacebookSocialLinkPlatinum1-2" 2106 }); 2107 }); 2108 $('#yelp-social-footer').on('click', function () { 2109 gtag('event', 'Link Click', { 2110 'event_category': analyticsCategory, 2111 'event_label': "CustomerYelpSocialLinkPlatinum1-2" 2112 }); 2113 }); 2114 $('#twitter-social-footer').on('click', function () { 2115 gtag('event', 'Link Click', { 2116 'event_category': analyticsCategory, 2117 'event_label': "CustomerTwitterSocialLinkPlatinum1-2" 2118 }); 2119 }); 2120 $('#linkedin-social-footer').on('click', function () { 2121 gtag('event', 'Link Click', { 2122 'event_category': analyticsCategory, 2123 'event_label': "CustomerLinkedinSocialLinkPlatinum1-2" 2124 }); 2125 }); 2126 $('#instagram-social-footer').on('click', function () { 2127 gtag('event', 'Link Click', { 2128 'event_category': analyticsCategory, 2129 'event_label': "CustomerInstagramSocialLinkPlatinum1-2" 2130 }); 2131 }); 2132 $('#contactEmailFooter').on('click', function () { 2133 gtag('event', 'Link Click', { 2134 'event_category': analyticsCategory, 2135 'event_label': "CustomerBusinessEmailLinkPlatinum1-2" 2136 }); 2137 }); 2138 $('#btnContactPost').on('click', function () { 2139 gtag('event', 'Link Click', { 2140 'event_category': analyticsCategory, 2141 'event_label': "CustomerContactLeadPostPlatinum1" 2142 }); 2143 }); 2144 $("#external-review-link").on('click', function () { 2145 gtag('event', 'Link Click', { 2146 'event_category': analyticsCategory, 2147 'event_label': "CustomerExternalReviewLinkPlatinum1" 2148 }); 2149 }); 2150 $('#video').on('click', function () { 2151 gtag('event', 'Video Click', { 2152 'event_category': analyticsCategory, 2153 'event_label': "CustomerVideoPlatinum1" 2154 }); 2155 }); 2156 $('#website-social').on('click', function () { 2157 gtag('event', 'Link Click', { 2158 'event_category': analyticsCategory, 2159 'event_label': "CustomerWebsiteSocialLinkPlatinum1-1" 2160 }); 2161 }); 2162 $('#website-social-footer').on('click', function () { 2163 gtag('event', 'Link Click', { 2164 'event_category': analyticsCategory, 2165 'event_label': "CustomerWebsiteSocialLinkPlatinum1-2" 2166 }); 2167 }); 2168 $('#accessibility-social-footer').on('click', function () { 2169 gtag('event', 'Link Click', { 2170 'event_category': analyticsCategory, 2171 'event_label': "CustomerWebsiteAccessibilityLinkPlatinum1" 2172 }); 2173 }); 2174 $('#photos-image-element').on('click', function () { 2175 gtag('event', 'Link Click', { 2176 'event_category': analyticsCategory, 2177 'event_label': "CustomerWebsiteImageryPhotoPlatinum1" 2178 }); 2179 }); 2180 $('#HomePageNavigationLink').on('click', function () { 2181 gtag('event', 'Link Click', { 2182 'event_category': analyticsCategory, 2183 'event_label': "CustomerHomePageNavLinkPlatinum1" 2184 }); 2185 }); 2186 $('#AccessibilityPageNavigationLink').on('click', function () { 2187 gtag('event', 'Link Click', { 2188 'event_category': analyticsCategory, 2189 'event_label': "CustomerAccessibilityPageNavLinkPlatinum1" 2190 }); 2191 }); 2192 $('#ContactPageNavigationLink').on('click', function () { 2193 gtag('event', 'Link Click', { 2194 'event_category': analyticsCategory, 2195 'event_label': "CustomerContactPageNavLinkPlatinum1" 2196 }); 2197 }); 2198 $('#PhotosNavigationLink').on('click', function () { 2199 gtag('event', 'Link Click', { 2200 'event_category': analyticsCategory, 2201 'event_label': "CustomerPhotosPageNavLinkPlatinum1" 2202 }); 2203 }); 2204 $('#testimoinalsPageNavigationLink').on('click', function () { 2205 gtag('event', 'Link Click', { 2206 'event_category': analyticsCategory, 2207 'event_label': "CustomerTestimonialsPageNavLinkPlatinum1" 2208 }); 2209 }); 2210 $('#ServicesPageNavigationLink').on('click', function () { 2211 gtag('event', 'Link Click', { 2212 'event_category': analyticsCategory, 2213 'event_label': "CustomerServicesPageNavLinkPlatinum1" 2214 }); 2215 }); 2216 $('#AboutPageNavigationLink').on('click', function () { 2217 gtag('event', 'Link Click', { 2218 'event_category': analyticsCategory, 2219 'event_label': "CustomerAboutPageNavLinkPlatinum1" 2220 }); 2221 }); 2222 2223 $(document).on('click', '.btn-link', function() { 2224 // Find the closest parent that includes both the button and the items to be toggled 2225 var $parentNav = $(this).closest('.navbar-attribute'); 2226 2227 // Toggle the visibility of hidden items within this specific parent 2228 var $hiddenItems = $parentNav.find('.hidden-item'); 2229 $hiddenItems.toggle(); 2230 2231 // Find the arrow within the clicked button 2232 var $arrow = $(this).find('.arrow'); 2233 2234 // Toggle arrow direction by switching classes 2235 if ($arrow.hasClass('arrow-down')) { 2236 $arrow.removeClass('arrow-down').addClass('arrow-up'); 2237 } else { 2238 $arrow.removeClass('arrow-up').addClass('arrow-down'); 2239 } 2240 }); 2241 2242 $(document).on('click', '#photos-image-element1', function () { 2243 $('#selectedServiceId').val('service1'); 2244 DisplayPage('#servicesPage'); 2245 }); 2246 $(document).on('click', '#photos-image-element2', function () { 2247 $('#selectedServiceId').val('service2'); 2248 DisplayPage('#servicesPage'); 2249 }); 2250 $(document).on('click', '#photos-image-element3', function () { 2251 $('#selectedServiceId').val('service3'); 2252 DisplayPage('#servicesPage'); 2253 }); 2254 2255 //unable to directly track cross domain iFrame clicks. Track only first click on the iFrame itself 2256 var monitor = setInterval(function () { 2257 var elem = document.activeElement; 2258 if (elem && elem.tagName == "IFRAME" && elem.id == "googleMapEmbed") { 2259 gtag('event', 'iFrame Click', { 2260 'event_category': analyticsCategory, 2261 'event_label': "GoogleDirectionsPlatinum1" 2262 }); 2263 clearInterval(monitor); 2264 } 2265 }, 1000); 2266 2267 var navbarHeight = $('#headernav').outerHeight(); // Make sure this matches your navbar class 2268 document.documentElement.style.setProperty('--scroll-padding-top', navbarHeight + 'px'); 2269 });
2270 2271 function scrollToService(serviceId) { 2272 var targetElement = document.getElementById(serviceId); 2273 if (targetElement) { 2274 var headerHeight = document.querySelector('#headernav').offsetHeight; 2275 var descriptionOffset = 165; // Adjust this value as needed 2276 var scrollPosition = targetElement.offsetTop - headerHeight - descriptionOffset; 2277 2278 window.scrollTo({ 2279 top: scrollPosition, 2280 behavior: 'smooth' 2281 }); 2282 } else { 2283 console.log('Service section element not found'); 2284 } 2285 } 2286 2287 function DisplayPage(page, serviceId) { 2288 PauseVideoPlayer(); 2289 2290 if (!$(page).hasClass("show")) { 2291 $("#pages div.collapse.show").collapse("hide"); 2292 } 2293 $(page).collapse("show"); 2294 2295 if(page == "#homePage") 2296 { 2297 var carousel = $(".slick-slider"); 2298 if(carousel != null) 2299 { 2300 carousel.slick('refresh'); 2301 } 2302 } 2303 2304 if (page == "#testimonialsPage") { 2305 // Load Testimonials via Ajax if not already loaded 2306 if (!testimonialsRendered) { 2307 ShowLoading(); 2308 $.get('/Home/GetTestimonialsContent', { id: 41272, template: "Platinum_1"}, function (data) { 2309 if (data != "") 2310 { 2311 $("#testimonialsPage").append(data); 2312 } 2313 }).always(function() { 2314 HideLoading(); 2315 testimonialsRendered = true; 2316 }); 2317 } 2318 2319 $("html, body").animate({ scrollTop: 0 }, "fast"); 2320 } 2321 2322 if (page == "#aboutPage") { 2323 // Load About via Ajax if not already loaded 2324 if (!aboutRendered) { 2325 ShowLoading(); 2326 $.get('/Home/GetAboutContent', { id: 41272, template: "Platinum_1"}, function (data) { 2327 if (data != "") 2328 { 2329 $("#aboutPage").append(data); 2330 $.getScript("https://maps.googleapis.com/maps/api/js?key=AIzaSyB2UoPWVWPR8WrIFK_zqJ5nTN1NvGm9dqY&callback=initMap"); 2331 2332 } 2333 }).always(function() { 2334 HideLoading(); 2335 aboutRendered = true; 2336 }); 2337 } 2338 } 2339 2340 if (page === "#servicesPage") 2341 { 2342 // Load Services via Ajax if not already loaded 2343 if (!servicesRendered) { 2344 ShowLoading(); 2345 $.get('/Home/GetServicesContent', { id: 41272, template: "Platinum_1" }) 2346 .done(function (data) { 2347 if (data !== "") { 2348 $("#servicesPage").append(data); 2349 servicesRendered = true; 2350 // Trigger the scroll after a short delay 2351 setTimeout(function() { 2352 var selectedServiceId = $('#selectedServiceId').val(); 2353 if (selectedServiceId) { 2354 scrollToService(selectedServiceId); 2355 $('#selectedServiceId').val(''); 2356 } 2357 }, 300); // Adjust the delay as needed 2358 } 2359 }) 2360 .always(function () { 2361 HideLoading(); 2362 }); 2363 } else { 2364 // If the services are already rendered, trigger the scroll after a short delay 2365 setTimeout(function() { 2366 var selectedServiceId = $('#selectedServiceId').val(); 2367 if (selectedServiceId) { 2368 scrollToService(selectedServiceId); 2369 $('#selectedServiceId').val(''); 2370 } 2371 }, 100); // Adjust the delay as needed 2372 } 2373 } else { 2374 window.scrollTo(0, 0); 2375 } 2376 2377 if (page == "#imageryPage") { 2378 // Load photos via Ajax if not already loaded 2379 if (!photosRendered) { 2380 ShowLoading(); 2381 $.get('/Home/GetPhotosContent', { id: 41272, template: "Platinum_1"}, function (data) { 2382 if (data != "") 2383 { 2384 $("#imageryPage").append(data); 2385 } 2386 }).always(function() { 2387 HideLoading(); 2388 photosRendered = true; 2389 }); 2390 } 2391 } 2392 2393 if (page == "#contactPage") { 2394 // Load Contact via Ajax if not already loaded 2395 if (!contactRendered) { 2396 ShowLoading(); 2397 $.get('/Home/GetContactContent', { id: 41272, template: "Platinum_1"}, function (data) { 2398 if (data != "") 2399 { 2400 $("#contactPage").append(data); 2401 } 2402 }).always(function() { 2403 HideLoading(); 2404 contactRendered = true; 2405 }); 2406 } 2407 } 2408 2409 if (page == "#locationsPage") { 2410 // Load Locations via Ajax if not already loaded 2411 if (!locationsRendered) { 2412 ShowLoading(); 2413 2414 $.get('/Home/GetLocationsContent', { id: 41272, template: "Platinum_1" }, function (data) { 2415 if (data != "") 2416 { 2417 $("#locationsPage").append(data); 2418 } 2419 }).always(function() { 2420 HideLoading(); 2421 locationsRendered = true; 2422 }); 2423 } 2424 } 2425 2426 if (page == "#faqPage") { 2427 // Load Faqs via Ajax if not already loaded 2428 if (!faqRendered) { 2429 ShowLoading(); 2430 2431 $.get('/Home/GetFAQContent', { id: 41272, template: "Platinum_1" }, function (data) { 2432 if (data != "") { 2433 $("#faqPage").append(data); 2434 } 2435 }).always(function () { 2436 HideLoading(); 2437 faqRendered = true; 2438 }); 2439 } 2440 } 2441 2442 if (page == "#contentPage") { 2443 // Load Additional Content via Ajax if not already loaded 2444 if (!additionalContentRendered) { 2445 ShowLoading(); 2446 2447 $.get('/Home/GetAdditionalContentContent', { id: 41272, template: "Platinum_1" }, function (data) { 2448 if (data != "") { 2449 $("#contentPage").append(data); 2450 } 2451 }).always(function () { 2452 HideLoading(); 2453 additionalContentRendered = true; 2454 }); 2455 } 2456 } 2457 } 2458 2459 function PauseVideoPlayer() { 2460 2461 var videos = document.querySelectorAll('video'); 2462 var iframes = document.querySelectorAll('iframe'); 2463 2464 //mp4 2465 Array.prototype.forEach.call(videos, video => { 2466 video.pause(); 2467 }); 2468 2469 //youtube 2470 Array.prototype.forEach.call(iframes, iframe => { 2471 iframe.contentWindow.postMessage(JSON.stringify({ 2472 event: 'command', 2473 func: 'pauseVideo' 2474 }), '*'); 2475 }); 2476 2477 //wistia + vimeo 2478 Array.prototype.forEach.call(iframes, iframe => { 2479 iframe.contentWindow.postMessage(JSON.stringify({ 2480 "method": "pause", 2481 "value": "true" 2482 }), '*'); 2483 }); 2484 } 2485 2486 function GetPostsData(i) 2487 { 2488 if(i != 0){ 2489 ShowLoading(); 2490 } 2491 postsPageIndex = postsPageIndex + i; 2492 $.get('/Home/GetTestimonialPostsInfo', {id: 41272, program_id: 18, profileDomain: 'https://strattegyinc.com/', subdomain: 'strattegyinc', testimonialSSL : 'False', domainSSL : 'True', pageIndex: postsPageIndex, pageSize: pageSize, file: '_TestimonialPostsContent'}, function (data) { 2493 if (data != "") 2494 { 2495 $(".postsInfo").html(data); 2496 } 2497 }).always(function() { 2498 HideLoading(); 2499 }); 2500 SetPostsPaginationButtons(); 2501 } 2502 2503 function GetPostsBanner() 2504 { 2505 ShowLoading(); 2506 var bannerObj = null; 2507 $.ajax({
2508 method: "POST", 2509 url: "/Home/GetPostBanner", 2510 data:JSON.stringify( 2511 { 2512 banner: bannerObj, 2513 testimonialPageColor: (false) ? 'transparent' :'#1F1F1F', 2514 postsColor: '#1F1F1F' 2515 }), 2516 contentType: 'application/json', 2517 success: function (data) { 2518 var holdaspect = ""; 2519 if ($("#homepagebanner").hasClass('aspect-ratio-16x9')) { 2520 $('#homepagebanner').removeClass('aspect-ratio-16x9'); 2521 holdaspect = "aspect-ratio-16x9"; 2522 } 2523 2524 if(isMobile || isTablet){ 2525 setTimeout(function(){ 2526 $(".home-content").prepend(data); 2527 }, 5000); 2528 } 2529 else{ 2530 $(".home-content").prepend(data); 2531 } 2532 2533 $('#bannerclose').click(function() { 2534 if (holdaspect != "") { 2535 $('#homepagebanner').addClass('aspect-ratio-16x9'); 2536 } 2537 }); 2538 2539 /*remove banner after 30 seconds regardless of mobile/tablet/desktop*/ 2540 if (!keepPostUp) { 2541 setTimeout(function () { 2542 $("#posts-banner-alert").remove(); 2543 if (holdaspect != "" && !(isMobile || isTablet)) { 2544 $('#homepagebanner').addClass('aspect-ratio-16x9'); 2545 } 2546 }, 30000); 2547 } 2548 } 2549 }).always(function() { 2550 HideLoading(); 2551 if (holdaspect != "" && !(isMobile || isTablet)) { 2552 $('#homepagebanner').addClass('aspect-ratio-16x9'); 2553 } 2554 }); 2555 } 2556 2557 function SetPostsPaginationButtons() 2558 { 2559 //look ahead by one 2560 if (((postsPageIndex + 1) * pageSize) >= numOfPosts) { 2561 $("#nextPosts").hide(); 2562 } 2563 else { 2564 $("#nextPosts").show(); 2565 $("#nextPosts").prop('disabled', false); 2566 } 2567 2568 if (postsPageIndex <= 0) { 2569 postsPageIndex = 0; 2570 $("#prevPosts").hide(); 2571 } 2572 else if (postsPageIndex > 0) { 2573 $("#prevPosts").show(); 2574 $("#prevPosts").prop('disabled', false); 2575 } 2576 } 2577 2578 function ShowLoading() 2579 { 2580 $("#loadingImg").show(); 2581 } 2582 2583 function HideLoading() 2584 { 2585 $("#loadingImg").hide(); 2586 } 2587 2588 function checkMobile() { 2589 var windowsize = $(window).width(); 2590 switch (true) { 2591 case /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent): 2592 isMobile = true; 2593 break; 2594 case windowsize < 800: 2595 isMobile = true; 2596 break; 2597 default: 2598 isMobile = false; 2599 } 2600 } 2601 2602 function checkTablet() { 2603 var windowsize = $(window).width(); 2604 switch (true) { 2605 case (windowsize >= 800) && (windowsize < 1200): 2606 isTablet = true; 2607 break; 2608 default: 2609 isTablet = false; 2610 } 2611 } 2612 2613 function checkHashRoute() { 2614 if ((location.hash != null) && (location.hash != "") && (location.hash == '#homePage' || location.hash == '#aboutPage' || location.hash == '#servicesPage' || location.hash == '#testimonialsPage' || location.hash == '#contactPage' || location.hash == '#locationsPage' || location.hash == '#faqPage' || location.hash == '#contentPage')) { 2615 DisplayPage(location.hash); 2616 } 2617 } 2618 2619 function contactUsPost(event) { 2620 var _contactForm = $("#ContactPostForm"); 2621 2622 // Clear previous validation states 2623 $('.validation-error-message').remove(); 2624 _contactForm.find('.validation-error').removeClass('validation-error'); 2625 $("#contactResponseMessage").empty(); 2626 2627 if (_contactForm[0].checkValidity()) { 2628 contactUsSubmit(event); 2629 } else { 2630 var firstInvalidField = null; 2631 2632 _contactForm.find('input[required], textarea[required], select[required]').each(function () { 2633 var $field = $(this); 2634 2635 if (!this.checkValidity()) { 2636 var fieldId = $field.attr('id') || $field.attr('name'); 2637 var fieldLabel = getFieldLabel(fieldId); 2638 2639 $field.addClass('validation-error'); 2640 2641 var errorMessage = getCustomErrorMessage($field, fieldLabel); 2642 $field.after(`<div class="validation-error-message">${errorMessage}</div>`); 2643 2644 if (!firstInvalidField) { 2645 firstInvalidField = $field; 2646 } 2647 } 2648 }); 2649 2650 // Focus first invalid field 2651 if (firstInvalidField) { 2652 firstInvalidField.focus(); 2653 } 2654 2655 // Re-enable submit button 2656 $("#btnContactPost").prop('disabled', false); 2657 $("#btnContactPost").css('font-weight', 'bold'); 2658 } 2659 } 2660 2661 function getFieldLabel(fieldId) { 2662 var labels = { 2663 'contact_us_phone': 'Phone Number', 2664 'contact_us_address': 'Address', 2665 'contact_us_city': 'City', 2666 'contact_us_state': 'State', 2667 'contact_us_zip': 'ZIP Code', 2668 'contact_us_subject': 'Subject', 2669 'contact_us_name': 'Name', 2670 'contact_us_email': 'Email', 2671 'contact_us_message': 'Message' 2672 }; 2673 return labels[fieldId] || 'This field'; 2674 } 2675 2676 function getCustomErrorMessage($field, fieldLabel) { 2677 if ($field.prop('required') && !$field.val().trim()) { 2678 return `${fieldLabel} required`; 2679 } 2680 2681 if ($field.attr('type') === 'email' && $field.val()) { 2682 return `Please enter a valid email address.`; 2683 } 2684 2685 return `Please enter a valid ${fieldLabel.toLowerCase()}.`; 2686 } 2687 2688 function contactUsSubmit(event) { 2689 event.preventDefault(); 2690 2691 var form = $("#ContactPostForm"); 2692 grecaptcha.ready(function() { 2693 grecaptcha.execute('6LcokacUAAAAAH_snk3O5bpdYwjpC5XAuXNLrJLH', {action: 'contact_us'}).then(function(token) { 2694 $("#g-Recaptcha-Response-Contact").attr("value", token); //add token for server side validation 2695 $.ajax({
2696 type: "POST", 2697 url: "/Home/ContactPost", 2698 data: form.serialize(), 2699 success: function(data){ 2700 if (data.indexOf('{"message":') != -1) { 2701 var jsonData = JSON.parse(data); 2702 if (!jsonData.success) { 2703 $("#contactResponseMessage").html('<div class="alert alert-warning alert-dissmisable" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' + jsonData.message + '</div>'); 2704 recaptchaContactUsInComplete(); 2705 showClassicCaptcha("contact"); 2706 } 2707 else{ 2708 $("#contactResponseMessage").html('<div class="alert alert-success alert-dissmisable" role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>' + jsonData.message + '</div>'); 2709 recaptchaContactUsComplete(); 2710 } 2711 } 2712 } 2713 }); 2714 }); 2715 }); 2716 } 2717 2718 function ScrollForPosts(e){ 2719 // target element 2720 var $id = $(".posts-partial-content"); 2721 if ($id.length === 0) { 2722 return; 2723 } 2724 2725 // prevent standard hash navigation (avoid blinking in IE) 2726 e.preventDefault(); 2727 2728 // top position relative to the document 2729 var pos = $id.offset().top - $('.navbar').height(); 2730 2731 // animated top scrolling 2732 // .stop() keeps from scrolling to top then to element 2733 $('body, html').stop().animate({ scrollTop: pos }, 500); 2734 } 2735 2736 function recaptchaContactUsInComplete(){ 2737 $("#btnContactPost").prop('disabled', false); 2738 $("#btnContactPost").css('font-weight', 'bold'); 2739 } 2740 2741 function recaptchaContactUsComplete() { 2742 $("#btnContactPost").prop('disabled', false); 2743 $("#btnContactPost").css('font-weight', 'normal'); 2744 $("#ContactPostForm").trigger("reset"); 2745 } 2746 2747 function recaptchaReviewIncomplete(){ 2748 $("#postReview").prop('disabled', false); 2749 $("#postReview").css('font-weight', 'bold'); 2750 } 2751 2752 function recaptchaReviewComplete(){ 2753 $("#postReview").css('font-weight', 'normal'); 2754 $("#postReviewForm").trigger("reset"); 2755 $("#postReview").prop('disabled', false); 2756 } 2757 2758 function ClearReviewFields() { 2759 $('#starRating').barrating('clear'); 2760 $("#review").val(""); 2761 $("#review_alias").val(""); 2762 $("#review_heading").val(""); 2763 $("#reviewCaptcha").val(""); 2764 } 2765 2766 function resetReviewButton($button) { 2767 var $buttonText = $button.find('.button-text'); 2768 var $spinner = $button.find('.spinner'); 2769 2770 $button.prop('disabled', false); 2771 2772 if ($buttonText.length && $spinner.length) { 2773 $buttonText.show(); 2774 $spinner.hide(); 2775 } else { 2776 var originalText = $button.data('original-text'); 2777 if (originalText) { 2778 $button.html(originalText); 2779 } 2780 } 2781 } 2782 2783 function setProcessingState($button, $form, isProcessing) { 2784 var $buttonText = $button.find('.button-text'); 2785 var $spinner = $button.find('.spinner'); 2786 2787 if (isProcessing) { 2788 $button.prop('disabled', true); 2789 $form.addClass('review-form-processing'); 2790 $form.find('input, textarea, select').not('#profile_id, #g-Recaptcha-Response-Review, [type="hidden"]').prop('disabled', true); 2791 2792 if ($buttonText.length && $spinner.length) { 2793 $buttonText.hide(); 2794 $spinner.show(); 2795 } else { 2796 $button.data('original-text', $button.html()); 2797 $button.html('<i class="fas fa-spinner fa-spin"></i> Processing...'); 2798 } 2799 } else { 2800 $button.prop('disabled', false); 2801 $form.removeClass('review-form-processing'); 2802 $form.find('input, textarea, select').prop('disabled', false); 2803 2804 if ($buttonText.length && $spinner.length) { 2805 $buttonText.show(); 2806 $spinner.hide(); 2807 } else { 2808 var originalText = $button.data('original-text'); 2809 if (originalText) { 2810 $button.html(originalText); 2811 } 2812 } 2813 } 2814 } 2815 2816 function ClearReviewFields() { 2817 console.log('Clearing review fields'); 2818 $('#starRating').barrating('clear'); 2819 $("#review").val(""); 2820 $("#review_alias").val(""); 2821 $("#review_heading").val(""); 2822 $("#reviewCaptcha").val(""); 2823 2824 $("#postReviewForm input, #postReviewForm textarea").removeClass('error'); 2825 $("#postReviewForm .br-widget").removeClass('error'); 2826 } 2827 2828 function validateReview(btn) { 2829 var $form = $("#postReviewForm"); 2830 var isValid = true; 2831 2832 console.log('Starting validation...'); 2833 2834 $form.find('input, textarea').removeClass('error'); 2835 $form.find('.br-widget').removeClass('error'); 2836 2837 var reviewText = $('#review').val(); 2838 console.log('Review text length:', reviewText ? reviewText.trim().length : 0); 2839 2840 if (!reviewText || reviewText.trim().length === 0) { 2841 console.log('Review text validation failed - empty or whitespace only'); 2842 $('#review').addClass('error'); 2843 $('#review').focus(); 2844 isValid = false; 2845 } else { 2846 console.log('Review text validation passed'); 2847 } 2848 2849 var rating = null; 2850 var selectRating = $('#starRating')[0] ? $('#starRating')[0].value : null; 2851 var jqueryRating = $('#starRating').val(); 2852 var selectedOption = $('#starRating option:selected').val(); 2853 var barRating = null; 2854 2855 if (typeof $('#starRating').barrating === 'function') { 2856 try { 2857 var barResult = $('#starRating').barrating('show'); 2858 if (barResult && typeof barResult === 'string') { 2859 barRating = barResult; 2860 } else if (barResult && typeof barResult === 'number') { 2861 barRating = barResult.toString(); 2862 } 2863 } catch (e) { 2864 console.log('Error getting barrating value:', e); 2865 } 2866 } 2867 2868 if (jqueryRating && typeof jqueryRating === 'string') { 2869 } else if (jqueryRating && typeof jqueryRating === 'number') { 2870 jqueryRating = jqueryRating.toString(); 2871 } else { 2872 jqueryRating = null; 2873 } 2874 2875 if (barRating && barRating !== "" && barRating !== "0") { 2876 rating = barRating; 2877 } else if (selectRating && selectRating !== "" && selectRating !== "0") { 2878 rating = selectRating; 2879 } else if (selectedOption && selectedOption !== "" && selectedOption !== "0") { 2880 rating = selectedOption; 2881 } else if (jqueryRating && jqueryRating !== "" && jqueryRating !== "0") { 2882 rating = jqueryRating; 2883 } 2884 2885 if (rating && typeof rating !== 'string') { 2886 console.log('WARNING: Rating is not a string, converting:', rating, typeof rating);
2887 rating = String(rating); 2888 } 2889 2890 if (rating && typeof rating === 'object') { 2891 console.error('CRITICAL ERROR: Rating is still an object!', rating); 2892 rating = null; 2893 } 2894 2895 console.log('Validation - Final rating value:', rating, typeof rating); 2896 2897 if (!rating || rating === "" || rating === "0") { 2898 console.log('Rating validation failed'); 2899 $('.br-widget').addClass('error'); 2900 isValid = false; 2901 } else { 2902 console.log('Rating validation passed with value:', rating); 2903 } 2904 2905 console.log('Validation result:', isValid); 2906 return isValid; 2907 } 2908 2909 function validateReviewLength() { 2910 var text = $('#review').val(); 2911 var success = true; 2912 2913 if (text.trim().length == 0) { 2914 $('#review').addClass('error'); 2915 success = false; 2916 } 2917 return success; 2918 } 2919 2920 function validateRating() { 2921 var rating = null; 2922 2923 // Use the same rating detection logic 2924 var selectRating = $('#starRating')[0] ? $('#starRating')[0].value : null; 2925 var jqueryRating = $('#starRating').val(); 2926 var selectedOption = $('#starRating option:selected').val(); 2927 var barRating = null; 2928 2929 if (typeof $('#starRating').barrating === 'function') { 2930 try { 2931 barRating = $('#starRating').barrating('show'); 2932 } catch (e) { 2933 console.log('Error getting barrating value in validateRating:', e); 2934 } 2935 } 2936 2937 // Determine which rating to use 2938 if (barRating && barRating !== "" && barRating !== "0") { 2939 rating = barRating; 2940 } else if (selectRating && selectRating !== "" && selectRating !== "0") { 2941 rating = selectRating; 2942 } else if (selectedOption && selectedOption !== "" && selectedOption !== "0") { 2943 rating = selectedOption; 2944 } else if (typeof jqueryRating === 'string' && jqueryRating !== "" && jqueryRating !== "0") { 2945 rating = jqueryRating; 2946 } 2947 2948 var success = true; 2949 if (!rating || rating === "" || rating === "0") { 2950 $('.br-widget').addClass('error'); 2951 success = false; 2952 } 2953 return success; 2954 } 2955</script>
2955 2956</body> 2957</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.