1<!doctype html> 2<html lang="en"> 3 4<head> 5 <meta name="viewport" content="width=1300, max-width=1300"> 6 <meta name="google-site-verification" content="l_kBGVByEFuQBNvWwVoARudBcFDIGjXjDZ9cFhfwagg" /> 7 8 9 10 11 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 12<meta http-equiv="Cache-Control" content="Public" /> 13<meta name="robots" content="index, follow" /> 14 15 16 17 <title>Habitaciones - Hotel Premium Tower Suites</title> 18 <meta name="description" content="Bienvenido a Premium Tower Suites Mendoza!"> 19 20 <meta http-equiv="content-language" content="en"> 21 <link rel="canonical" href="https://www.premiumtowersuites.com.ar/en/habitaciones.html" /> 22 <meta property="og:url" content="https://www.premiumtowersuites.com.ar/en/habitaciones.html" /> 23 <meta property="og:type" content="website" /> 24 <meta property="og:title" content="Habitaciones - Hotel Premium Tower Suites" /> 25 <meta property="og:description" content="Bienvenido a Premium Tower Suites Mendoza!" /> 26 27 <meta property="og:image" content="https://images-new.pxsol.com/zCpb3wQ8tAPxyvptRRENo7U3l_bLkXyqwO1o1Eo7Anc/rs:fill:630:430:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F208072094042521a7eef689dd75da20d9a192531f4a.jpg@jpg" /> 28 29 30 31 <link rel="alternate" hreflang="es-AR" href="https://www.premiumtowersuites.com.ar/habitaciones.html" /> 32 <link rel="alternate" hreflang="en-US" href="https://www.premiumtowersuites.com.ar/en/habitaciones.html" /> 33 <link rel="alternate" hreflang="pt-BR" href="https://www.premiumtowersuites.com.ar/pt/habitaciones.html" /> 34 <link rel="alternate" hreflang="x-default" href="https://www.premiumtowersuites.com.ar/habitaciones.html" /> 35 36<link rel="icon" type="image/png" sizes="16x16" href="https://images-new.pxsol.com/2U7WkjCmNR4Un9Fc7dN5NUHXQTZuECIj3_27QD8MxdM/rs:fill:16:16:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 37<link rel="icon" type="image/png" sizes="32x32" href="https://images-new.pxsol.com/mrjm7fH4HNnqniMLNVwHsOvaTnW9-jVvIajD3A0tJrE/rs:fill:32:32:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 38<link rel="icon" type="image/png" sizes="48x48" href="https://images-new.pxsol.com/OF7O-mz3D9gMdCvekkPeVORxS4BWe3WJdVviBtZottY/rs:fill:48:48:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 39<link rel="icon" type="image/png" sizes="96x96" href="https://images-new.pxsol.com/ODhNY4k6TiHLs5c7SD36rcobdjHYCCmRv3O1i51-qvE/rs:fill:96:96:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 40<link rel="shortcut icon" href="https://files-p.pxsol.com/18413/company/library/user/241250311408a778cb276110216fe92234bb4283ca1.png" /> 41 42<link rel="apple-touch-icon" sizes="57x57" href="https://images-new.pxsol.com/fc4e-xzVmDGN9uA2mVN4aeZIya2-aQnuqE66122Mxbo/rs:fill:57:57:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 43<link rel="apple-touch-icon" sizes="72x72" href="https://images-new.pxsol.com/gJzhwFzZ7p4kxWPxcwhEVlTKQSGc3cWKTR7CXGXT7-c/rs:fill:72:72:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 44<link rel="apple-touch-icon" sizes="76x76" href="https://images-new.pxsol.com/-SQPeEmjag4WQKM8YDH3IFmVNA96Pf6n1vR0y8l8ukU/rs:fill:76:76:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 45<link rel="apple-touch-icon" sizes="114x114" href="https://images-new.pxsol.com/hZFUC63Uz-bj6l-CTAjwiW838gAEQraKQVZT1NNBKGk/rs:fill:114:114:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 46<link rel="apple-touch-icon" sizes="120x120" href="https://images-new.pxsol.com/2_PBoUA5vCk_K_dDyLgZ4jn0lPvEFrNhRifu3RIyVM8/rs:fill:120:120:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 47<link rel="apple-touch-icon" sizes="144x144" href="https://images-new.pxsol.com/I8RIr_toEMHY9LLmg6frgIiA3Q7kVj_VbKrbxpcT_cU/rs:fill:144:144:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 48<link rel="apple-touch-icon" sizes="152x152" href="https://images-new.pxsol.com/cIm410q0YquLb0Uf9WNQVC9GKrMwysqTFRos6AC3y6k/rs:fill:152:152:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 49<link rel="apple-touch-icon" sizes="180x180" href="https://images-new.pxsol.com/16fCed3HSNvWdAMWVwLcXIXrgagQU3936suwxCGNX04/rs:fill:180:180:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 50 51<link rel="icon" sizes="192x192" href="https://images-new.pxsol.com/-Yf5A7vNvQSoGGnNEUUQwCJXrvds9EzCOBgo-8FFCWo/rs:fill:192:192:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 52<link rel="icon" sizes="512x512" href="https://images-new.pxsol.com/L_sI1fGsipYlAKrw-1zWxyXjFA0lk4z-1tjrR9UkQLs/rs:fill:512:512:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 53 54 <link rel="manifest" href="/manifest.json?pos=PremiumTowerApartHotel"> 55 56<meta name="theme-color" content="#b29e73"> 57 58<meta property="og:site_name" content="Habitaciones - Hotel Premium Tower Suites" /> 59<meta name="twitter:card" content="summary"> 60<meta name="twitter:site" content="Habitaciones - Hotel Premium Tower Suites"> 61<meta name="twitter:title" content="Habitaciones - Hotel Premium Tower Suites"> 62<meta name="twitter:description" content="Bienvenido a Premium Tower Suites Mendoza!"> 63<meta name="twitter:creator" content="PXSOL"> 64<meta name="twitter:image" content="https://images-new.pxsol.com/zCpb3wQ8tAPxyvptRRENo7U3l_bLkXyqwO1o1Eo7Anc/rs:fill:630:430:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F208072094042521a7eef689dd75da2
640d9a192531f4a.jpg@jpg"> 65 66 67 68<style> 69 .neo_bgcolor_primary, .MuiButton-containedSecondary { 70background-color: #b29e73 !important; 71} 72 73.MuiButton-containedSecondary.MuiButton-contained.Mui-disabled { 74 box-shadow: none !important; 75 background-color: rgba(0, 0, 0, 0.12) !important; 76} 77 78.neo_color_primary { 79color: #b29e73; 80} 81 82.cta_webcheckin_px:not(.btn_sesion) { 83background-color: #b29e73 !important; 84color: white !important; 85border: none !important; 86font-weight: bold; 87right: 0; 88display: flex; 89align-items: center; 90font-size: 13px !important; 91padding: 7px 8px !important; 92line-height: 1.2; 93text-align: left; 94} 95 96.cta_webcheckin_px.btn_sesion { 97border: none !important; 98font-weight: bold; 99right: 0; 100display: flex; 101align-items: center; 102font-size: 13px !important; 103padding: 7px 8px !important; 104line-height: 1.2; 105text-align: left; 106} 107 108.cta_webcheckin_px * { 109color: inherit !important; 110} 111 112.cta_webcheckin_px.btn_sesion > i { 113 color: #b29e73 !important; 114} 115 116.cta_webcheckin_px { 117background-color: #c2b28f; 118} 119.cta_webcheckin_px i { 120margin-right: 10px; 121font-size: 15px; 122} 123 124.neo_bgcolor_primary:hover, .MuiButton-containedSecondary:hover { 125background-color: #c2b28f; 126} 127.px-sm-inputcontainer:hover label { 128color: #b29e73 !important; 129} 130div.ui-datepicker#ui-datepicker-div .ui-state-active, div.ui-datepicker#ui-datepicker-div .ui-widget-content .ui-state-active, div.ui-datepicker#ui-datepicker-div .ui-widget-header .ui-state-active, div.ui-datepicker#ui-datepicker-div td:not(.ui-datepicker-today) .ui-state-highlight, div.ui-datepicker#ui-datepicker-div .ui-widget-content .ui-state-highlight, div.ui-datepicker#ui-datepicker-div .ui-widget-header .ui-state-highlight { 131background-color: #b29e73 !important; 132} 133 134.px-mk-iconchangesearch { 135color: #b29e73 !important; 136} 137 138.px-mk-locationdropdown>*:hover .px-mk-locationimg { 139fill: #b29e73 !important; 140} 141 142.neo_mobile_supratop .neo_supratop_selector i { 143color: #b29e73 !important; 144} 145 146.standard_cta { 147padding: 10px 15px; 148box-sizing: border-box; 149border-radius: 5px; 150display: flex; 151justify-content: center; 152text-align: center; 153align-items: center; 154background: #b29e73 !important; 155color: #000000; 156transition: .2s ease-out; 157color: white; 158text-decoration: none; 159font-size: 18px; 160border: none; 161transition: .25s ease-out; 162cursor: pointer; 163} 164 165.standard_cta:hover { 166background-color: #cabc9d; 167} 168.standard_cta:disabled { 169opacity: .5; 170cursor: not-allowed; 171} 172 173.neo_cta_naked {
174font-weight: bold; 175text-decoration: none; 176color: #b29e73; 177display: inline-flex; 178background-color: transparent; 179border: none; 180cursor: pointer; 181transition: .2s ease-out; 182} 183 184.neo_cta_naked.gray { 185color: darkgray; 186} 187 188.neo_cta_naked:hover { 189color: #7d6f51; 190} 191 192.neo_cta_standard { 193border: none; 194border-radius: 10px; 195padding: 12px 20px; 196font-size: 18px; 197display: flex; 198align-items: center; 199justify-content: space-between; 200font-weight: bold; 201cursor: pointer; 202transition: .25s ease-out; 203box-sizing: border-box; 204text-decoration: none; 205} 206 207.neo_cta_standard.smaller { 208font-size: 16px; 209padding: 7px 13px; 210} 211 212.neo_cta_standard.shadow { 213box-shadow: 0px -1px 15px rgba(0,0,0,.3); 214} 215 216.neo_cta_standard.lowpadding { 217padding: 12px; 218} 219.neo_cta_standard.lowpadding > i { 220margin: 0; 221} 222 223.neo_cta_standard:disabled { 224opacity: .5; 225cursor: not-allowed; 226} 227 228.neo_cta_standard.primary { 229background: #b29e73; 230color: #000000; 231} 232.neo_cta_standard.white_cta { 233background: white; 234color: black; 235} 236.neo_cta_standard.primary:hover { 237background-color: #7d6f51; 238color: #FFFFFF; 239} 240.neo_cta_standard.primary:active { 241background-color: #594f3a; 242color: #FFFFFF; 243} 244 245.neo_cta_standard > i { 246margin-left: 10px; 247} 248 249.neo_cta_standard:disabled, .neo_cta_standard[disabled] {
250cursor: not-allowed; 251filter: saturate(.3); 252opacity: 0.8; 253} 254 255.neo_cta_standard.v_disabled { 256background-color: #1e1e1e; 257} 258 259.neo_cta_standard .loading-text, .neo_cta_standard .success-text { 260display:none; 261} 262 263.neo_cta_standard.v_loading { 264pointer-events: none; 265} 266.neo_cta_standard.v_loading { 267position: relative; 268} 269.neo_cta_standard .loading-text { 270display:none; 271} 272.neo_cta_standard.v_loading > *:not(i,.loading-text) { 273display:none; 274} 275.neo_cta_standard.v_loading > i { 276position: relative; 277height: 20px; 278width: 20px; 279} 280 281.neo_cta_standard.v_loading > i:before { 282content: none; 283} 284 285.neo_cta_standard.v_loading > i::after { 286content: ""; 287position: absolute; 288width: 100%; 289height: 100%; 290box-sizing: border-box; 291top: 0; 292left: 0; 293right: 0; 294bottom: 0; 295margin: auto; 296border: 0.25rem solid transparent; 297border-top-color: #ffffff; 298border-right-color: #ffffff; 299border-radius: 50%; 300animation: spinner .6s linear infinite; 301} 302.neo_cta_standard.v_loading .loading-text { 303display:block; 304} 305 306.neo_cta_standard.v_success { 307background-color: #00a651; 308} 309.neo_cta_standard.v_success > *:not(.success-text) { 310display:none; 311} 312.neo_cta_standard.v_success .success-text { 313display:block; 314} 315@keyframes button-loading-spinner { 316from { 317transform: rotate(0turn); 318} 319 320to { 321transform: rotate(1turn); 322} 323} 324 325@keyframes spinner { 326to { 327transform: rotate(360deg); 328} 329} 330 331#innerLoader, .innerLoader { 332height: 100%; 333display: flex; 334justify-content: center; 335align-items: center; 336min-height: 200px; 337} 338.neo_spin_loader { 339height: 60px; 340width: 60px; 341margin-bottom: 20px; 342} 343.neo_spin_loader:before { 344content: ""; 345box-sizing: border-box; 346position: absolute; 347width: 60px; 348height: 60px; 349border-radius: 50%; 350border: 3px solid #ccc; 351border-top-color: #b29e73; 352animation: spinner 1s linear infinite; 353} 354.neo_bgcolor_primary { 355background-color: #b29e73; 356} 357 358.neo_button_partyselector { 359border: 1px solid #b29e73; 360height: 40px; 361width: 40px; 362display: flex; 363justify-content: center; 364align-items: center; 365text-align: center; 366background: transparent; 367color: #b29e73; 368margin: 10px 0; 369transition: .2s ease-out; 370border-radius: 10px; 371font-size: 18px; 372cursor: pointer; 373 374} 375 376.neo_button_partyselector:hover { 377background-color: #e1d9c7; 378} 379 380.neo_button_partyselector:focus { 381box-shadow: 0 0 0 3px #f0ece3; 382} 383 384.neo_button_partyselector:active { 385color: #000000; 386background: #b29e73; 387} 388 389.neo_partyselector_quantity { 390padding: 15px 10px; 391font-size: 18px; 392} 393 394.ChildrensAgeSelect { 395width: 100%; 396box-sizing: border-box; 397padding: 10px; 398margin-bottom: 10px; 399border-radius: 10px; 400border-color: #ccc; 401} 402 403.PartyTypeSimulator .px-mk-inputicon svg { 404height: 1.2em; 405width: 1.2em; 406fill: #aaa; 407} 408.neo_bgcolor_primary_text { 409color: #000000; 410} 411 412.neo_pxuser_mainbtn { 413height: 3.5rem; 414max-height: 100%; 415overflow: hidden; 416transition: .2s ease-out; 417border-radius: .5rem; 418cursor: pointer; 419padding: 0 0.5rem; 420background-color: white; 421color: black !important; 422} 423 424.neo_pxuser_mainbtn * { 425color: black !important; 426} 427 428.neo_pxuser_mainbtn:hover { 429background-color: #f2f2f2; 430} 431 432.neo_pxuser_avatar_container { 433height: 100%; 434width: 3rem; 435display: flex; 436justify-content: center; 437align-items: center; 438} 439 440.neo_pxuser_avatar_container img { 441height: 80%; 442border-radius: 2rem; 443} 444 445.neo_pxuser_text_block { 446padding: .5rem .5rem .5rem .5rem; 447box-sizing: border-box; 448height: 100%; 449justify-content: center; 450line-height: 1.5; 451} 452 453.neo_pxuser_icon_dd { 454padding: .5rem; 455box-sizing: border-box; 456} 457 458.neo_pxuser_dropdown { 459position: absolute; 460right: 0; 461top: 100% !important; 462background: white; 463border-radius: .25rem; 464min-width: 110%; 465box-shadow: 0 3px 6px rgba(0,0,0,.5); 466text-align: left; 467display: none !important; 468} 469 470.neo_pxuser_dropdown * { 471color: black !important; 472} 473 474.neo_pxuser_dropdown.open { 475display: flex !important; 476top: 100% !important; 477} 478 479.neo_pxuser_dd_button { 480padding: 1rem; 481transition: .2s ease-out; 482cursor: pointer; 483text-decoration: none; 484color: black; 485} 486 487.neo_pxuser_dd_button > .mdi { 488font-size: 1.2rem; 489line-height: 1; 490vertical-align: middle; 491display: inline-flex; 492width: 2rem; 493justify-content: center; 494align-items: center; 495height: 2rem; 496} 497 498.neo_pxuser_dd_button > span { 499padding: .5rem; 500display: inline-flex; 501flex-grow: 1; 502width: calc(100% - 3rem); 503} 504 505.neo_pxuser_dd_button:hover { 506background-color: #f2f2f2; 507border-radius: .25rem; 508} 509 510.neo_pxuser_email { 511 max-width: 8rem; 512 overflow: hidden; 513 text-overflow: ellipsis; 514} 515 516@media only screen and (max-width: 468px) { 517 518 .neo_pxuser_mainbtn { 519 flex-flow: row-reverse; 520 flex-grow: 1; 521 } 522 523 .neo_pxuser_icon_dd { 524 display: none; 525 } 526 527 .neo_pxuser_text_block { 528 text-align: right; 529 text-transform: none; 530 letter-spacing: initial; 531 color: black; 532 line-height: 1; 533 max-width: 50%; 534 } 535 536 .neo_pxuser_email { 537 display: none; 538 } 539 540 .neo_pxuser_container { 541 text-transform: initial; 542 letter-spacing: initial; 543 font-weight: normal; 544 font-size: .8rem; 545 } 546 547 .neo_pxuser_name { 548 font-weight: bold; 549 text-align: left; 550 white-space: nowrap; 551 overflow: hidden; 552 text-overflow: ellipsis; 553 display: flex; 554 align-items: center; 555 } 556 557 .neo_pxuser_name strong { 558 display: inline-block; 559 max-width: 150px; 560 overflow: hidden; 561 white-space: nowrap; 562 text-overflow: ellipsis; 563 vertical-align: middle; 564 line-height: 1.2; 565 } 566 567 .neo_pxuser_dd_button { 568 padding: .5rem; 569 } 570 571 572}</style> 573 574 575
576<script type="application/ld+json" defer async> 577{ 578 "url" : "https:\/\/www.premiumtowersuites.com.ar\/en\/habitaciones.html", 579 "telephone": "+54 261 248 0888", 580 "description" : "Bienvenido a Premium Tower Suites Mendoza!", 581 "name" : "Habitaciones - Hotel Premium Tower Suites", 582 "logo" : "https:\/\/images-new.pxsol.com\/L_sI1fGsipYlAKrw-1zWxyXjFA0lk4z-1tjrR9UkQLs\/rs:fill:512:512:1\/q:80\/plain\/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png", 583 "image" : "https:\/\/images-new.pxsol.com\/zCpb3wQ8tAPxyvptRRENo7U3l_bLkXyqwO1o1Eo7Anc\/rs:fill:630:430:1\/q:80\/plain\/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F208072094042521a7eef689dd75da20d9a192531f4a.jpg@jpg", 584 "aggregateRating" : { 585 "reviewCount" : 585, 586 "@type" : "AggregateRating", 587 "bestRating" : 10, 588 "ratingValue" : 9.2 }, 589 "@type" : "Hotel", 590 "address" : { 591 "postalCode" : "5500", 592 "streetAddress" : "Av. España 948, M5500 Mendoza, Argentina, 5500 Capital, Mendoza, Argentina", 593 "addressCountry" : "Argentina", 594 "addressRegion" : "Mendoza", 595 "addressLocality" : "Capital", 596 "@type" : "PostalAddress" 597 }, 598 "geo": { 599 "@type": "GeoCoordinates", 600 "latitude": -32.8917813, 601 "longitude": -68.842663 }, 602 "@context" : "http://schema.org" 603 } 604</script>
604 605 606<!-- Organization Schema for Brand/Logo SEO -->
607<script type="application/ld+json"> 608{ 609 "@context": "https://schema.org", 610 "@type": "Organization", 611 "name": "Habitaciones - Hotel Premium Tower Suites", 612 "url": "https:\/\/www.premiumtowersuites.com.ar\/en\/habitaciones.html", 613 "logo": "https:\/\/images-new.pxsol.com\/L_sI1fGsipYlAKrw-1zWxyXjFA0lk4z-1tjrR9UkQLs\/rs:fill:512:512:1\/q:80\/plain\/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png", 614 "image": "https:\/\/images-new.pxsol.com\/L_sI1fGsipYlAKrw-1zWxyXjFA0lk4z-1tjrR9UkQLs\/rs:fill:512:512:1\/q:80\/plain\/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"} 615</script>
615 616 617 618 619 <link rel="icon" sizes="192x192" href="https://images-new.pxsol.com/-Yf5A7vNvQSoGGnNEUUQwCJXrvds9EzCOBgo-8FFCWo/rs:fill:192:192:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F241250311408a778cb276110216fe92234bb4283ca1.png@png"> 620 <link rel="icon" type="image/png" href="https://files-p.pxsol.com/18413/company/library/user/241250311408a778cb276110216fe92234bb4283ca1.png" /> 621 <!-- CustomHTMLHead (SiteJson) --><link rel="preconnect" href="https://fonts.googleapis.com"> 622<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 623<link href="https://fonts.googleapis.com/css2?family=Jost:ital,wght@0,100..900;1,100..900&family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap" rel="stylesheet"> 624<meta name="facebook-domain-verification" content="z14neqel3ls8yrz9f1dwkl3i2gyy10" /> <!-- Pos->Type: hotel.css --> 625 626<!-- Google tag (gtag.js) GA4 PXSOL TODOS LOS HOTELES -->
627<script> 628 window.dataLayer = window.dataLayer || []; 629 function gtag(){dataLayer.push(arguments);} 630 gtag('js', new Date()); 631</script>
vendor: 64 bytes, lines 631-632
631 632<script async src="https://www.googletagmanager.com/gtag/js?id=
632G-SYSQR6EL6E
vendor: 12 bytes, line 632
632"></script>
633<script> 634 let globalSessionGA4Config = { 635 'pos': 'PremiumTowerApartHotel', 636 'product_id': '19433', 637 'product_name': 'Hotel Premium Tower Suites', 638 'product_country': 'Argentina', 639 'product_state': 'Mendoza', 640 'product_plaza': 'Capital', 641 'product_score': '93' 642 }; 643 644 645 gtag('config', 'G-SYSQR6EL6E', globalSessionGA4Config); 646 647 gtag('config', 'AW-1028619328', globalSessionGA4Config); 648 649 // Mirror page_view into dataLayer for GTM debug (guard to avoid duplicates) 650 if (!window.__dl_page_view_pushed) { 651 window.dataLayer.push({ event: 'page_view' }); 652 window.__dl_page_view_pushed = true; 653 } 654 655 656</script>
656 657 658<!-- Global site tag (gtag.js) -->
vendor: 64 bytes, lines 658-659
658 659<script async src="https://www.googletagmanager.com/gtag/js?id=
659UA-34517567-10
vendor: 12 bytes, line 659
659"></script>
660<script> 661 window.dataLayer = window.dataLayer || []; 662 663 function gtag() { 664 dataLayer.push(arguments); 665 try { 666 var args = Array.prototype.slice.call(arguments); 667 if (args[0] === 'event') { 668 var dlEventName = args[1]; 669 var dlParams = (args.length > 2 && typeof args[2] === 'object') ? args[2] : {}; 670 var dlObject = {}; 671 for (var key in dlParams) { 672 if (Object.prototype.hasOwnProperty.call(dlParams, key)) { 673 dlObject[key] = dlParams[key]; 674 } 675 } 676 dlObject.event = dlEventName; 677 window.dataLayer.push(dlObject); 678 679 // Intercept add_to_cart and fire form_success after it 680 if (dlEventName === 'add_to_cart') { 681 setTimeout(function() { 682 console.log('%c[pxTrack] ð FIRING form_success for add_to_cart', 'color: #4CAF50; font-weight: bold;'); 683 window.pxTrack('form_success', { 684 form_id: 'add_to_cart', 685 lead_id: null, 686 transaction_id: null 687 }); 688 }, 100); 689 } 690 } 691 } catch (e) {} 692 } 693 gtag('js', new Date()); 694 695 696 gtag('config', 'UA-34517567-10'); 697 698 gtag('config', 'AW-1028619328'); 699 700 </script>
700 701 702<!-- Pxsol Data Layer utilities and event wiring -->
703<script> 704 (function() { 705 // DEBUG: Confirm script is loaded and updated 706 console.log('%c[pxTrack] Script loaded - Version: 2025-01-15-no-inventory-v3-rate-limit-fix', 'color: #4CAF50; font-weight: bold; font-size: 12px;'); 707 708 // Define manual scan function globally FIRST (before any other code that might fail) 709 window.__px_manual_no_inventory_scan = function() { 710 console.log('[pxTrack] Manual scan triggered'); 711 if (window.__px_no_inventory_scan_func) { 712 return window.__px_no_inventory_scan_func(); 713 } else { 714 console.warn('[pxTrack] Watcher not initialized yet. Performing basic scan...'); 715 // Perform basic scan even if watcher not initialized 716 try { 717 var hasNoInventory = false; 718 var detectionMethod = ''; 719 720 // Check DOM elements 721 var noInventoryContainer = document.querySelector('#no-inventory-container'); 722 var noInventoryElement = document.querySelector('#no-inventory'); 723 if (noInventoryContainer || noInventoryElement) { 724 hasNoInventory = true; 725 detectionMethod = 'DOM element (ID)'; 726 console.log('[pxTrack] â Found #no-inventory-container or #no-inventory'); 727 } 728 729 // Check px_jsonQuery 730 if (!hasNoInventory && typeof window.px_jsonQuery !== 'undefined' && window.px_jsonQuery) { 731 var jsonQuery = window.px_jsonQuery; 732 if (jsonQuery.ProductList && Array.isArray(jsonQuery.ProductList) && jsonQuery.ProductList.length > 0) { 733 var allZero = true; 734 for (var i = 0; i < jsonQuery.ProductList.length; i++) { 735 var product = jsonQuery.ProductList[i]; 736 var productAvail = product.Availability || 0; 737 if (product.SkuList && Array.isArray(product.SkuList) && product.SkuList.length > 0) { 738 for (var j = 0; j < product.SkuList.length; j++) { 739 if (product.SkuList[j].Availability && product.SkuList[j].Availability > 0) { 740 allZero = false; 741 break; 742 } 743 } 744 } else if (productAvail > 0) { 745 allZero = false; 746 } 747 if (!allZero) break; 748 } 749 if (allZero) { 750 hasNoInventory = true; 751 detectionMethod = 'Json_Query'; 752 console.log('[pxTrack] â All products have Availability === 0'); 753 } 754 } 755 } 756 757 if (hasNoInventory && !window.__px_no_inventory_pushed) { 758 console.log('[pxTrack] ð FIRING no_inventory event manually - Method:', detectionMethod); 759 window.__px_no_inventory_pushed = true; 760 var params = {}; 761 try { 762 // Try to get search params 763 var startRaw = (document.querySelector('#fechaingreso') || {}).value || ''; 764 var endRaw = (document.querySelector('#fechaegreso') || {}).value || ''; 765 params.start_date = startRaw; 766 params.end_date = endRaw; 767 params.no_inventory = true; 768 } catch(e) {} 769 window.pxTrack('no_inventory', params); 770 771 // Fire form_success for search form after no_inventory 772 setTimeout(function() { 773 console.log('%c[pxTrack] ð FIRING form_success for search form (after manual no_inventory)', 'color: #4CAF50; font-weight: bold;'); 774 window.pxTrack('form_success', { 775 form_id: 'pxmk_searchform', 776 lead_id: null, 777 transaction_id: null 778 }); 779 }, 100); 780 781 return { fired: true, method: detectionMethod, params: params }; 782 } else if (hasNoInventory) { 783 return { already_fired: true, method: detectionMethod }; 784 } else { 785 return { no_inventory_detected: false, px_jsonQuery_exists: typeof window.px_jsonQuery !== 'undefined' }; 786 } 787 } catch(e) { 788 console.error('[pxTrack] Error in manual scan:', e); 789 return { error: 'Scan failed', message: e.message }; 790 } 791 } 792 }; 793 794 window.dataLayer = window.dataLayer || []; 795 796 // Helper that tracks to both GA4 and dataLayer 797 if (!window.pxTrack) { 798 window.pxTrack = function(eventName, params) { 799 params = params || {}; 800 try { gtag('event', eventName, params); } catch(e) {} 801 try { 802 var dl = {}; 803 for (var k in params) if (Object.prototype.hasOwnProperty.call(params, k)) dl[k] = params[k]; 804 dl.event = eventName; 805 window.dataLayer.push(dl); 806 } catch(e) {} 807 }; 808 } 809 810 // Privacy-safe booleans for PII presence 811 function bool(val) { return !!val; } 812 813 // Read URL param 814 function getUrlParam(name) {
815 try { 816 var params = new URLSearchParams(location.search); 817 return params.get(name) || ''; 818 } catch (e) { return ''; } 819 } 820 821 // Normalize common date formats to YYYY-MM-DD (best-effort) 822 function normalizeDate(value) { 823 try { 824 if (!value) return ''; 825 var v = String(value).trim(); 826 // dd/mm/yyyy -> yyyy-mm-dd 827 if (/^\d{2}\/\d{2}\/\d{4}$/.test(v)) { 828 var p = v.split('/'); 829 return [p[2], p[1].padStart(2, '0'), p[0].padStart(2, '0')].join('-'); 830 } 831 // Already ISO 832 if (/^\d{4}-\d{2}-\d{2}$/.test(v)) return v; 833 return v; 834 } catch (e) { 835 return String(value || ''); 836 } 837 } 838 839 // Session id generator 840 function getPxSessionId() { 841 try { 842 var key = 'px_session_id'; 843 var match = document.cookie.match(new RegExp('(^| )' + key + '=([^;]+)')); 844 if (match) return match[2]; 845 var id = (crypto && crypto.randomUUID) ? crypto.randomUUID() : String(Date.now()) + '_' + Math.floor(Math.random()*1e9); 846 document.cookie = key + '=' + id + ';path=/;max-age=' + (60*60*24*365).toString(); 847 return id; 848 } catch(e) { 849 return 'sid_' + String(Date.now()); 850 } 851 } 852 853 // Expose chat helpers (to be called from chat widget) 854 window.pxChatOpen = function(payload) { window.pxTrack('chat_open', payload || {}); }; 855 window.pxChatMessage = function(payload) { window.pxTrack('chat_message', payload || {}); }; 856 window.pxChatClose = function(payload) { window.pxTrack('chat_close', payload || {}); }; 857 window.pxFormSuccess = function(payload) { window.pxTrack('form_success', payload || {}); }; 858 window.pxNoInventory = function(payload) { window.pxTrack('no_inventory', payload || { no_inventory: true }); }; 859 860 // Context payload from PHP (best-effort) 861 var pxContext = { 862 pos: 'PremiumTowerApartHotel', 863 product_id: '19433', 864 product_name: 'Hotel Premium Tower Suites', 865 product_country: 'Argentina', 866 product_state: 'Mendoza', 867 product_plaza: 'Capital', 868 search_id: '', 869 start_date: '', 870 end_date: '', 871 transaction_id: '', 872 value: null, 873 currency: '', 874 page_url: location.href, 875 session_id: getPxSessionId() 876 }; 877 878 // --- External engine redirect auto event when engine is disabled --- 879 880 881 // Adults/children/rooms best-effort totals from PHP when available 882 pxContext.adults = 0; 883 pxContext.children = 0; 884 pxContext.rooms = 0; 885 886 // Push context for GTM usage 887 try { window.dataLayer.push(Object.assign({ event: 'px_context' }, pxContext)); } catch(e) {} 888 889 // Boot event para validar integración en DebugView/GTM 890 if (!window.__px_boot_pushed) { 891 window.__px_boot_pushed = true; 892 window.pxTrack('px_layer_ready', { 893 session_id: pxContext.session_id, 894 page_url: pxContext.page_url, 895 pos: pxContext.pos || '', 896 product_id: pxContext.product_id || '', 897 search_id: pxContext.search_id || '', 898 ts: Date.now() 899 }); 900 } 901 902 // ----- Search events wiring (V3/V8) ----- 903 function getSearchParamsFromDOM() { 904 var startRaw = (document.querySelector('.neo_marketplace_buscador_v3 #fechaingreso') || 905 document.querySelector('#fechaingreso') || 906 document.querySelector('[name="Start"]') || 907 document.querySelector('#Start') || { }).value || pxContext.start_date || ''; 908 var endRaw = (document.querySelector('.neo_marketplace_buscador_v3 #fechaegreso') || 909 document.querySelector('#fechaegreso') || 910 document.querySelector('[name="End"]') || 911 document.querySelector('#End') || { }).value || pxContext.end_date || ''; 912 var sidRaw = (document.querySelector('#SearchID') || { }).value || getUrlParam('SearchID') || pxContext.search_id || ''; 913 var params = { 914 start_date: normalizeDate(startRaw) || '', 915 end_date: normalizeDate(endRaw) || '', 916 pos: pxContext.pos || '', 917 hotel_id: pxContext.product_id || '', 918 page_url: location.href, 919 session_id: pxContext.session_id 920 };
921 if (sidRaw) params.search_id = sidRaw; 922 // Adults/children from UI if present 923 try { 924 var adultsEl = document.querySelector('.neo_partyselector_quantity[party-type="adults"]'); 925 var childrenEl = document.querySelector('.neo_partyselector_quantity[party-type="children"]'); 926 if (adultsEl) params.adults = Number(adultsEl.getAttribute('val') || adultsEl.textContent) || pxContext.adults || 0; 927 if (childrenEl) params.children = Number(childrenEl.getAttribute('val') || childrenEl.textContent) || pxContext.children || 0; 928 // Fallback from hidden GroupsForm if exists 929 if ((!params.adults || !params.children) && document.querySelector('#GroupsForm')) { 930 var gf = document.querySelector('#GroupsForm').value || ''; 931 var rooms = 0, adults = 0, children = 0; 932 if (gf) { 933 gf.split(';').forEach(function(groupStr){ 934 if (!groupStr) return; 935 rooms += 1; 936 var parts = groupStr.split(':'); 937 if (parts.length < 2) return; 938 var trio = parts[1].split(','); 939 var a = parseInt(trio[0] || '0', 10); 940 adults += isNaN(a) ? 0 : a; 941 var childrenAges = (trio[1] || '0'); 942 if (childrenAges && childrenAges !== '0') { 943 children += childrenAges.split('.').filter(Boolean).length; 944 } 945 }); 946 if (!params.adults) params.adults = adults; 947 if (!params.children) params.children = children; 948 if (!params.rooms) params.rooms = rooms; 949 } 950 } 951 } catch(e) {} 952 return params; 953 } 954 955 // -- Estado COMPARTIDO del throttle de `search_modify` -------------------------------- 956 // Vive FUERA de las funciones de cableado a proposito: `wireSearchEventsWhenReady()` puede 957 // re-ejecutar `wireSearchEvents()` varias veces hasta enganchar el buscador que llega por 958 // AJAX, y con el throttle dentro del cierre cada invocacion tenia su propia ventana de 1 s 959 // => dos cableados equivalentes podian emitir el mismo cambio dos veces. 960 var pxLastModifyMs = 0; 961 var pxLastSnapshot = null; 962 963 function getModifySnapshot() { 964 var p = getSearchParamsFromDOM(); 965 return { 966 start_date: p.start_date || '', 967 end_date: p.end_date || '', 968 rooms: (p.rooms*1) || 0, 969 adults: (p.adults*1) || 0, 970 children: (p.children*1) || 0 971 }; 972 } 973 function pushModifyFlagsIfChanged(prevSnap, nextSnap) { 974 try { 975 if (!prevSnap) return true; 976 var changes = {}; 977 if (nextSnap.start_date !== prevSnap.start_date) changes.start_date = true; 978 if (nextSnap.end_date !== prevSnap.end_date) changes.end_date = true; 979 if ((nextSnap.rooms*1) !== (prevSnap.rooms*1)) changes.rooms = true; 980 if ((nextSnap.adults*1) !== (prevSnap.adults*1)) changes.adults = true; 981 if ((nextSnap.children*1) !== (prevSnap.children*1)) changes.children = true; 982 if (Object.keys(changes).length) return true; 983 } catch (e) {} 984 return false; 985 } 986 function throttledModifyFire() { 987 var now = Date.now(); 988 if (now - pxLastModifyMs < 1000) return; // throttle to 1s 989 pxLastModifyMs = now; 990 var current = getModifySnapshot(); 991 // Push GA/DataLayer event with current values 992 window.pxTrack('search_modify', getSearchParamsFromDOM()); 993 // Also push a probe event with the current values for GTM debug 994 try { 995 window.dataLayer.push({ 996 event: 'px_search_modify_probe', 997 search_modify: current, 998 ts: Date.now() 999 }); 1000 } catch(e) {} 1001 // Update snapshot only if something changed 1002 if (pushModifyFlagsIfChanged(pxLastSnapshot, current)) { 1003 pxLastSnapshot = current; 1004 } 1005 } 1006 1007 /** 1008 * Respaldos de `search_modify` que NO dependen de que el buscador exista en el DOM: 1009 * listeners DELEGADOS en `document` (captura) + un poller de 400 ms sobre 1010 * `#fechaingreso`/`#fechaegreso`/`#GroupsForm`. 1011 * 1012 * OJO: se instalan SIEMPRE en el init, sin pasar por `searchDomPresent()` ni por el tope de 1013 * 20 s del watcher -- que es exactamente como se instalaban antes, cuando `wireSearchEvents()` 1014 * se llamaba incondicionalmente. Justamente por ser delegados/poll son los que hacen que 1015 * `search_modify` funcione sobre un buscador inyectado por AJAX: meterlos detras del 1016 * reintento dejaba sin ningun listener a las sesiones donde el buscador tarda mas de 20 s 1017 * (telefono con red lenta), que ANTES si los tenian. 1018 */ 1019 function wireSearchFallbacks() { 1020 if (window.__px_search_fallbacks_wired) return; 1021 window.__px_search_fallbacks_wired = true; 1022 pxLastSnapshot = getModifySnapshot(); 1023 // Debug: signal that search watchers are alive
1024 try { 1025 window.dataLayer.push({ 1026 event: 'px_search_watchers_ready', 1027 ts: Date.now() 1028 }); 1029 } catch(e) {} 1030 // Listeners delegados (capturan aunque el DOM se re-renderice) 1031 try { 1032 if (!window.__px_global_search_listeners) { 1033 window.__px_global_search_listeners = true; 1034 var selectorList = ['#fechaingreso','#fechaegreso','.AdultsSelect','.ChildrensSelect','.neo_partyselector_quantity','.ChildrensAgeSelect']; 1035 function matchesTracked(el) { 1036 try { return selectorList.some(function(sel){ return el && el.matches && el.matches(sel); }); } catch(e) { return false; } 1037 } 1038 document.addEventListener('change', function(e){ if (matchesTracked(e.target)) throttledModifyFire(); }, true); 1039 document.addEventListener('input', function(e){ if (matchesTracked(e.target)) throttledModifyFire(); }, true); 1040 document.addEventListener('click', function(e){ 1041 var t = e.target; 1042 if (t && t.classList && t.classList.contains('neo_button_partyselector')) throttledModifyFire(); 1043 }, true); 1044 } 1045 } catch(e) {} 1046 // Robust watchers for datepicker-driven value changes and hidden GroupsForm updates 1047 try { 1048 if (!window.__px_modify_watchers_started) { 1049 window.__px_modify_watchers_started = true; 1050 var lastIn = (document.querySelector('#fechaingreso') || {}).value || ''; 1051 var lastOut = (document.querySelector('#fechaegreso') || {}).value || ''; 1052 var lastGF = (document.querySelector('#GroupsForm') || {}).value || ''; 1053 setInterval(function(){ 1054 try { 1055 var inEl = document.querySelector('#fechaingreso'); 1056 var outEl = document.querySelector('#fechaegreso'); 1057 var gfEl = document.querySelector('#GroupsForm'); 1058 var curIn = inEl ? inEl.value : ''; 1059 var curOut = outEl ? outEl.value : ''; 1060 var curGF = gfEl ? gfEl.value : ''; 1061 if (curIn !== lastIn || curOut !== lastOut || curGF !== lastGF) { 1062 lastIn = curIn; lastOut = curOut; lastGF = curGF; 1063 throttledModifyFire(); 1064 } 1065 } catch(e) {} 1066 }, 400); 1067 } 1068 } catch(e) {} 1069 } 1070 1071 /** 1072 * SOLO los cableados que necesitan el nodo del buscador en el DOM: `search_open` (existe el 1073 * contenedor) y `search_submit` (existe el form). Los reintenta `wireSearchEventsWhenReady()`. 1074 * 1075 * OJO: ya NO cuelga listeners de `search_modify` del contenedor. Eran un duplicado EXACTO de 1076 * los delegados de `wireSearchFallbacks()` (la misma lista de 6 selectores y el mismo click 1077 * sobre `.neo_button_partyselector`). Mientras esta funcion corria una sola vez compartian el 1078 * cierre -- y con el el throttle -- asi que no se notaba; con el reintento podian quedar en 1079 * invocaciones distintas y contar el mismo cambio dos veces. 1080 */ 1081 function wireSearchEvents() { 1082 var searchForm = document.querySelector('.neo_marketplace_buscador_v3 #pxmk_searchform') || document.querySelector('#search_form'); 1083 var searchContainer = document.querySelector('.neo_marketplace_buscador_v3') || document.querySelector('.px-mk-buscador-container') || document.querySelector('#search_form') || document.querySelector('.PartyTypeSimulatorContainer'); 1084 1085 if (searchContainer && !window.__px_search_container_bound) { 1086 window.__px_search_container_bound = true; 1087 // fire search_open once 1088 if (!window.__px_search_open_pushed) { 1089 window.__px_search_open_pushed = true; 1090 window.pxTrack('search_open', { page_url: location.href }); 1091 } 1092 } 1093 1094 if (searchForm && !window.__px_search_form_bound) { 1095 window.__px_search_form_bound = true; 1096 searchForm.addEventListener('submit', function() { 1097 window.pxTrack('search_submit', getSearchParamsFromDOM()); 1098 }, true); 1099 var searchBtn = document.querySelector('.neo_marketplace_buscador_v3 #PxMkAcion_Search') || document.querySelector('#Acion_Search'); 1100 if (searchBtn) { 1101 searchBtn.addEventListener('click', function() {
1102 window.pxTrack('search_submit', getSearchParamsFromDOM()); 1103 }, true); 1104 } 1105 } 1106 } 1107 1108 /** 1109 * El buscador NO existe al DOMContentLoaded en NINGUNA `lp.html`: lo inyecta por AJAX 1110 * `neo_modules/lp_cart.php` (CargarModulo) cientos de ms despues. `wireSearchEvents()` se 1111 * cableaba UNA sola vez, asi que sus dos gates de DOM evaluaban null y no se emitian nunca 1112 * `search_open` (gate `if (searchContainer)`) ni `search_submit` (gate `if (searchForm)`), 1113 * ni `start_search`/`egreso_search` (`wireDatePickers`). Sólo disparaban en las HOME 1114 * server-rendered, donde el buscador viene en el HTML inicial. 1115 * 1116 * Medido en vivo el 2026-08-21 sobre `fincaogawa.reservadirecto.com/lp.html`: los 6 1117 * selectores del buscador estan en 0 en DOMContentLoaded (1389 ms) y en load (2369 ms), y 1118 * recien aparecen a los ~3010 ms; un click en el submit real (`#Acion_Search`) generaba 1119 * SearchID y `has_inventory`, pero CERO `search_submit`. 1120 * 1121 * `has_inventory`/`no_inventory` nunca sufrieron esto porque cuelgan de una cascada de scans 1122 * + MutationObserver (`wireNoInventoryWatcher` / `observeAvailabilityContainers`), no de un 1123 * cableado one-shot. Esta funcion aplica esa MISMA tecnica a la fam
1123ilia de busqueda. 1124 * 1125 * Se apaga sola en cuanto engancha el contenedor y el form (los dos productores de 1126 * `search_open`/`search_submit`), con tope duro de 20 s. Cada bind es idempotente por su 1127 * propia guarda global, asi que re-correr no duplica ni un listener ni un evento. 1128 */ 1129 function searchDomPresent() { 1130 try { 1131 return !!(document.querySelector('.neo_marketplace_buscador_v3') 1132 || document.querySelector('.px-mk-buscador-container') 1133 || document.querySelector('#search_form') 1134 || document.querySelector('.PartyTypeSimulatorContainer') 1135 || document.querySelector('#fechaingreso')); 1136 } catch (e) { return false; } 1137 } 1138 function wireSearchEventsWhenReady() { 1139 if (window.__px_search_ready_watcher) return; 1140 window.__px_search_ready_watcher = true; 1141 var mo = null; 1142 var stopped = false; 1143 function stop() { 1144 if (stopped) return; 1145 stopped = true; 1146 if (mo) { try { mo.disconnect(); } catch (e) {} mo = null; } 1147 } 1148 function attempt() { 1149 if (stopped) return; 1150 // Chequeo barato primero: sin buscador en el DOM no se toca nada. Evita correr 1151 // `wireSearchEvents()` (que lee bastante DOM) en cada mutacion de una pagina sin motor. 1152 if (!searchDomPresent()) return; 1153 if (!window.__px_search_container_bound || !window.__px_search_form_bound) { 1154 try { wireSearchEvents(); } catch (e) {} 1155 } 1156 if (!window.__px_date_pickers_bound) { 1157 try { wireDatePickers(); } catch (e) {} 1158 } 1159 if (window.__px_search_container_bound && window.__px_search_form_bound) stop(); 1160 } 1161 attempt(); 1162 if (stopped) return; 1163 [200, 500, 1000, 2000, 3000, 5000, 8000, 12000].forEach(function(ms){ 1164 setTimeout(attempt, ms); 1165 }); 1166 setTimeout(stop, 20000); 1167 if ('MutationObserver' in window && document.body) { 1168 try { 1169 mo = new MutationObserver(function(){ 1170 if (stopped || mo.__px_scheduled) return; 1171 mo.__px_scheduled = true; 1172 setTimeout(function(){ if (mo) { mo.__px_scheduled = false; } attempt(); }, 100); 1173 }); 1174 mo.observe(document.body, { childList: true, subtree: true }); 1175 } catch (e) { mo = null; } 1176 } 1177 } 1178 1179 // ----- Form events wiring (generic) ----- 1180 function wireFormEvents() { 1181 var forms = Array.prototype.slice.call(document.querySelectorAll('form:not([data-px-ignore="true"])')); 1182 var observed = new WeakSet(); 1183 1184 // form_view when enters viewport first time 1185 if ('IntersectionObserver' in window) { 1186 var io = new IntersectionObserver(function(entries) { 1187 entries.forEach(function(entry) { 1188 if (entry.isIntersecting && !observed.has(entry.target)) { 1189 observed.add(entry.target); 1190 window.pxTrack('form_view', { 1191 form_id: entry.target.id || entry.target.getAttribute('name') || 'form', 1192 page_url: location.href 1193 }); 1194 } 1195 }); 1196 }, { threshold: 0.2 }); 1197 forms.forEach(function(f){ io.observe(f); }); 1198 } else { 1199 forms.forEach(function(f){ 1200 window.pxTrack('form_view', { form_id: f.id || f.getAttribute('name') || 'form', page_url: location.href }); 1201 }); 1202 } 1203 1204 // form_interaction on field focus 1205 document.addEventListener('focusin', function(e) { 1206 var field = e.target; 1207 var form = field.form; 1208 if (!form) return; 1209 var fieldName = field.name || field.id || field.type || 'field'; 1210 try { 1211 if (field.classList && field.classList.contains('neo_partyselector_quantity')) { 1212 var pt = field.getAttribute('party-type'); 1213 if (pt) fieldName = 'party_' + pt; 1214 } 1215 } catch(e) {} 1216 window.pxTrack('form_interaction', { 1217 form_id: form.id || form.getAttribute('name') || 'form', 1218 field_name: fieldName 1219 }); 1220 }); 1221 1222 // form_submit with privacy-safe flags 1223 forms.forEach(function(form) { 1224 form.addEventListener('submit', function() { 1225 var email = form.querySelector('input[type="email"]'); 1226 var phone = form.querySelector('input[type="tel"], input[name*="phone"], input[name*="telefono"]'); 1227 var required = Array.prototype.slice.call(form.querySelectorAll('[required]')); 1228 var incomplete = required.some(function(el){ return !el.value; }); 1229 window.pxTrack('form_submit', { 1230 form_id: form.id || form.getAttribute('name') || 'form', 1231 page_url: location.href, 1232 fields_status: incomplete ? 'incompletos' : 'completos', 1233 email_provided: bool(email && email.value), 1234 phone_provided: bool(phone && phone.value), 1235 session_id: pxContext.session_id 1236 }); 1237 }, true); 1238 }); 1239 } 1240 // Extra: map clicks/changes on party selector controls to meaningful field_name 1241 (function wirePartySelectorInteractions(){
1242 try { 1243 var lastMs = 0; 1244 function pushPartyInteraction(partyType) { 1245 var now = Date.now(); 1246 if (now - lastMs < 400) return; 1247 lastMs = now; 1248 var form = document.querySelector('#search_form') || document.querySelector('.neo_marketplace_buscador_v3 #pxmk_searchform'); 1249 window.pxTrack('form_interaction', { 1250 form_id: form ? (form.id || form.getAttribute('name') || 'form') : 'form', 1251 field_name: partyType ? ('party_' + partyType) : 'party_selector' 1252 }); 1253 } 1254 document.addEventListener('click', function(e){ 1255 var t = e.target; 1256 if (t && t.classList && t.classList.contains('neo_button_partyselector')) { 1257 pushPartyInteraction(t.getAttribute('party-type') || ''); 1258 } 1259 }, true); 1260 document.addEventListener('change', function(e){ 1261 var t = e.target; 1262 if (t && t.classList && t.classList.contains('neo_partyselector_quantity')) { 1263 pushPartyInteraction(t.getAttribute('party-type') || ''); 1264 } 1265 }, true); 1266 document.addEventListener('input', function(e){ 1267 var t = e.target; 1268 if (t && t.classList && t.classList.contains('neo_partyselector_quantity')) { 1269 pushPartyInteraction(t.getAttribute('party-type') || ''); 1270 } 1271 }, true); 1272 } catch(e) {} 1273 })(); 1274 1275 // Fire specific date interactions (optional) 1276 function wireDatePickers() { 1277 if (window.__px_date_pickers_bound) return; 1278 var inEl = document.querySelector('.neo_marketplace_buscador_v3 #fechaingreso'); 1279 var outEl = document.querySelector('.neo_marketplace_buscador_v3 #fechaegreso'); 1280 // Todavia no llego el buscador: NO se marca como cableado, lo reintenta 1281 // `wireSearchEventsWhenReady()`. 1282 if (!inEl && !outEl) return; 1283 window.__px_date_pickers_bound = true; 1284 if (inEl) inEl.addEventListener('change', function(){ window.pxTrack('start_search', { start_search: inEl.value || '', page_url: location.href }); }); 1285 if (outEl) outEl.addEventListener('change', function(){ window.pxTrack('egreso_search', { egreso_search: outEl.value || '', page_url: location.href }); }); 1286 } 1287 1288 // ----- WhatsApp click tracking (GA4/dataLayer + Meta Pixel "Contact") ----- 1289 // El cliente pidió medir el clic en el botón de WhatsApp como una conversión más. 1290 // Se replica el patrón del resto de los eventos (window.pxTrack -> gtag + dataLayer) y, 1291 // si el POS tiene el pixel cargado (FacebookPixelID), se dispara el evento estándar "Contact". 1292 function wireWhatsappClick() { 1293 if (window.__px_whatsapp_wired) return; 1294 window.__px_whatsapp_wired = true; 1295 1296 var companyId = ''; 1297 var lastWaMs = 0; 1298 1299 function extractPhone(href) { 1300 try { 1301 var m = href.match(/[?&]phone=(\+?\d+)/i); 1302 if (m) return m[1]; 1303 m = href.match(/wa\.me\/(\+?\d+)/i); 1304 if (m) return m[1]; 1305 } catch (e) {} 1306 return ''; 1307 } 1308 1309 // Cualquier <a> hacia WhatsApp (api./web.whatsapp.com o wa.me), incluidos los botones 1310 // flotantes .wsp_floating (neo_social_links / standard_lp_motor) y #checkout_wsp_floating. 1311 function findWhatsappLink(el) { 1312 try { 1313 if (!el || !el.closest) return null; 1314 var a = el.closest('a'); 1315 if (!a) return null; 1316 var href = (a.getAttribute('href') || '').toLowerCase(); 1317 if (/(?:api\.|web\.)?whatsapp\.com|wa\.me/.test(href)) return a; 1318 if (a.closest('.wsp_floating') || a.closest('#checkout_wsp_floating')) return a; 1319 } catch (e) {} 1320 return null; 1321 } 1322 1323 // Delegado en captura: se dispara aunque el módulo re-renderice el botón (los .wsp_floating 1324 // se re-inyectan/mueven al body). target="_blank" mantiene la página viva para los beacons. 1325 document.addEventListener('click', function (e) { 1326 var link = findWhatsappLink(e.target); 1327 if (!link) return; 1328 var now = Date.now(); 1329 if (now - lastWaMs < 800) return; // dedupe de doble-disparo 1330 lastWaMs = now; 1331 1332 var href = link.getAttribute('href') || ''; 1333 var phone = extractPhone(href); 1334 var payload = { 1335 phone: phone, 1336 destination_url: href, 1337 pos: pxContext.pos || '', 1338 product_id: pxContext.product_id || '', 1339 product_name: pxContext.product_name || '', 1340 company_id: companyId || '', 1341 search_id: pxContext.search_id || '', 1342 currency: pxContext.currency || '', 1343 page_url: location.href, 1344 session_id: pxContext.session_id 1345 }; 1346 1347 // GA4 + dataLayer (Google y GTM) 1348 window.pxTrack('whatsapp_click', payload); 1349 1350 // Meta Pixel: evento estándar "Contact". fbq solo existe si el POS tiene FacebookPixelID 1351 // (se inicializa en Conversion_SearchOK.php / PageView), asà que este typeof es el guard. 1352 try { 1353 if (typeof window.fbq === 'function') { 1354 window.fbq('track', 'Contact', { content_name: 'whatsapp', content_category: 'whatsapp_click' }); 1355 } 1356 } catch (e) {} 1357 }, true); 1358 } 1359
1360 // Enrich context from hidden inputs present in LP/consultas templates 1361 function enhanceContextFromHiddenInputs() { 1362 var startRaw = (document.querySelector('#Start') || 1363 document.querySelector('#fechaingreso') || 1364 document.querySelector('[name="Start"]') || { }).value || ''; 1365 var endRaw = (document.querySelector('#End') || 1366 document.querySelector('#fechaegreso') || 1367 document.querySelector('[name="End"]') || { }).value || ''; 1368 var start = normalizeDate(startRaw); 1369 var end = normalizeDate(endRaw); 1370 var sid = (document.querySelector('#SearchID') || {}).value || ''; 1371 var gf = (document.querySelector('#GroupsForm') || {}).value || ''; 1372 var rooms = 0, adults = 0, children = 0; 1373 if (gf) { 1374 gf.split(';').forEach(function(groupStr){ 1375 if (!groupStr) return; 1376 rooms += 1; 1377 var parts = groupStr.split(':'); 1378 if (parts.length < 2) return; 1379 var trio = parts[1].split(','); 1380 var a = parseInt(trio[0] || '0', 10); 1381 adults += isNaN(a) ? 0 : a; 1382 var childrenAges = (trio[1] || '0'); 1383 if (childrenAges && childrenAges !== '0') { 1384 children += childrenAges.split('.').filter(Boolean).length; 1385 } 1386 }); 1387 } 1388 var updated = {}; 1389 if (start && start !== pxContext.start_date) { pxContext.start_date = start; updated.start_date = start; } 1390 if (end && end !== pxContext.end_date) { pxContext.end_date = end; updated.end_date = end; } 1391 if (sid && sid !== pxContext.search_id) { pxContext.search_id = sid; updated.search_id = sid; } 1392 if (adults && adults !== pxContext.adults) { pxContext.adults = adults; updated.adults = adults; } 1393 if (children && children !== pxContext.children) { pxContext.children = children; updated.children = children; } 1394 if (rooms && rooms !== pxContext.rooms) { pxContext.rooms = rooms; updated.rooms = rooms; } 1395 if (Object.keys(updated).length) { 1396 try { window.dataLayer.push(Object.assign({ event: 'px_context_update' }, updated)); } catch(e) {} 1397 } 1398 } 1399 1400 // Parse GroupsForm like "1:2,0,0;1:1,5.7,0" into {rooms, adults, children} 1401 function parseGroupsForm(gf) { 1402 var out = { rooms: 0, adults: 0, children: 0 };
1403 try { 1404 if (!gf) return out; 1405 String(gf).split(';').forEach(function(groupStr){ 1406 if (!groupStr) return; 1407 out.rooms += 1; 1408 var parts = groupStr.split(':'); 1409 if (parts.length < 2) return; 1410 var trio = parts[1].split(','); 1411 var a = parseInt(trio[0] || '0', 10); 1412 out.adults += isNaN(a) ? 0 : a; 1413 var childrenAges = (trio[1] || '0'); 1414 if (childrenAges && childrenAges !== '0') { 1415 out.children += childrenAges.split('.').filter(Boolean).length; 1416 } 1417 // Babies are not counted in children 1418 }); 1419 } catch (e) {} 1420 return out; 1421 } 1422 1423 // Enrich context from px_jsonQuery (server-rendered Json_Query) when available 1424 function enhanceContextFromPxJson() { 1425 try { 1426 var q = (typeof window !== 'undefined' && window.px_jsonQuery) ? window.px_jsonQuery : (typeof px_jsonQuery !== 'undefined' ? px_jsonQuery : null); 1427 if (!q) return; 1428 var updated = {}; 1429 // SearchID 1430 if (q.SearchID && String(q.SearchID) !== String(pxContext.search_id || '')) { 1431 pxContext.search_id = String(q.SearchID); 1432 updated.search_id = pxContext.search_id; 1433 } 1434 // Dates 1435 var start = normalizeDate(q.Start || ''); 1436 var end = normalizeDate(q.End || ''); 1437 if (start && start !== pxContext.start_date) { pxContext.start_date = start; updated.start_date = start; } 1438 if (end && end !== pxContext.end_date) { pxContext.end_date = end; updated.end_date = end; } 1439 // Pax/rooms from GroupsForm or Group array 1440 var paxParsed = null; 1441 if (q.GroupsForm) { 1442 paxParsed = parseGroupsForm(q.GroupsForm); 1443 } else if (q.Group && Array.isArray(q.Group)) { 1444 paxParsed = { rooms: 0, adults: 0, children: 0 }; 1445 q.Group.forEach(function(g){ 1446 paxParsed.rooms += 1; 1447 paxParsed.adults += (g.Adults*1) || 0; 1448 paxParsed.children += (g.Childs*1) || 0; 1449 }); 1450 } 1451 if (paxParsed) { 1452 if (paxParsed.adults && paxParsed.adults !== pxContext.adults) { pxContext.adults = paxParsed.adults; updated.adults = paxParsed.adults; } 1453 if (paxParsed.children && paxParsed.children !== pxContext.children) { pxContext.children = paxParsed.children; updated.children = paxParsed.children; } 1454 if (paxParsed.rooms && paxParsed.rooms !== pxContext.rooms) { pxContext.rooms = paxParsed.rooms; updated.rooms = paxParsed.rooms; } 1455 } 1456 if (Object.keys(updated).length) { 1457 try { window.dataLayer.push(Object.assign({ event: 'px_context_update' }, updated)); } catch(e) {} 1458 } 1459 } catch (e) {} 1460 } 1461 1462 // Process API payloads to enrich context 1463 function processApiData(url, data) { 1464 try { 1465 if (!data) return; 1466 // avoid reprocessing same SearchID repeatedly 1467 window.__px_processed_sids = window.__px_processed_sids || {}; 1468 var updated = {}; 1469 var payload = data && data.Json_Query ? data.Json_Query : data; 1470 // SearchID present? 1471 if (typeof payload.SearchID !== 'undefined' && String(payload.SearchID)) { 1472 var sid = String(payload.SearchID); 1473 if (window.__px_processed_sids[sid]) return; 1474 if (sid && sid !== String(pxContext.search_id || '')) { pxContext.search_id = sid; updated.search_id = sid; } 1475 window.__px_processed_sids[sid] = true; 1476 } 1477 // Start / End can exist either top-level or nested 1478 var start = payload.Start || (data && data.Start) || ''; 1479 var end = payload.End || (data && data.End) || ''; 1480 start = normalizeDate(start); 1481 end = normalizeDate(end); 1482 if (start && start !== pxContext.start_date) { pxContext.start_date = start; updated.start_date = start; } 1483 if (end && end !== pxContext.end_date) { pxContext.end_date = end; updated.end_date = end; } 1484 // GroupsForm could be present 1485 var gf = payload.GroupsForm || (data && data.GroupsForm) || ''; 1486 if (gf) { 1487 var parsed = parseGroupsForm(gf); 1488 if (parsed.adults && parsed.adults !== pxContext.adults) { pxContext.adults = parsed.adults; updated.adults = parsed.adults; } 1489 if (parsed.children && parsed.children !== pxContext.children) { pxContext.children = parsed.children; updated.children = parsed.children; } 1490 if (parsed.rooms && parsed.rooms !== pxContext.rooms) { pxContext.rooms = parsed.rooms; updated.rooms = parsed.rooms; } 1491 } 1492 // Some APIs include Group arrays; attempt totals 1493 if (payload.Group && Array.isArray(payload.Group)) { 1494 var aT = 0, cT = 0, rT = 0; 1495 payload.Group.forEach(function(g){ 1496 if (!g) return; 1497 rT += 1; 1498 aT += (g.Adults*1) || 0; 1499 cT += (g.Childs*1) || 0; 1500 }); 1501 if (aT && aT !== pxContext.adults) { pxContext.adults = aT; updated.adults = aT; } 1502 if (cT && cT !== pxContext.children) { pxContext.children = cT; updated.children = cT; } 1503 if (rT && rT !== pxContext.rooms) { pxContext.rooms = rT; updated.rooms = rT; } 1504 } 1505 if (Object.keys(updated).length) { 1506 try { window.dataLayer.push(Object.assign({ event: 'px_context_update' }, updated)); } catch(e) {} 1507 } 1508 } catch(e) {} 1509 } 1510 1511 // Intercept fetch/XHR to learn from API responses 1512 (function installNetworkTaps(){
1513 try { 1514 var origFetch = window.fetch; 1515 if (origFetch && !window.__px_fetch_hooked) { 1516 window.__px_fetch_hooked = true; 1517 window.fetch = function(input, init) { 1518 var p = origFetch(input, init); 1519 try { 1520 var url = typeof input === 'string' ? input : (input && input.url) || ''; 1521 p.then(function(res){ 1522 try { 1523 var ct = (res.headers && res.headers.get && res.headers.get('content-type')) || ''; 1524 if (ct && ct.indexOf('application/json') !== -1 && (/\/query\/list/i.test(url) || /\/search\/info/i.test(url))) { 1525 res.clone().json().then(function(json){ processApiData(url, json); }).catch(function(){}); 1526 } 1527 } catch(e) {} 1528 }).catch(function(){}); 1529 } catch(e) {} 1530 return p; 1531 }; 1532 } 1533 } catch(e) {} 1534 try { 1535 if (!window.__px_xhr_hooked && window.XMLHttpRequest) { 1536 window.__px_xhr_hooked = true; 1537 var XHR = window.XMLHttpRequest; 1538 var open = XHR.prototype.open; 1539 var send = XHR.prototype.send; 1540 XHR.prototype.open = function(method, url) { 1541 this.__px_url = url; 1542 return open.apply(this, arguments); 1543 }; 1544 XHR.prototype.send = function(body) { 1545 try { 1546 this.addEventListener('load', function() { 1547 try { 1548 var url = this.__px_url || ''; 1549 var ct = this.getResponseHeader && this.getResponseHeader('content-type') || ''; 1550 if (ct && ct.indexOf('application/json') !== -1 && (/\/query\/list/i.test(url) || /\/search\/info/i.test(url))) { 1551 var txt = this.responseText; 1552 try { processApiData(url, JSON.parse(txt)); } catch(e) {} 1553 } 1554 } catch(e) {} 1555 }); 1556 } catch(e) {} 1557 return send.apply(this, arguments); 1558 }; 1559 } 1560 } catch(e) {} 1561 })(); 1562 1563 // If we have SearchID but missing details, fetch /search/info 1564 function fetchSearchInfoIfNeeded() { 1565 try { 1566 var sid = pxContext.search_id || getUrlParam('SearchID') || (document.querySelector('#SearchID')||{}).value || ''; 1567 var needsDates = !(pxContext.start_date && pxContext.end_date); 1568 var needsPaxs = !((pxContext.adults*1) > 0 || (pxContext.children*1) > 0); 1569 if (sid && (needsDates || needsPaxs)) { 1570 fetchSearchInfoForSid(sid); 1571 } 1572 } catch(e) {} 1573 } 1574 1575 // Cached fetch per SearchID 1576 function fetchSearchInfoForSid(sid) { 1577 try { 1578 window.__px_sid_promises = window.__px_sid_promises || {}; 1579 if (window.__px_sid_promises[sid]) return window.__px_sid_promises[sid]; 1580 var endpoint = 'https://api-1-eb-web.pxsol.io/search/info?SearchID=' + encodeURIComponent(sid); 1581 var pr = fetch(endpoint, { credentials: 'omit' }).then(function(res){ 1582 if (!res.ok) return; 1583 var ct = (res.headers && res.headers.get && res.headers.get('content-type')) || ''; 1584 if (ct.indexOf('application/json') === -1) return; 1585 return res.json(); 1586 }).then(function(json){ 1587 if (json) processApiData(endpoint, json); 1588 return true; 1589 }).catch(function(){ return false; }); 1590 window.__px_sid_promises[sid] = pr; 1591 return pr; 1592 } catch(e) { return Promise.resolve(false); } 1593 } 1594 1595 // Ensure dates/paxs are ready before firing a callback 1596 function ensureContextReady(cb) { 1597 try { 1598 // Try quick enrichments first 1599 enhanceContextFromHiddenInputs(); 1600 enhanceContextFromPxJson(); 1601 var sid = pxContext.search_id || getUrlParam('SearchID') || (document.querySelector('#SearchID')||{}).value || ''; 1602 var hasDates = !!(pxContext.start_date && pxContext.end_date); 1603 var hasPaxs = ((pxContext.adults*1) > 0) || ((pxContext.children*1) > 0); 1604 if (hasDates && hasPaxs) { cb(); return; } 1605 if (sid) { 1606 fetchSearchInfoForSid(sid).finally(function(){ cb(); }); 1607 return; 1608 } 1609 // Last resort: try to enrich from DOM then run
1610 enhanceContextFromHiddenInputs(); 1611 cb(); 1612 } catch(e) { cb(); } 1613 } 1614 1615 // Detect "No hay resultados" to push no_inventory automatically 1616 function wireNoInventoryWatcher() { 1617 console.log('%c[pxTrack] ð Initializing no_inventory watcher...', 'color: #2196F3; font-weight: bold; font-size: 14px;'); 1618 console.log('[pxTrack] wireNoInventoryWatcher() called at:', new Date().toISOString()); 1619 var scanCount = 0; 1620 var lastScanResult = null; 1621 var lastSearchID = null; // Track SearchID to detect new searches 1622 var lastScanTime = 0; // For throttling scans 1623 var SCAN_THROTTLE_MS = 1000; // Maximum 1 scan per second 1624 var EVENT_COOLDOWN_MS = 5000; // Minimum 5 seconds between events of the same type 1625 var lastEventTime = {}; // Track last time each event type was fired 1626 var MAX_SCANS_PER_SEARCH = 30; // Maximum scans per search to prevent excessive polling 1627 var __px_has_inventory_pushed = false; // Flag para has_inventory (opuesto de no_inventory) 1628 1629 // Log immediately to confirm function is executing 1630 console.log('[pxTrack] â wireNoInventoryWatcher() is executing - scan function will be defined'); 1631 1632 // Expose scan function to global manual trigger 1633 window.__px_no_inventory_scan_func = function() { 1634 console.log('[pxTrack] Manual scan triggered via global function'); 1635 scan(); 1636 return lastScanResult; 1637 }; 1638 1639 function checkJsonQueryAvailability() { 1640 try { 1641 // Check if px_jsonQuery is available 1642 if (typeof window.px_jsonQuery === 'undefined' || !window.px_jsonQuery) { 1643 return false; 1644 } 1645 1646 var jsonQuery = window.px_jsonQuery; 1647 1648 // Log full structure on first check (for debugging) 1649 if (!window.__px_jsonQuery_logged) { 1650 window.__px_jsonQuery_logged = true; 1651 try { 1652 console.log('[pxTrack] ð¦ px_jsonQuery structure detected:', { 1653 hasProductList: !!(jsonQuery.ProductList), 1654 productListIsArray: Array.isArray(jsonQuery.ProductList), 1655 productListLength: jsonQuery.ProductList ? jsonQuery.ProductList.length : 0, 1656 sampleProduct: jsonQuery.ProductList && jsonQuery.ProductList.length > 0 ? { 1657 hasAvailability: typeof jsonQuery.ProductList[0].Availability !== 'undefined', 1658 availability: jsonQuery.ProductList[0].Availability, 1659 hasSkuList: !!(jsonQuery.ProductList[0].SkuList), 1660 skuListLength: jsonQuery.ProductList[0].SkuList ? jsonQuery.ProductList[0].SkuList.length : 0 1661 } : null 1662 }); 1663 // Log first product details if available 1664 if (jsonQuery.ProductList && jsonQuery.ProductList.length > 0) { 1665 var firstProduct = jsonQuery.ProductList[0]; 1666 console.log('[pxTrack] First product sample:', { 1667 Availability: firstProduct.Availability, 1668 hasSkuList: !!(firstProduct.SkuList), 1669 SkuList: firstProduct.SkuList ? firstProduct.SkuList.map(function(sku) { 1670 return { Availability: sku.Availability }; 1671 }).slice(0, 3) : null 1672 }); 1673 } 1674 } catch(e) { 1675 console.error('[pxTrack] Error logging Json_Query structure:', e); 1676 } 1677 } 1678 1679 // Check if ProductList exists and is an array 1680 if (!jsonQuery.ProductList) { 1681 // ProductList might not be loaded yet, but object exists 1682 return false; 1683 } 1684 1685 if (!Array.isArray(jsonQuery.ProductList)) { 1686 console.warn('[pxTrack] px_jsonQuery.ProductList exists but is not an array:', typeof jsonQuery.ProductList); 1687 return false; 1688 } 1689 1690 if (jsonQuery.ProductList.length === 0) { 1691 // Empty ProductList might indicate no inventory, but we need at least one product to check 1692 return false; 1693 } 1694 1695 // Check if ALL products have Availability === 0 1696 var allZeroAvailability = true; 1697 var availabilityDetails = []; 1698 1699 for (var i = 0; i < jsonQuery.ProductList.length; i++) { 1700 var product = jsonQuery.ProductList[i]; 1701 // Check Availability property (could be at product level or in SkuList) 1702 var productAvailability = product.Availability || 0; 1703 var productHasAvailability = typeof product.Availability !== 'undefined'; 1704 1705 // If product has SkuList, check all SKUs 1706 if (product.SkuList && Array.isArray(product.SkuList) && product.SkuList.length > 0) { 1707 var allSkusZero = true; 1708 var skuAvailabilities = []; 1709 for (var j = 0; j < product.SkuList.length; j++) { 1710 var sku = product.SkuList[j]; 1711 var skuAvail = sku.Availability || 0; 1712 skuAvailabilities.push(skuAvail); 1713 if (sku.Availability && sku.Availability > 0) { 1714 allSkusZero = false;
1715 break; 1716 } 1717 } 1718 availabilityDetails.push({ 1719 productIndex: i, 1720 hasProductAvailability: productHasAvailability, 1721 productAvailability: productAvailability, 1722 hasSkuList: true, 1723 skuAvailabilities: skuAvailabilities, 1724 allSkusZero: allSkusZero 1725 }); 1726 if (!allSkusZero) { 1727 allZeroAvailability = false; 1728 break; 1729 } 1730 } else { 1731 // Product-level availability check 1732 availabilityDetails.push({ 1733 productIndex: i, 1734 hasProductAvailability: productHasAvailability, 1735 productAvailability: productAvailability, 1736 hasSkuList: false 1737 }); 1738 if (productAvailability > 0) { 1739 allZeroAvailability = false; 1740 break; 1741 } 1742 } 1743 } 1744 1745 // Log availability details when checking (first time or when all zero) 1746 if (allZeroAvailability || !window.__px_availability_details_logged) { 1747 window.__px_availability_details_logged = true; 1748 console.log('[pxTrack] Availability check result:', { 1749 allZeroAvailability: allZeroAvailability, 1750 totalProducts: jsonQuery.ProductList.length, 1751 details: availabilityDetails.slice(0, 3) // Show first 3 products 1752 }); 1753 } 1754 1755 return allZeroAvailability; 1756 } catch(e) { 1757 console.error('[pxTrack] Error checking Json_Query availability:', e); 1758 return false; 1759 } 1760 } 1761 1762 function checkJsonQueryHasAvailability() { 1763 try { 1764 // Check if px_jsonQuery is available 1765 if (typeof window.px_jsonQuery === 'undefined' || !window.px_jsonQuery) { 1766 return { hasAvailability: false, totalAvailability: 0, availabilityDetails: null }; 1767 } 1768 1769 var jsonQuery = window.px_jsonQuery; 1770 1771 // Check if ProductList exists and is an array 1772 if (!jsonQuery.ProductList || !Array.isArray(jsonQuery.ProductList) || jsonQuery.ProductList.length === 0) { 1773 return { hasAvailability: false, totalAvailability: 0, availabilityDetails: null }; 1774 } 1775 1776 var totalAvailability = 0; 1777 var hasAnyAvailability = false; 1778 var availabilityDetails = []; 1779 1780 for (var i = 0; i < jsonQuery.ProductList.length; i++) { 1781 var product = jsonQuery.ProductList[i]; 1782 var productAvailability = product.Availability || 0; 1783 var productTotal = 0; 1784 1785 // If product has SkuList, sum all SKU availabilities 1786 if (product.SkuList && Array.isArray(product.SkuList) && product.SkuList.length > 0) { 1787 for (var j = 0; j < product.SkuList.length; j++) { 1788 var sku = product.SkuList[j]; 1789 var skuAvail = sku.Availability || 0; 1790 productTotal += skuAvail; 1791 if (skuAvail > 0) { 1792 hasAnyAvailability = true; 1793 } 1794 } 1795 } else { 1796 // Product-level availability 1797 productTotal = productAvailability; 1798 if (productAvailability > 0) { 1799 hasAnyAvailability = true; 1800 } 1801 } 1802 1803 totalAvailability += productTotal; 1804 availabilityDetails.push({ 1805 productIndex: i, 1806 productAvailability: productAvailability, 1807 productTotal: productTotal, 1808 hasSkuList: !!(product.SkuList && Array.isArray(product.SkuList) && product.SkuList.length > 0) 1809 }); 1810 } 1811 1812 return { 1813 hasAvailability: hasAnyAvailability, 1814 totalAvailability: totalAvailability, 1815 availabilityDetails: availabilityDetails, 1816 productCount: jsonQuery.ProductList.length 1817 }; 1818 } catch(e) { 1819 console.error('[pxTrack] Error checking Json_Query for availability:', e); 1820 return { hasAvailability: false, totalAvailability: 0, availabilityDetails: null }; 1821 } 1822 } 1823 1824 function scan() { 1825 // THROTTLING: Evitar escaneos muy frecuentes 1826 var now = Date.now(); 1827 if (now - lastScanTime < SCAN_THROTTLE_MS) { 1828 console.debug('[pxTrack] scan() throttled (too soon after last scan)'); 1829 return; 1830 } 1831 lastScanTime = now; 1832 1833 // Check if SearchID changed (new search) - if so, reset the flag 1834 try { 1835 var currentSearchID = null; 1836 if (typeof window.px_jsonQuery !== 'undefined' && window.px_jsonQuery && window.px_jsonQuery.SearchID) { 1837 currentSearchID = String(window.px_jsonQuery.SearchID); 1838 } else { 1839 var searchIDEl = document.querySelector('#SearchID'); 1840 if (searchIDEl && searchIDEl.value) { 1841 currentSearchID = String(searchIDEl.value); 1842 } else { 1843 try {
1844 var urlParams = new URLSearchParams(location.search); 1845 currentSearchID = urlParams.get('SearchID') || null; 1846 } catch(e) {} 1847 } 1848 } 1849 1850 // If SearchID changed, reset the flags for new search 1851 if (currentSearchID && currentSearchID !== lastSearchID && lastSearchID !== null) { 1852 console.log('[pxTrack] ð New search detected (SearchID: ' + lastSearchID + ' â ' + currentSearchID + '), resetting flags'); 1853 window.__px_no_inventory_pushed = false; 1854 __px_has_inventory_pushed = false; 1855 scanCount = 0; // Reset scan count 1856 lastScanTime = 0; // Reset throttling for new search 1857 } 1858 1859 // Update lastSearchID 1860 if (currentSearchID) { 1861 lastSearchID = currentSearchID; 1862 } 1863 } catch(e) { 1864 console.error('[pxTrack] Error checking SearchID:', e); 1865 } 1866 1867 // Don't scan if event already fired (unless we just reset it) 1868 if (window.__px_no_inventory_pushed) { 1869 console.debug('[pxTrack] scan() called but event already fired, skipping'); 1870 return; 1871 } 1872 1873 // LÃmite máximo de escaneos por búsqueda 1874 if (scanCount >= MAX_SCANS_PER_SEARCH) { 1875 console.debug('[pxTrack] scan() skipped - maximum scans per search reached (' + MAX_SCANS_PER_SEARCH + ')'); 1876 return; 1877 } 1878 1879 scanCount++; 1880 // Log first few scans to confirm function is working 1881 if (scanCount <= 5) { 1882 console.log('[pxTrack] scan() executing - Scan #' + scanCount); 1883 } 1884 var shouldFire = false; 1885 var detectionMethod = ''; 1886 var debugInfo = { 1887 scanNumber: scanCount, 1888 px_jsonQuery_exists: typeof window.px_jsonQuery !== 'undefined' && !!window.px_jsonQuery, 1889 productList_length: 0, 1890 productList_details: [] 1891 }; 1892 1893 // Method 1: Check px_jsonQuery.ProductList for all Availability === 0 1894 try { 1895 if (typeof window.px_jsonQuery !== 'undefined' && window.px_jsonQuery) { 1896 debugInfo.productList_length = (window.px_jsonQuery.ProductList && Array.isArray(window.px_jsonQuery.ProductList)) ? window.px_jsonQuery.ProductList.length : 0; 1897 1898 if (checkJsonQueryAvailability()) { 1899 shouldFire = true; 1900 detectionMethod = 'Json_Query'; 1901 try { 1902 console.log('%c[pxTrack] â no_inventory DETECTED via Json_Query (all Availability === 0) - Scan #' + scanCount, 'color: #FF5722; font-weight: bold;'); 1903 } catch(_e){} 1904 } else { 1905 // Log details about why it didn't fire 1906 try { 1907 if (window.px_jsonQuery.ProductList && Array.isArray(window.px_jsonQuery.ProductList)) { 1908 var productDetails = []; 1909 for (var idx = 0; idx < Math.min(window.px_jsonQuery.ProductList.length, 3); idx++) { 1910 var p = window.px_jsonQuery.ProductList[idx]; 1911 var prodAvail = p.Availability || 0; 1912 var skuAvail = 'N/A'; 1913 if (p.SkuList && Array.isArray(p.SkuList) && p.SkuList.length > 0) { 1914 var skuAvails = []; 1915 for (var skuIdx = 0; skuIdx < p.SkuList.length; skuIdx++) { 1916 skuAvails.push(p.SkuList[skuIdx].Availability || 0); 1917 } 1918 skuAvail = skuAvails.join(','); 1919 } 1920 productDetails.push({productAvail: prodAvail, skuAvail: skuAvail}); 1921 } 1922 debugInfo.productList_details = productDetails; 1923 } 1924 } catch(e) {} 1925 } 1926 } 1927 } catch(e) { 1928 console.error('[pxTrack] Error in Json_Query availability check:', e); 1929 } 1930 1931 // Method 2: Check for specific DOM elements (most reliable) 1932 if (!shouldFire) { 1933 try { 1934 // Check for #no-inventory-container or #no-inventory (from sindispo.php) 1935 var noInventoryContainer = document.querySelector('#no-inventory-container'); 1936 var noInventoryElement = document.querySelector('#no-inventory'); 1937 if (noInventoryContainer || noInventoryElement) { 1938 shouldFire = true; 1939 detectionMethod = 'DOM element (ID)'; 1940 try { 1941 console.log('%c[pxTrack] â no_inventory DETECTED via DOM element (#no-inventory-container or #no-inventory) - Scan #' + scanCount, 'color: #FF5722; font-weight: bold;'); 1942 console.log('[pxTrack] DOM elements found:', { 1943 hasContainer: !!noInventoryContainer, 1944 hasElement: !!noInventoryElement, 1945 containerVisible: noInventoryContainer ? (noInventoryContainer.offsetParent !== null) : false, 1946 elementText: noInventoryElement ? (noInventoryElement.textContent || noInventoryElement.innerText || '').substring(0, 50) : '' 1947 }); 1948 } catch(_e){} 1949 } else if (scanCount <= 3 || scanCount % 10 === 0) { 1950 // Log when elements are not found (for debugging) 1951 try { 1952 console.debug('[pxTrack] DOM check: #no-inventory-container and #no-inventory not found (scan #' + scanCount + ')'); 1953 } catch(_e){} 1954 } 1955 } catch(e) { 1956 console.error('[pxTrack] Error in DOM element check:', e); 1957 } 1958 } 1959 1960 // Method 3: Fallback - Check DOM text for "No hay resultados" or "No results" 1961 if (!shouldFire) { 1962 try { 1963 var candidates = Array.prototype.slice.call(document.querySelectorAll('body *')); 1964 for (var i=0; i<candidates.length; i++) { 1965 var t = (candidates[i].innerText || '').trim(); 1966 if (!t) continue; 1967 if (t.indexOf('No hay resultados') !== -1 || t.indexOf('No results') !== -1) { 1968 shouldFire = true; 1969 detectionMethod = 'DOM text'; 1970 try { 1971 console.log('%c[pxTrack] â no_inventory DETECTED via DOM text - Scan #' + scanCount, 'color: #FF5722; font-weight: bold;'); 1972 } catch(_e){} 1973 break; 1974 } 1975 } 1976 } catch(e) { 1977 console.error('[pxTrack] Error in DOM text check:', e); 1978 } 1979 } 1980 1981 // Store last scan result for debugging 1982 lastScanResult = { 1983 shouldFire: shouldFire, 1984 method: detectionMethod, 1985 scanCount: scanCount, 1986 px_jsonQuery_exists: debugInfo.px_jsonQuery_exists, 1987 productList_length: debugInfo.productList_length, 1988 productList_details: debugInfo.productList_details 1989 }; 1990 1991 // Log scan details every 5th scan or when px_jsonQuery becomes available 1992 if (scanCount % 5 === 0 || (debugInfo.px_jsonQuery_exists && scanCount <= 3)) { 1993 try { 1994 console.log('[pxTrack] no_inventory scan #' + scanCount + ':', { 1995 px_jsonQuery_exists: debugInfo.px_jsonQuery_exists, 1996 productList_length: debugInfo.productList_length, 1997 shouldFire: shouldFire, 1998 method: detectionMethod 1999 }); 2000 if (debugInfo.productList_details.length > 0) { 2001 console.log('[pxTrack] Sample product availability:', debugInfo.productList_details); 2002 } 2003 } catch(_e){} 2004 } 2005 2006 if (shouldFire && !window.__px_no_inventory_pushed) { 2007 // COOLDOWN: Verificar que no se haya disparado recientemente 2008 var eventType = 'no_inventory'; 2009 var now = Date.now(); 2010 if (lastEventTime[eventType] && (now - lastEventTime[eventType] < EVENT_COOLDOWN_MS)) { 2011 console.log('[pxTrack] â¸ï¸ Event cooldown active, skipping no_inventory event (last fired ' + Math.round((now - lastEventTime[eventType]) / 1000) + 's ago)'); 2012 return; 2013 } 2014 2015 window.__px_no_inventory_pushed = true; 2016 lastEventTime[eventType] = now; // Registrar tiempo del evento 2017 2018 // Ensure dates/paxs are enriched before sending 2019 ensureContextReady(function(){ 2020 var params = getSearchParamsFromDOM(); 2021 params.no_inventory = true; 2022 try { 2023 console.log('%c[pxTrack] ð FIRING no_inventory event - Detection method: ' + detectionMethod + ' - Scan #' + scanCount, 'color: #4CAF50; font-weight: bold; font-size: 14px;'); 2024 console.log('[pxTrack] no_inventory payload:', params); 2025 console.log('[pxTrack] Last scan result:', lastScanResult); 2026 } catch(_e){} 2027 window.pxTrack('no_inventory', params); 2028 2029 // Fire form_success for search form after no_inventory 2030 setTimeout(function() { 2031 console.log('%c[pxTrack] ð FIRING form_success for search form (after no_inventory)', 'color: #4CAF50; font-weight: bold;'); 2032 window.pxTrack('form_success', { 2033 form_id: 'pxmk_searchform', 2034 lead_id: null, 2035 transaction_id: null 2036 }); 2037 }, 100); 2038 }); 2039 } 2040 2041 // OPPOSITE: Check if there IS availability (has_inventory) 2042 // Only check if no_inventory was NOT detected and has_inventory hasn't been fired yet 2043 if (!shouldFire && !__px_has_inventory_pushed && !window.__px_no_inventory_pushed) { 2044 try { 2045 // Also verify that no "no inventory" DOM elements are present 2046 var noInventoryContainer = document.querySelector('#no-inventory-container'); 2047 var noInventoryElement = document.querySelector('#no-inventory'); 2048 var hasNoInventoryDOM = !!(noInventoryContainer || noInventoryElement); 2049 2050 if (hasNoInventoryDOM) { 2051 console.debug('[pxTrack] has_inventory blocked - no inventory DOM elements present'); 2052 } else { 2053 var availabilityInfo = checkJsonQueryHasAvailability(); 2054 2055 if (availabilityInfo.hasAvailability) { 2056 // COOLDOWN: Verificar que no se haya disparado recientemente 2057 var eventType = 'has_inventory'; 2058 var now = Date.now(); 2059 if (lastEventTime[eventType] && (now - lastEventTime[eventType] < EVENT_COOLDOWN_MS)) { 2060 console.log('[pxTrack] â¸ï¸ Event cooldown active, skipping has_inventory event (last fired ' + Math.round((now - lastEventTime[eventType]) / 1000) + 's ago)'); 2061 } else { 2062 2063 __px_has_inventory_pushed = true; 2064 lastEventTime[eventType] = now; 2065 2066 // Ensure dates/paxs are enriched before sending 2067 ensureContextReady(function(){ 2068 var params = getSearchParamsFromDOM(); 2069 params.has_availability = true; 2070 params.availability = availabilityInfo.totalAvailability; 2071 params.product_count = availabilityInfo.productC
2071ount || 0; 2072 2073 // Add SearchID if available 2074 try { 2075 if (typeof window.px_jsonQuery !== 'undefined' && window.px_jsonQuery && window.px_jsonQuery.SearchID) { 2076 params.search_id = String(window.px_jsonQuery.SearchID); 2077 } 2078 } catch(e) {} 2079 2080 // Add availability details (first 3 products for debugging) 2081 if (availabilityInfo.availabilityDetails && availabilityInfo.availabilityDetails.length > 0) { 2082 params.availability_details = availabilityInfo.availabilityDetails.slice(0, 3).map(function(detail) { 2083 return { 2084 product_index: detail.productIndex, 2085 availability: detail.productTotal, 2086 has_skus: detail.hasSkuList 2087 }; 2088 }); 2089 } 2090 2091 try { 2092 console.log('%c[pxTrack] ð FIRING has_inventory event (availability detected) - Scan #' + scanCount, 'color: #4CAF50; font-weight: bold; font-size: 14px;'); 2093 console.log('[pxTrack] has_inventory payload:', params); 2094 console.log('[pxTrack] Availability info:', { 2095 totalAvailability: availabilityInfo.totalAvailability, 2096 productCount: availabilityInfo.productCount, 2097 hasAvailability: availabilityInfo.hasAvailability 2098 }); 2099 } catch(_e){} 2100 window.pxTrack('has_inventory', params); 2101 2102 // Fire form_success for search form after has_inventory 2103 setTimeout(function() { 2104 console.log('%c[pxTrack] ð FIRING form_success for search form (after has_inventory)', 'color: #4CAF50; font-weight: bold;'); 2105 window.pxTrack('form_success', { 2106 form_id: 'pxmk_searchform', 2107 lead_id: null, 2108 transaction_id: null 2109 }); 2110 }, 100); 2111 }); 2112 } 2113 } 2114 } 2115 } catch(e) { 2116 console.error('[pxTrack] Error checking for availability (has_inventory):', e); 2117 } 2118 } 2119 } 2120 2121 // Try to intercept px_jsonQuery assignment (works if px_jsonQuery is undefined) 2122 try { 2123 if (typeof window.px_jsonQuery === 'undefined') { 2124 try { 2125 var _px_jsonQuery_value = undefined; 2126 var _px_jsonQuery_lastTrigger = 0; 2127 Object.defineProperty(window, 'px_jsonQuery', { 2128 get: function() { return _px_jsonQuery_value; }, 2129 set: function(newValue) { 2130 _px_jsonQuery_value = newValue; 2131 if (newValue) { 2132 try { 2133 // Throttle interceptor triggers (máximo 1 cada 1 segundo) 2134 var now = Date.now(); 2135 if (now - _px_jsonQuery_lastTrigger < 1000) { 2136 console.debug('[pxTrack] px_jsonQuery interceptor throttled'); 2137 return; 2138 } 2139 _px_jsonQuery_lastTrigger = now; 2140 console.log('[pxTrack] px_jsonQuery was set via Object.defineProperty, triggering scan'); 2141 setTimeout(function() { scan(); }, 150); 2142 } catch(e) { 2143 console.error('[pxTrack] Error in triggerScan:', e); 2144 } 2145 } 2146 }, 2147 configurable: true, 2148 enumerable: true 2149 }); 2150 } catch(e) { 2151 console.error('[pxTrack] Object.defineProperty failed for px_jsonQuery:', e); 2152 } 2153 } 2154 } catch(e) { 2155 console.error('[pxTrack] Error setting up px_jsonQuery interception:', e); 2156 } 2157 2158 // Multiple initial scans with increasing delays (for Chrome compatibility) 2159 function runInitialScans() { 2160 console.log('%c[pxTrack] Starting initial scans for no_inventory detection...', 'color: #FF9800; font-weight: bold;'); 2161 console.log('[pxTrack] runInitialScans() called - will execute multiple scans'); 2162 // Immediate scan 2163 console.log('[pxTrack] Executing immediate scan...'); 2164 scan(); 2165 // Delayed scans to catch px_jsonQuery if it loads later AND DOM elements that load dynamically 2166 setTimeout(function() { scan(); }, 200); 2167 setTimeout(function() { scan(); }, 500); 2168 setTimeout(function() { scan(); }, 1000); 2169 setTimeout(function() { scan(); }, 2000); 2170 setTimeout(function() { scan(); }, 3000); 2171 setTimeout(function() { scan(); }, 5000); 2172 } 2173 2174 // Run initial scans after DOM is ready 2175 if (document.readyState === 'loading') { 2176 console.log('[pxTrack] DOM is loading, will wait for DOMContentLoaded'); 2177 document.addEventListener('DOMContentLoaded', function() { 2178 console.log('[pxTrack] DOMContentLoaded fired, scheduling runInitialScans() in 100ms'); 2179 setTimeout(function() { 2180 console.log('[pxTrack] Executing runInitialScans() now...'); 2181 runInitialScans(); 2182 }, 100); 2183 }); 2184 } else { 2185 console.log('[pxTrack] DOM already ready, scheduling runInitialScans() in 100ms'); 2186 setTimeout(function() { 2187 console.log('[pxTrack] Executing runInitialScans() now...'); 2188 runInitialScans(); 2189 }, 100); 2190 } 2191 2192 // Also use requestAnimationFrame for Chrome (ensures DOM is painted) 2193 if (window.requestAnimationFrame) { 2194 requestAnimationFrame(function() { 2195 setTimeout(function() { scan(); }, 500); 2196 }); 2197 } 2198 2199 // Watch for px_jsonQuery availability (reduced polling frequency to prevent rate limiting) 2200 var jsonQueryCheckStart = Date.now(); 2201 var jsonQueryCheckTimeout = 20000; // 20 seconds 2202 var jsonQueryCheckInterval = setInterval(function() { 2203 // Stop if timeout reached 2204 if (Date.now() - jsonQueryCheckStart > jsonQueryCheckTimeout) { 2205 clearInterval(jsonQueryCheckInterval); 2206 try { 2207 console.log('[pxTrack] no_inventory px_jsonQuery polling timed out after', scanCount, 'scans'); 2208 console.log('[pxTrack] Last scan result:', lastScanResult); 2209 } catch(_e){} 2210 return; 2211 } 2212 2213 // Stop if event already fired 2214 if (window.__px_no_inventory_pushed) { 2215 clearInterval(jsonQueryCheckInterval); 2216 return; 2217 } 2218 2219 // Check if px_jsonQuery is now available and scan 2220 if (typeof window.px_jsonQuery !== 'undefined' && window.px_jsonQuery) { 2221 scan(); 2222 } 2223 }, 1000); // Reduced to 1 second to prevent rate limiting 2224 2225 // Watch DOM changes and specifically look for #no-inventory-container or #no-inventory
2226 try { 2227 var mo = new MutationObserver(function(mutations) { 2228 if (window.__px_no_inventory_pushed) return; 2229 2230 // Throttling más agresivo para MutationObserver (2 segundos mÃnimo) 2231 var now = Date.now(); 2232 if (mo.__px_lastScan && (now - mo.__px_lastScan < 2000)) { 2233 return; 2234 } 2235 2236 // Check if any of the mutations added our target elements 2237 var foundTarget = false; 2238 for (var i = 0; i < mutations.length; i++) { 2239 var mutation = mutations[i]; 2240 if (mutation.addedNodes && mutation.addedNodes.length > 0) { 2241 for (var j = 0; j < mutation.addedNodes.length; j++) { 2242 var node = mutation.addedNodes[j]; 2243 if (node.nodeType === 1) { // Element node 2244 // Check if the added node is our target or contains it 2245 if (node.id === 'no-inventory-container' || node.id === 'no-inventory' || 2246 node.querySelector && (node.querySelector('#no-inventory-container') || node.querySelector('#no-inventory'))) { 2247 foundTarget = true; 2248 break; 2249 } 2250 } 2251 } 2252 } 2253 if (foundTarget) break; 2254 } 2255 2256 // If target found or if enough time passed, scan 2257 if (foundTarget || !mo.__px_lastScan || Date.now() - mo.__px_lastScan > 2000) { 2258 mo.__px_lastScan = Date.now(); 2259 if (foundTarget) { 2260 console.log('[pxTrack] MutationObserver detected #no-inventory-container or #no-inventory added to DOM'); 2261 } 2262 scan(); 2263 } 2264 }); 2265 mo.observe(document.body, { childList: true, subtree: true }); 2266 } catch(e) { 2267 console.error('[pxTrack] MutationObserver failed for no_inventory:', e); 2268 } 2269 2270 // Additional polling specifically for DOM elements (reduced frequency to prevent rate limiting) 2271 var domPollingStart = Date.now(); 2272 var domPollingTimeout = 15000; // 15 seconds 2273 var domPollingInterval = setInterval(function() { 2274 if (Date.now() - domPollingStart > domPollingTimeout) { 2275 clearInterval(domPollingInterval); 2276 return; 2277 } 2278 2279 if (window.__px_no_inventory_pushed) { 2280 clearInterval(domPollingInterval); 2281 return; 2282 } 2283 2284 // Quick check for target elements 2285 var noInventoryContainer = document.querySelector('#no-inventory-container'); 2286 var noInventoryElement = document.querySelector('#no-inventory'); 2287 if (noInventoryContainer || noInventoryElement) { 2288 console.log('[pxTrack] DOM polling detected #no-inventory-container or #no-inventory'); 2289 scan(); 2290 clearInterval(domPollingInterval); 2291 } 2292 }, 1000); // Reduced to 1 second to prevent rate limiting 2293 2294 // Confirm watcher is fully initialized 2295 console.log('%c[pxTrack] â no_inventory watcher fully initialized and ready', 'color: #4CAF50; font-weight: bold; font-size: 14px;'); 2296 console.log('[pxTrack] wireNoInventoryWatcher() completed at:', new Date().toISOString()); 2297 console.log('[pxTrack] All watchers, observers, and polling intervals are now active'); 2298 } 2299 2300 // Observe availability containers to re-enrich context after dynamic updates 2301 function observeAvailabilityContainers() { 2302 try { 2303 var targets = []; 2304 var el1 = document.querySelector('#neo_cart_results_list'); 2305 var el2 = document.querySelector('#neo_cart_pedido_container'); 2306 if (el1) targets.push(el1); 2307 if (el2) targets.push(el2); 2308 if (!targets.length || !('MutationObserver' in window)) return; 2309 var refresh = function() { 2310 enhanceContextFromHiddenInputs(); 2311 enhanceContextFromPxJson(); 2312 }; 2313 var mo = new MutationObserver(function(muts) { 2314 // throttle bursts 2315 if (mo.__px_scheduled) return; 2316 mo.__px_scheduled = true;
2317 setTimeout(function(){ mo.__px_scheduled = false; refresh(); }, 100); 2318 }); 2319 targets.forEach(function(t){ mo.observe(t, { childList: true, subtree: true }); }); 2320 // initial pass 2321 refresh(); 2322 } catch (e) {} 2323 } 2324 2325 // Init after DOM ready - LOG EARLY AND OFTEN 2326 console.log('%c[pxTrack] STEP 1: Checking DOM readyState...', 'color: #9C27B0; font-weight: bold; font-size: 14px;'); 2327 console.log('[pxTrack] document.readyState:', document.readyState); 2328 console.log('[pxTrack] wireNoInventoryWatcher function exists:', typeof wireNoInventoryWatcher); 2329 2330 if (document.readyState === 'loading') { 2331 console.log('%c[pxTrack] STEP 2: DOM is loading, setting up DOMContentLoaded listener', 'color: #9C27B0; font-weight: bold;'); 2332 document.addEventListener('DOMContentLoaded', function() { 2333 console.log('%c[pxTrack] STEP 3: DOMContentLoaded fired!', 'color: #9C27B0; font-weight: bold; font-size: 16px;'); 2334 console.log('[pxTrack] DOMContentLoaded fired, initializing watchers...'); 2335 try { 2336 wireSearchFallbacks(); 2337 wireSearchEventsWhenReady(); 2338 wireFormEvents(); 2339 wireWhatsappClick(); 2340 if (typeof wireCheckoutForm === 'function') { 2341 wireCheckoutForm(); 2342 } else { 2343 console.log('[pxTrack] wireCheckoutForm() not available (may be conditional)'); 2344 } 2345 wireDatePickers(); 2346 enhanceContextFromHiddenInputs(); 2347 enhanceContextFromPxJson(); 2348 fetchSearchInfoIfNeeded(); 2349 console.log('%c[pxTrack] STEP 4: About to call wireNoInventoryWatcher()...', 'color: #FF5722; font-weight: bold; font-size: 16px;'); 2350 try { 2351 wireNoInventoryWatcher(); 2352 console.log('%c[pxTrack] STEP 5: wireNoInventoryWatcher() completed successfully!', 'color: #4CAF50; font-weight: bold; font-size: 16px;'); 2353 } catch(e) { 2354 console.error('[pxTrack] ERROR calling wireNoInventoryWatcher():', e); 2355 console.error('[pxTrack] Error stack:', e.stack); 2356 } 2357 observeAvailabilityContainers(); 2358 // delayed retries in case modules/scripts load late 2359 setTimeout(function(){ enhanceContextFromHiddenInputs(); enhanceContextFromPxJson(); }, 500); 2360 setTimeout(function(){ enhanceContextFromHiddenInputs(); enhanceContextFromPxJson(); }, 1500); 2361 // checkout success detector (thank-you page) - multiple attempts with delays 2362 if (typeof maybePushFormSuccess === 'function') { 2363 maybePushFormSuccess(); // Immediate 2364 setTimeout(function(){ maybePushFormSuccess(); }, 500); // After 500ms 2365 setTimeout(function(){ maybePushFormSuccess(); }, 1500); // After 1.5s 2366 setTimeout(function(){ maybePushFormSuccess(); }, 3000); // After 3s (for slow loading pages) 2367 } 2368 } catch(e) { 2369 console.error('[pxTrack] Error during initialization:', e); 2370 } 2371 }); 2372 } else { 2373 console.log('%c[pxTrack] STEP 2: DOM already ready, initializing immediately', 'color: #9C27B0; font-weight: bold;'); 2374 console.log('[pxTrack] DOM already ready, initializing watchers immediately...'); 2375 try { 2376 wireSearchFallbacks(); 2377 wireSearchEventsWhenReady(); 2378 wireFormEvents(); 2379 wireWhatsappClick(); 2380 if (typeof wireCheckoutForm === 'function') { 2381 wireCheckoutForm(); 2382 } else { 2383 console.log('[pxTrack] wireCheckoutForm() not available (may be conditional)'); 2384 } 2385 wireDatePickers(); 2386 enhanceContextFromHiddenInputs(); 2387 enhanceContextFromPxJson(); 2388 fetchSearchInfoIfNeeded(); 2389 console.log('%c[pxTrack] STEP 4: About to call wireNoInventoryWatcher()...', 'color: #FF5722; font-weight: bold; font-size: 16px;'); 2390 try { 2391 wireNoInventoryWatcher(); 2392 console.log('%c[pxTrack] STEP 5: wireNoInventoryWatcher() completed successfully!', 'color: #4CAF50; font-weight: bold; font-size: 16px;'); 2393 } catch(e) { 2394 console.error('[pxTrack] ERROR calling wireNoInventoryWatcher():', e); 2395 console.error('[pxTrack] Error stack:', e.stack); 2396 } 2397 observeAvailabilityContainers();
2398 setTimeout(function(){ enhanceContextFromHiddenInputs(); enhanceContextFromPxJson(); }, 500); 2399 setTimeout(function(){ enhanceContextFromHiddenInputs(); enhanceContextFromPxJson(); }, 1500); 2400 // checkout success detector (thank-you page) - multiple attempts with delays 2401 if (typeof maybePushFormSuccess === 'function') { 2402 maybePushFormSuccess(); // Immediate 2403 setTimeout(function(){ maybePushFormSuccess(); }, 500); // After 500ms 2404 setTimeout(function(){ maybePushFormSuccess(); }, 1500); // After 1.5s 2405 setTimeout(function(){ maybePushFormSuccess(); }, 3000); // After 3s (for slow loading pages) 2406 } 2407 } catch(e) { 2408 console.error('[pxTrack] Error during initialization:', e); 2409 console.error('[pxTrack] Error stack:', e.stack); 2410 } 2411 } 2412 })(); 2413</script>
2413 2414 2415 2416<!-- Google Tag Manager -->
2417<script>
vendor: 436 bytes, lines 2417-2431
2417 2418 (function(w, d, s, l, i) { 2419 w[l] = w[l] || []; 2420 w[l].push({ 2421 'gtm.start': new Date().getTime(), 2422 event: 'gtm.js' 2423 }); 2424 var f = d.getElementsByTagName(s)[0], 2425 j = d.createElement(s), 2426 dl = l != 'dataLayer' ? '&l=' + l : ''; 2427 j.async = true; 2428 j.src = 2429 'https://www.googletagmanager.com/gtm.js?id=' + i + dl; 2430 f.parentNode.insertBefore(j, f); 2431 })(window, document, 'script', 'dataLayer', '
2431GTM-TPTNCNX
vendor: 4 bytes, line 2431
2431');
2432</script>
2432 2433<!-- End Google Tag Manager --> 2434 2435 2436 2437 2438</head> 2439 2440<body> 2441 <!-- Google Tag Manager (noscript) -->
vendor: 69 bytes, lines 2441-2442
2441 2442 <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=
2442GTM-TPTNCNX
vendor: 84 bytes, lines 2442-2443
2442" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> 2443
2443<!-- End Google Tag Manager (noscript) --> 2444 2445 2446 2447 2448 <div class="neo_loader"> 2449 <style> 2450 .linear-activity { 2451 overflow: hidden; 2452 width: 100%; 2453 height: 4px; 2454 background-color: #B3E5FC; 2455 margin: 0 2456 } 2457 2458 .determinate { 2459 position: relative; 2460 max-width: 100%; 2461 height: 100%; 2462 -webkit-transition: width .5s ease-out 1s; 2463 -moz-transition: width .5s ease-out 1s; 2464 -o-transition: width .5s ease-out 1s; 2465 transition: width .5s ease-out 1s; 2466 background-color: #03A9F4 2467 } 2468 2469 .indeterminate { 2470 position: relative; 2471 width: 100%; 2472 height: 100% 2473 } 2474 2475 .indeterminate:after, 2476 .indeterminate:before { 2477 content: ''; 2478 position: absolute; 2479 height: 100% 2480 } 2481 2482 .indeterminate:before { 2483 background-color: #03A9F4; 2484 animation: indeterminate_first 1.5s infinite ease-out 2485 } 2486 2487 .indeterminate:after { 2488 background-color: #4FC3F7; 2489 animation: indeterminate_second 1.5s infinite ease-in 2490 } 2491 2492 @keyframes indeterminate_first { 2493 0% { 2494 left: -100%; 2495 width: 100% 2496 } 2497 2498 100% { 2499 left: 100%; 2500 width: 10% 2501 } 2502 } 2503 2504 @keyframes indeterminate_second { 2505 0% { 2506 left: -150%; 2507 width: 100% 2508 } 2509 2510 100% { 2511 left: 100%; 2512 width: 10% 2513 } 2514 } 2515 2516 .neo_loader { 2517 position: fixed; 2518 top: 0; 2519 left: 0; 2520 right: 0; 2521 bottom: 0; 2522 z-index: 9999999999999999999999; 2523 background: #fff; 2524 height: 100vh; 2525 width: 100vw; 2526 display: flex; 2527 flex-direction: column; 2528 justify-content: center; 2529 align-items: center; 2530 padding: 40px; 2531 box-sizing: border-box; 2532 text-align: center; 2533 } 2534 2535 .neo_loader .loaderline { 2536 width: 400px; 2537 margin: 40px; 2538 max-width: 90vw 2539 } 2540 2541 .loadername { 2542 color: #bbb; 2543 font-family: Helvetica, Arial, sans-serif; 2544 margin: 10px auto 15px 2545 } 2546 2547 .linear-activity.gray { 2548 background-color: #eaeaea 2549 } 2550 2551 .gray .indeterminate:after, 2552 .gray .indeterminate:before { 2553 background-color: #bbb 2554 } 2555 2556 .neo_megacontainer { 2557 display: none 2558 } 2559 </style> 2560 2561 <img loading="lazy" style=" max-height: 200px; max-width: 200px; object-fit: contain; margin-bottom: 20px;" src="https://files-p.pxsol.com/18413/company/library/user/241250311408a778cb276110216fe92234bb4283ca1.png" alt="Premium Tower Suites Mendoza"> 2562 <div class="loadername"> 2563 Premium Tower Suites Mendoza </div> 2564 <div class="loaderline"> 2565 <div class="linear-activity gray"> 2566 <div class="indeterminate"></div> 2567 </div> 2568 </div> 2569 </div> 2570 2571 <div class="neo_megacontainer habitaciones"> 2572 2573 2574 2575 2576 2577<div class="main_wraper_top" id="main_wraper_top"> 2578 2579 2580<div class="neo_template_container neo_template_ computer"> 2581 2582 2583<div id='normalheader' class="navbar-fullwidth normalheader" ><div class="fullwidth flex flex-m-sb flex-s-center padding-xs-5" ><div class='xs-50' ><div class='pxModule_include ModuloWrap_idiomas '><div id="top_menu"> 2584 2585 <div id="contenedor_top"> 2586 <div id="menu_div_top"> 2587 <div class="nav_top flex flex-s-center"> 2588 2589 2590 <div class="selectidiomaymoneda"> 2591 <div class="currency_module_container" > 2592 <input type="hidden" id='ModuloIdioma_DefaultCurrency' value="ARS"> 2593 <input type="hidden" id="ModuloIdioma_BookingEngineVersion" value="8"> 2594 <div class="texto_idiomaymoneda"> 2595 Currency - </div> 2596 <div id="deploymoneda" class="pointer deploymoneda" > 2597 <div class="monedaactual hidden" cur="USD"> 2598 USD $ </div> 2599 <div class="monedaactual hidden" cur="ARS"> 2600 ARS $ </div> 2601 </div> 2602 <div id="monedasshow" class="monedasshow"> 2603 <div class="titlemenujs"> 2604 Choose the currency of your preference </div> 2605 <div class="monedaitem changeCurrency hidden" cur="USD"> 2606 <strong>USD $</strong> 2607 <div class="monedasname"> 2608 Dólar americano </div> 2609 </div> 2610 <div class="monedaitem changeCurrency hidden" cur="ARS"> 2611 <strong>ARS $</strong> 2612 <div class="monedasname"> 2613 Peso argentino </div> 2614 </div> 2615 </div> 2616 2617 </div> 2618 <div class="texto_idiomaymoneda"> 2619 Language - </div> 2620 2621 2622 <div id="deployidioma" class="deployidioma"> 2623 <img alt="flag" style="object-fit: contain;" class="bandera" src="/css/images/bnd_en.png" height="24px" width="24px" /> 2624 </div> 2625 2626 2627 <div id="idiomasshow" class="idiomasshow"> 2628 <div class="titlemenujs"> 2629 Choose the language of your preference </div> 2630 <div class="idiomaitem"> 2631 <a class="idiomalink" lng="es" href="/habitaciones.html?lng=es" ignorar-vista="true" style="width: 100%;"> 2632 <img class="bandera" style="object-fit: contain;" src="/css/images/bnd_es.png" height="20" width="20" alt="es" /> 2633 <span class="nameidioma"> 2634 Español </span> 2635 </a> 2636 </div> 2637 <div class="idiomaitem"> 2638 <a class="idiomalink" lng="pt" href="/pt/habitaciones.html?lng=pt" ignorar-vista="true" style="width: 100%;"> 2639 <img class="bandera" style="object-fit: contain;" src="/css/images/bnd_pt.png" height="20" width="20" alt="pt" /> 2640 <span class="nameidioma"> 2641 Português </span> 2642 </a> 2643 </div> 2644 </div>
2645 </div> 2646 2647 2648 <a href="https://app.reservadirecto.com/auth_web?return_url=https%3A%2F%2Fwww.premiumtowersuites.com.ar%2Fauthorize.php%3Fredirect_url%3Dhttps%253A%252F%252Fwww.premiumtowersuites.com.ar%252Fen%252Fhabitaciones.html&origin_pos=PremiumTowerApartHotel" ignorar-vista="true" class="btn_sesion cta_webcheckin_px margin-sm-right-10" style="text-decoration: none"> 2649 <i class="mdi mdi-account" aria-hidden="true"></i> 2650 <span> 2651 Log in </span> 2652 </a> 2653 2654
2654<script src="https://accounts.google.com/gsi/intermediate"></script>
2654 2655
2655<script src="https://accounts.google.com/gsi/intermediatesupport"></script>
2655 2656 2657 <div id="g_id_intermediate_iframe" data-src="https://eva.reservadirecto.com/core/includes/google_one_tap_intermediate_iframe.php?origin=https%3A%2F%2Fwww.premiumtowersuites.com.ar&redirect_url=https%3A%2F%2Fwww.premiumtowersuites.com.ar%2Fen%2Fhabitaciones.html&pos=PremiumTowerApartHotel"> 2658 </div> 2659 2660 <style> 2661 .neo_login_incentive { 2662 position: fixed; 2663 top: 10rem; 2664 right: calc(1rem + 10px); 2665 width: 375px; 2666 text-align: left; 2667 z-index: 1; 2668 } 2669 2670 .neo_login_incentive>div { 2671 margin: 0; 2672 border-radius: 10px; 2673 } 2674 2675 iframe#onetap_google_intermediate_iframe, 2676 #credential_picker_container, 2677 #credential_picker_container iframe, 2678 iframe[src*="google_one_tap_intermediate_iframe"] { 2679 top: 18.5rem !important; 2680 right: 1rem !important; 2681 } 2682 2683 @media only screen and (max-width: 468px) { 2684 .neo_login_incentive { 2685 display: none !important; 2686 bottom: 0rem; 2687 top: initial; 2688 left: 0; 2689 right: 0; 2690 position: fixed; 2691 width: 100%; 2692 text-transform: initial; 2693 letter-spacing: normal; 2694 font-weight: initial; 2695 } 2696 2697 iframe#onetap_google_intermediate_iframe, 2698 #credential_picker_container, 2699 #credential_picker_container iframe, 2700 iframe[src*="google_one_tap_intermediate_iframe"] { 2701 top: initial !important; 2702 bottom: 5rem !important; 2703 right: initial !important; 2704 z-index: 1; 2705 } 2706 } 2707 </style> 2708
2708<script> 2709 (function() { 2710 var repositioned = false; 2711 var attempts = 0; 2712 var timer = setInterval(function() { 2713 if (repositioned || ++attempts > 60) { clearInterval(timer); return; } 2714 var el = document.getElementById('credential_picker_container') 2715 || document.querySelector('iframe[src*="google_one_tap_intermediate_iframe"]') 2716 || document.getElementById('onetap_google_intermediate_iframe'); 2717 if (el) { 2718 var target = (el.tagName === 'IFRAME' && el.parentElement && el.parentElement.style.position === 'fixed') ? el.parentElement : el; 2719 var isMobile = window.innerWidth <= 468; 2720 if (isMobile) { 2721 target.style.setProperty('top', 'initial', 'important'); 2722 target.style.setProperty('bottom', '5rem', 'important'); 2723 target.style.setProperty('right', 'initial', 'important'); 2724 } else { 2725 target.style.setProperty('top', '18.5rem', 'important'); 2726 target.style.setProperty('right', '1rem', 'important'); 2727 } 2728 repositioned = true; 2729 clearInterval(timer); 2730 } 2731 }, 100); 2732 })(); 2733 </script>
2733 2734 2735 </div> 2736 </div> 2737 </div> 2738 2739</div> 2740</div></div></div><div class="navbar-fullwidth navbar-top" ><ul class='nav-list' ><li class='' ><a class="item-list" href="/en/index.html" target="">Home</a></li><li class='' ><a class="item-list" href="/en/habitaciones.html" target="">Rooms</a></li><li class='' ><a class="item-list" href="/en/servicios.html" target="">Services</a></li><li class='' ><a class="item-list" href="/en/eventos.html" target="">Eventos</a></li></ul><div class="loguito" > <img loading="lazy" class="" lazy-src="https://picsv3.pxsol.com/18413/company/library/user/34464345120d57352cb6880b02f98dd39a87e622c7.png?ixlib=js-2.3.2&s=8403b09995ab0dc78d81a586e8eaddac" alt="PremiumTowerApartHotel" > </image></div><ul class='nav-list' ><li class='' ><a class="item-list" href="/en/galeria.html" target="">Gallery</a></li><li class='' ><a class="item-list" href="/en/promos.html" target="">Promotions</a></li><li class='' ><a class="item-list" href="/en/contacto.html" target="">Location and Contact</a></li></ul></div></div> 2741 2742 2743<div class="container-search" ><div id='normalsearch' class="normalsearch" ><div class='' ListSelector='false' ProductSelector='false' LocationSearch='false' BuscadorVertical='false' OwnLP='false'> 2744 <div class="neo_template_block neo_marketplace_buscador_v3 pxModule_include ModuloWrap_marketplace_buscador_v3" id="marketplace_buscador_v3" > 2745 2746 2747 <div class="px-mk-buscador-container buscar_lp "> 2748 2749 2750 2751 <form px-endpoint="https://api-1-eb-web.pxsol.io" action="https://api-1-eb-web.pxsol.io/search/insert" ajax-action="search/insert" method="post" name="pxmk_searchform" id="pxmk_searchform" class="px-mk-searchform marketplace_searchform_computer" target="_self"> 2752 <label class="error px-mk-generalerror nodisplay">An error has occurred, please try again</label> 2753 2754 2755 2756 2757 2758 <div class="fechas_ancho_entrada px-sm-inputcontainer w-padding px-mk-fixedwidth-inputcontainer"> 2759 <label class="px-mk-inputicon" for="fechaingreso"> 2760 <?xml version="1.0" encoding="iso-8859-1"?> 2761<svg version="1.1" id="Capa_1" 2762 xmlns="http://www.w3.org/2000/svg" 2763 xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 426.667 426.667" style="enable-background:new 0 0 426.667 426.667;" xml:space="preserve"> 2764 <g> 2765 <g> 2766 <g> 2767 <rect x="213.333" y="234.667" width="106.667" height="106.667"/> 2768 <path d="M362.667,42.667h-21.333V0h-42.667v42.667H128V0H85.333v42.667H64c-23.573,0-42.453,19.093-42.453,42.667L21.333,384 c0,23.573,19.093,42.667,42.667,42.667h298.667c23.573,0,42.667-19.093,42.667-42.667V85.333 C405.333,61.76,386.24,42.667,362.667,42.667z M362.667,384H64V149.333h298.667V384z"/> 2769 </g> 2770 </g> 2771 </g> 2772</svg> </label> 2773 <label class="px-mk-labelinput" for="fechaingreso"> 2774 Arrival </label> 2775 <input name="Start" type="text" style="font-size: 16px !important;" onfocus="return false;" readonly id="fechaingreso" class="" value="26/09/2026" placeholder="Check In" data-testid="date-start" /> 2776 </div> 2777 2778 <div class=" fechas_ancho_salida px-sm-inputcontainer w-padding px-mk-fixedwidth-inputcontainer"> 2779 <label class="px-mk-inputicon" for="fechaegreso"> 2780 <?xml version="1.0" encoding="iso-8859-1"?> 2781<svg version="1.1" id="Capa_1" 2782 xmlns="http://www.w3.org/2000/svg" 2783 xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 426.667 426.667" style="enable-background:new 0 0 426.667 426.667;" xml:space="preserve"> 2784 <g> 2785 <g> 2786 <g> 2787 <rect x="213.333" y="234.667" width="106.667" height="106.667"/> 2788 <path d="M362.667,42.667h-21.333V0h-42.667v42.667H128V0H85.333v42.667H64c-23.573,0-42.453,19.093-42.453,42.667L21.333,384 c0,23.573,19.093,42.667,42.667,42.667h298.667c23.573,0,42.667-19.093,42.667-42.667V85.333 C405.333,61.76,386.24,42.667,362.667,42.667z M362.667,384H64V149.333h298.667V384z"/> 2789 </g> 2790 </g> 2791 </g> 2792</svg> </label> 2793 <label class="px-mk-labelinput" for="fechaegreso"> 2794 Departure date </label> 2795 <input name="End" type="text" style="font-size: 16px !important;" onfocus="return false;" readonly id="fechaegreso" size="10" value="27/09/2026" class="relative maxzindex pointer" placeholder="Check-out" data-testid="date-end" /> 2796 </div> 2797 2798 2799 <div id="NochesError" class="error" style="display:none"></div> 2800 2801 2802 <div class="codigopromocional px-sm-inputcontainer w-padding px-mk-fixedwidth-inputcontainer"> 2803 <label class="px-mk-inputicon" for="fechaegreso"> 2804 <?xml version="1.0" encoding="iso-8859-1"?> 2805<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> 2806<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" 2807 viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve"> 2808<g> 2809 <g> 2810 <path d="M32,271.692v192c0,17.664,14.368,32,32,32h160v-224H32z"/> 2811 </g> 2812</g> 2813<g> 2814 <g> 2815 <path d="M480,143.692H378.752c7.264-4.96,13.504-9.888,17.856-14.304c25.824-25.952,25.824-68.192,0-94.144 2816 c-25.088-25.28-68.8-25.216-93.856,0c-13.888,13.92-50.688,70.592-45.6,108.448h-2.304c5.056-37.856-31.744-94.528-45.6-108.448 2817 c-25.088-25.216-68.8-25.216-93.856,0C89.6,61.196,89.6,103.436,115.36,129.388c4.384,4.416,10.624,9.344,17.888,14.304H32 2818 c-17.632,0-32,14.368-32,32v48c0,8.832,7.168,16,16,16h208v-64h64v64h208c8.832,0,16-7.168,16-16v-48 2819 C512,158.06,497.664,143.692,480,143.692z M222.112,142.636c0,0-1.344,1.056-5.92,1.056c-22.112,0-64.32-22.976-78.112-36.864 2820 c-13.408-13.504-13.408-35.52,0-49.024c6.496-6.528,15.104-10.112,24.256-10.112c9.12,0,17.728,3.584,24.224,10.112 2821 C208.128,79.5,229.568,134.924,222.112,142.636z M295.776,143.692c-4.544,0-5.888-1.024-5.888-1.056 2822 c-7.456-7.712,13.984-63.136,35.552-84.832c12.896-13.024,35.456-13.088,48.48,0c13.44,13.504,13.44,35.52,0,49.024 2823 C360.128,120.716,317.92,143.692,295.776,143.692z"/> 2824 </g> 2825</g> 2826<g> 2827 <g> 2828 <path d="M288,271.692v224h160c17.664,0,32-14.336,32-32v-192H288z"/> 2829 </g> 2830</g> 2831<g> 2832</g> 2833<g> 2834</g> 2835<g> 2836</g> 2837<g> 2838</g> 2839<g> 2840</g> 2841<g> 2842</g> 2843<g> 2844</g> 2845<g> 2846</g> 2847<g> 2848</g> 2849<g> 2850</g> 2851<g> 2852</g> 2853<g> 2854</g> 2855<g> 2856</g> 2857<g> 2858</g> 2859<g> 2860</g> 2861</svg> 2862 </label> 2863 <label class="px-mk-labelinput" for="PromoCode"> 2864 Promotional code </label> 2865 <input name="Code" type="text" id="PromoCode" size="6" class="relative maxzindex pointer" data-testid="promo-code" /> 2866 </div> 2867 2868 2869 2870 <div class="nodisplay" id="Combinations">[{"Adults":1,"Childs":0,"Babies":0},{"Adults":2,"Childs":0,"Babies":0},{"Adults":1,"Childs":1,"Babies":0},{"Adults":1,"Childs":0,"Babies":1},{"Adults":1,"Childs":1,"Babies":1},{"Adults":2,"Childs":0,"Babies":1},{"Adults":4,"Childs":0,"Babies":0},{"Adults":3,"Childs":1,"Babies":0},{"Adults":3,"Childs":0,"Babies":1},{"Adults":3,"Childs":0,"Babies":0},{"Adults":2,"Childs":2,"Babies":0},{"Adults":2,"Childs":1,"Babies":1},{"Adults":2,"Childs":1,"Babies":0},{"Adults":1,"Childs":3,"Babies":0},{"Adults":1,"Childs":2,"Babies":1},{"Adults":1,"Childs":2,"Babies":0}]</div> 2871 2872<style> 2873 /* Quitar flechitas de inputs number en Chrome, Safari, Edge, Opera */ 2874 .neo_partyselector_quantity::-webkit-outer-spin-button, 2875 .neo_partyselector_quantity::-webkit-inner-spin-button { 2876 -webkit-appearance: none; 2877 margin: 0; 2878 } 2879 2880 /* Desktop - mantener original, todo en una lÃnea */ 2881 .txtPartyGroup .guests-row, 2882 .txtPartyGroup .rooms-row { 2883 display: inline; 2884 } 2885 2886 /* Nacionalidad label - desktop #000, mobile #333 */ 2887 .nacionalidad-label { 2888 color: #000 !important; 2889 } 2890 2891 @media only screen and (max-width: 650px) { 2892 .nacionalidad-label { 2893 color: #333 !important; 2894 } 2895 } 2896 2897 .txtPartyGroup .party-number { 2898 margin-right: 4px; 2899 } 2900 2901 .txtPartyGroup .party-separator { 2902 color: #999; 2903 margin: 0 4px; 2904 } 2905 2906 /* Mobile - formato de dos lÃneas mejorado */ 2907 @media only screen and (max-width: 650px) { 2908 2909 /* Ocultar separador entre huéspedes y habitaciones en mobile */ 2910 .txtPartyGroup .rooms-separator { 2911 display: none; 2912 } 2913 2914 .txtPartyGroup { 2915 display: flex; 2916 flex-direction: column; 2917 align-items: flex-start; 2918 gap: 2px; 2919 font-size: 15px; 2920 line-height: 1.4;
2921 color: #555; 2922 } 2923 2924 .txtPartyGroup .guests-row { 2925 display: flex; 2926 align-items: center; 2927 flex-wrap: wrap; 2928 } 2929 2930 .txtPartyGroup .party-item { 2931 display: inline-flex; 2932 align-items: baseline; 2933 white-space: nowrap; 2934 } 2935 2936 .txtPartyGroup .party-number { 2937 font-weight: 700; 2938 color: #333; 2939 margin-right: 4px; 2940 } 2941 2942 .txtPartyGroup .party-label { 2943 color: #666; 2944 } 2945 2946 .txtPartyGroup .party-separator { 2947 color: #ccc; 2948 margin: 0 8px; 2949 } 2950 2951 .txtPartyGroup .rooms-row { 2952 display: block; 2953 color: #666; 2954 margin: 0; 2955 padding: 0; 2956 text-align: left; 2957 } 2958 2959 .SelectorInitial { 2960 min-height: 65px; 2961 padding: 12px 45px 12px 14px; 2962 display: flex; 2963 align-items: center; 2964 } 2965 2966 .PartyTypeSimulatorContainer { 2967 overflow: visible; 2968 } 2969 2970 /* Ajuste para los labels del selector */ 2971 .neo_party_selector>div:first-child { 2972 display: flex; 2973 flex-direction: column; 2974 min-width: 0; 2975 } 2976 2977 .neo_party_selector>div:first-child>div { 2978 white-space: nowrap; 2979 overflow: visible; 2980 font-size: 14px; 2981 font-weight: 500; 2982 } 2983 2984 .neo_party_selector>div:first-child>div:last-child { 2985 font-size: 12px; 2986 color: #888; 2987 margin-top: 3px; 2988 white-space: nowrap; 2989 font-weight: 400; 2990 } 2991 2992 /* Asegurar que en mobile los controles sigan alineados a la derecha */ 2993 .neo_party_selector { 2994 display: flex; 2995 justify-content: space-between; 2996 align-items: center; 2997 width: 100%; 2998 margin-bottom: 14px; 2999 padding-bottom: 14px; 3000 border-bottom: 1px solid #f0f0f0; 3001 } 3002 3003 .neo_party_selector:last-of-type { 3004 border-bottom: none; 3005 margin-bottom: 0; 3006 padding-bottom: 0; 3007 } 3008 3009 .neo_party_selector>div:last-child { 3010 display: flex; 3011 align-items: center; 3012 justify-content: flex-end; 3013 flex-shrink: 0; 3014 margin-left: 15px; 3015 } 3016 3017 .neo_party_selector .flex.flex-s-center { 3018 display: flex; 3019 align-items: center; 3020 gap: 4px; 3021 } 3022 } 3023 3024 /* Estilos para alinear correctamente los controles numéricos */ 3025 .neo_party_selector { 3026 display: flex !important; 3027 justify-content: space-between !important; 3028 align-items: center !important; 3029 width: 100% !important; 3030 margin-bottom: 15px !important; 3031 } 3032 3033 .neo_party_selector>div:first-child { 3034 flex: 1 !important; 3035 min-width: 0 !important; 3036 } 3037 3038 .neo_party_selector>div:last-child { 3039 display: flex !important; 3040 align-items: center !important; 3041 justify-content: flex-end !important; 3042 flex-shrink: 0 !important; 3043 margin-left: 15px !important; 3044 } 3045 3046 /* Asegurar que los botones y input estén alineados correctamente */ 3047 .neo_party_selector .flex.flex-s-center { 3048 display: flex !important; 3049 align-items: center !important; 3050 gap: 3px !important; 3051 } 3052</style> 3053 3054<div class="relative PartyTypeSimulatorContainer"> 3055 <div class="PartyTypeSimulator px-sm-inputcontainer w-padding" style="border-right: none" maxadult="4" maxchild="3" maxrooms="4"> 3056 <div class="SelectorInitial" data-testid="guest-selector-trigger"> 3057 <span class="txtPartyGroup" style="align-items: flex-start !important;"> 3058 <span class="guests-row"> 3059 <span class="party-item txtAdults"> 3060 <span class="party-number numberAdults">2</span> 3061 <span class="party-label txtAdultsTxt" plural="Adults" singular="adult"> 3062 Adults </span> 3063 </span> 3064 <span class="party-item txtChildren" style="display:none;"> 3065 <span class="party-separator">â¢</span> 3066 <span class="party-number numberChildren">0</span> 3067 <span class="party-label txtChildrenTxt" plural="Children" singular="boy"> 3068 boy </span> 3069 </span> 3070 <span class="party-item txtBabies" style="display:none;"> 3071 <span class="party-separator">â¢</span> 3072 <span class="party-number numberBabies">0</span> 3073 <span class="party-label txtBabiesTxt" plural="bebés" singular="bebé"> 3074 bebé </span> 3075 </span> 3076 </span> 3077 <span class="rooms-separator party-separator">â¢</span> 3078 <span class="rooms-row txtRooms"> 3079 <span class="party-number numberRooms">1</span> 3080 <span 3081 class="party-label txtRoomsTxt" 3082 plural="rooms" 3083 singular="room"> 3084 room </span> 3085 </span> 3086 </span> 3087 <label class='ignoreclick px-mk-inputicon'> 3088 <?xml version="1.0" encoding="iso-8859-1"?> 3089<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> 3090<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" 3091 viewBox="0 0 426.667 426.667" style="enable-background:new 0 0 426.667 426.667;" xml:space="preserve"> 3092<g> 3093 <g> 3094 <g> 3095 <path d="M309.333,213.333c29.44,0,53.12-23.893,53.12-53.333s-23.68
3095-53.333-53.12-53.333S256,130.56,256,160 3096 S279.893,213.333,309.333,213.333z"/> 3097 <path d="M149.333,192c35.307,0,63.787-28.693,63.787-64c0-35.307-28.48-64-63.787-64s-64,28.693-64,64 3098 C85.333,163.307,114.027,192,149.333,192z"/> 3099 <path d="M149.333,234.667C99.52,234.667,0,259.627,0,309.333v53.333h149.333v-48c0-18.133,7.147-49.813,50.56-74.027 3100 C181.333,236.693,163.307,234.667,149.333,234.667z"/> 3101 <path d="M309.333,256C270.187,256,192,275.627,192,314.667v48h234.667v-48C426.667,275.627,348.48,256,309.333,256z"/> 3102 </g> 3103 </g> 3104</g> 3105<g> 3106</g> 3107<g> 3108</g> 3109<g> 3110</g> 3111<g> 3112</g> 3113<g> 3114</g> 3115<g> 3116</g> 3117<g> 3118</g> 3119<g> 3120</g> 3121<g> 3122</g> 3123<g> 3124</g> 3125<g> 3126</g> 3127<g> 3128</g> 3129<g> 3130</g> 3131<g> 3132</g> 3133<g> 3134</g> 3135</svg> 3136 </label> 3137 </div> 3138 </div> 3139 <div class="PartyTypeSimulatorSelect nodisplay padding-xs-20"> 3140 <div class="flex-column full"> 3141 <div class="neo_party_selector neo_adults_selector flex flex-m-sb flex-s-center"> 3142 <div> 3143 <div>Adults</div> 3144 <div style="font-size: 11px; color: #888; margin-top: 2px;"> 3145 16 años o más </div> 3146 </div> 3147 <div class="flex flex-s-center"> 3148 <button onclick="alterPartyGroup(this);" class="neo_button_partyselector neo_minus_button" type='button' party-type="adults" action-type='minus' data-testid="adults-minus">-</button> 3149 <input type="number" inputmode="numeric" query-default="2" class="neo_partyselector_quantity" party-type="adults" val="2" value="2" onchange="handlePartyInputChange(this);" min="1" max="4" style="background-color: #f8f8f8 !important; border-radius: 10px !important; width: 50px !important; height: 42px !important; margin: 0 3px !important; padding: 0 !important; border: none; text-align: center !important; -moz-appearance: textfield !important;" data-testid="adults-input" /> 3150 <button onclick="alterPartyGroup(this);" class="neo_button_partyselector neo_plus_button" type='button' party-type="adults" action-type='plus' data-testid="adults-plus">+</button> 3151 </div> 3152 </div> 3153 <div class="neo_party_selector neo_adults_selector flex flex-m-sb flex-s-center"> 3154 <div> 3155 <div>Children</div> 3156 <div style="font-size: 11px; color: #888; margin-top: 2px;"> 3157 Hasta 15 años </div> 3158 </div> 3159 <div class="flex flex-s-center"> 3160 <button onclick="alterPartyGroup(this);" class="neo_button_partyselector neo_minus_button" type='button' party-type="children" action-type='minus' data-testid="children-minus">-</button> 3161 <input type="number" inputmode="numeric" query-default="0" class="neo_partyselector_quantity" party-type="children" val="0" value="0" onchange="handlePartyInputChange(this);" min="0" max="3" style="background-color: #f8f8f8 !important; border-radius: 10px !important; width: 50px !important; height: 42px !important; margin: 0 3px !important; padding: 0 !important; border: none; text-align: center !important; -moz-appearance: textfield !important;" data-testid="children-input" /> 3162 <button onclick="alterPartyGroup(this);" class="neo_button_partyselector neo_plus_button" type='button' party-type="children" action-type='plus' data-testid="children-plus">+</button> 3163 </div> 3164 </div> 3165 <div class="neo_party_selector neo_adults_selector flex flex-m-sb flex-s-center"> 3166 <div>Rooms</div> 3167 <div class="flex flex-s-center"> 3168 <button onclick="alterPartyGroup(this);" class="neo_button_partyselector neo_minus_button" type='button' party-type="rooms" action-type='minus' data-testid="rooms-minus">-</button> 3169 <input type="number" inputmode="numeric" class="neo_partyselector_quantity" party-type="rooms" val="1" value="1" onchange="handlePartyInputChange(this);" min="1" max="4" style="background-color: #f8f8f8 !important; border-radius: 10px !important; width: 50px !important; height: 42px !important; margin: 0 3px !important; padding: 0 !important; border: none; text-align: center !important; -moz-appearance: textfield !important;" data-testid="rooms-input" /> 3170 <button onclick="alterPartyGroup(this);" class="neo_button_partyselector neo_plus_button" type='button' party-type="rooms" action-type='plus' data-testid="rooms-plus">+</button> 3171 </div> 3172 </div> 3173 </div> 3174 <div class="ChildrenAgesContainer nodisplay"> 3175 <div class="flex-column"> 3176 <div class="texto padding-xs-bottom-20" style="font-size: 12px !important;">How old are the children you are traveling with?</div> 3177 <div class="ChildrensAges" child-id="0" style="max-height: 200px !important; overflow-y: auto !important; padding-right: 5px !important;"> 3178 <div class="ChildrensAgesSelectContainer" child-id="0" style="margin-bottom: 10px !important;"> 3179 <select class="ChildrensAgeSelect" child-id="0" onchange="alterPartyGroup()" style="color: #444 !important; background-color: transparent !important; padding: 10px 8px !important; border: 1px solid #ddd !important; border-radius: 8px !important; width: 100% !important;" data-testid="child-age-select"> 3180 <option value="" disabled selected>Age on check-out day</option> 3181 <option value="0">0 years</option> 3182 <option value="1">1 year</option> 3183 <option value="2">2 years</option> 3184 <option value="3">3 years</option> 3185 <option value="4">4 years</option> 3186 <option value="5">5 years</option> 3187 <option value="6">6 years</option> 3188 <option value="7">7 years</option> 3189 <option value="8">8 years</option> 3190 <option value="9">9 years</option> 3191 <option value="10">10 years</option> 3192 <option value="11">11 years</option> 3193 <option value="12">12 years</option> 3194 <option value="13">13 years</option> 3195 <option value="14">14 years</option> 3196 <option value="15">15 years</option> 3197 </select> 3198 </div>
3199 </div> 3200 <div class="NotValidChildrens nodisplay animated shake"><i class="fa fa-exclamation" aria-hidden="true"></i> Select age of minors please</div> 3201 </div> 3202 </div> 3203 3204 3205 3206 </div> 3207 3208</div> 3209
3210<script> 3211 // Global flag to track if ages have been initialized 3212 var childrenAgesInitialized = false; 3213 3214 // Function to initialize children ages from GroupsForm 3215 function initializeChildrenAgesFromGroupsForm(force) { 3216 // Only initialize once unless forced 3217 if (childrenAgesInitialized && !force) { 3218 return; 3219 } 3220 3221 try { 3222 } catch (e) { 3223 console.error('Error initializing children ages:', e); 3224 } 3225 } 3226 3227 // Call initialization on page load (in case selects already exist) 3228 $(document).ready(function() { 3229 // Wait a bit to ensure selects are created 3230 setTimeout(function() { 3231 initializeChildrenAgesFromGroupsForm(); 3232 }, 100); 3233 }); 3234</script>
3234 3235 <input name="MaxRooms" type="hidden" id="MaxRooms" value="4" /> 3236 <input name="Nights" type="hidden" id="Nights" /> 3237 <input name="Channel" type="hidden" id="Channel" value="2" /> 3238 <input name="RateType" type="hidden" id="RateType" value="auto" /> 3239 <input name="Pos" type="hidden" id="Pos" value='PremiumTowerApartHotel' /> 3240 <input name="Lng" type="hidden" id="Lng" value='en' /> 3241 <input name="Currency" type="hidden" id="Currency" value="ARS" /> 3242 <input name="MaxAgeChildrenNumber" type="hidden" id="MaxAgeChildrenNumber" value="15" /> 3243 <input name="MaxAgeBabiesNumber" type="hidden" id="MaxAgeBabiesNumber" value="3" /> 3244 <input name="MaxBabiesNumber" type="hidden" id="MaxBabiesNumber" value="1" /> 3245 <input name="ReturnUrl" type="hidden" id="ReturnUrl" value="https://www.premiumtowersuites.com.ar/en/lp.html" /> 3246 3247 <input name="FromUrl" type="hidden" id="FromUrl" value="https://www.premiumtowersuites.com.ar/en/habitaciones.html" /> 3248 <input name="Tag" type="hidden" id="Tag" value="" /> 3249 <input name="Source" id="Source" type="hidden" value="Contact Form"> 3250 3251 <input name="ProductTimezone" id="ProductTimezone" type="hidden" value="America/Argentina/Buenos_Aires"> 3252 <input name="GlobalDaysModifier" id="GlobalDaysModifier" type="hidden" value="0"> 3253 3254 <input name="SearchID" type="hidden" id="SearchID" value="0" /> 3255 3256 <input name="FromPID" type="hidden" id="FromPID" value="19433" /> 3257 3258 <input name="Type" type="hidden" id="Type" value="Hotel" /> 3259 3260 3261 <input name="ProductID" type="hidden" id="ProductID" value="19433" /> 3262 3263 <input name="ListID" type="hidden" id="ListID" value="0" /> 3264 3265 <input name="Location" type="hidden" id="Location" value="" /> 3266 3267 <input name="Device" type="hidden" id="Device" value="Computer" /> 3268 <input name="UserID" type="hidden" id="UserID" value="0" /> 3269 <input name="tag" type="hidden" id="tag" class="tag_cookie" value="" /> 3270 <input name="Email" type="hidden" id="Email" value="" /> 3271 <input name="UserType" type="hidden" id="UserType" value="" /> 3272 <input name="AgreementType" type="hidden" id="AgreementType" value="" /> 3273 3274 <input name="GroupsForm" type="hidden" id="GroupsForm" value="1:2,0,0" /> 3275 3276 3277 3278 3279 3280 3281 <input name="SkuID" type="hidden" id="SkuID" value="" /> 3282 3283 3284 <div class="nodisplay" id="MinNightsError"> 3285 The minimum number of nights must be greater than or equal to 0 </div> 3286 3287 <input name="MinNights" type="hidden" id="MinNights" value="0" /> 3288 3289 <div name="PxMkAcion_Search" id="PxMkAcion_Search" class="px-sm-searchbtn px-sm-inputcontainer w-padding px-mk-fixedwith-inputcontainer cta_webcheckin_px" btntxt="Check Rates" loadingbtntxt="Searching" data-testid="search-button"> 3290 <span class="update-search-span">Check Rates</span> 3291 <label for="" class="px-mk-searchicon px-mk-inputicon ignoreclick"> 3292 <?xml version="1.0" encoding="iso-8859-1"?> 3293<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> 3294<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" 3295 viewBox="0 0 373.12 373.12" style="enable-background:new 0 0 373.12 373.12;" xml:space="preserve"> 3296<g> 3297 <g> 3298 <path d="M266.667,234.667h-16.96l-5.867-5.867c20.907-24.213,33.493-55.68,33.493-90.133C277.333,62.08,215.253,0,138.667,0 3299 S0,62.08,0,138.667s62.08,138.667,138.667,138.667c34.453,0,65.92-12.587,90.133-33.387l5.867,5.867v16.853L341.333,373.12 3300 l31.787-31.787L266.667,234.667z M138.667,234.667c-53.013,0-96-42.987-96-96c0-53.013,42.987-96,96-96c53.013,0,96,42.987,96,96 3301 C234.667,191.68,191.68,234.667,138.667,234.667z"/> 3302 </g> 3303</g> 3304<g> 3305</g> 3306<g> 3307</g> 3308<g> 3309</g> 3310<g> 3311</g> 3312<g> 3313</g> 3314<g> 3315</g> 3316<g> 3317</g> 3318<g> 3319</g> 3320<g> 3321</g> 3322<g> 3323</g> 3324<g> 3325</g> 3326<g> 3327</g> 3328<g> 3329</g> 3330<g> 3331</g> 3332<g> 3333</g> 3334</svg> 3335 </label> 3336 <label for="" class="px-mk-searchloader px-mk-inputicon nodisplay ignoreclick"> 3337 <?xml version="1.0" encoding="iso-8859-1"?> 3338<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> 3339<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 3340<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" 3341 width="26.349px" height="26.35px" viewBox="0 0 26.349 26.35" style="enable-background:new 0 0 26.349 26.35;" 3342 xml:space="preserve"> 3343<g> 3344 <g> 3345 <circle cx="13.792" cy="3.082" r="3.082"/> 3346 <circle cx="13.792" cy="24.501" r="1.849"/> 3347 <circle cx="6.219" cy="6.218" r="2.774"/> 3348 <circle cx="21.365" cy="21.363" r="1.541"/> 3349 <circle cx="3.082" cy="13.792" r="2.465"/> 3350 <circle cx="24.501" cy="13.791" r="1.232"/> 3351 <path d="M4.694,19.84c-0.843,0.843-0.843,2.207,0,3.05c0.842,0.843,2.208,0.843,3.05,0c0.843-0.843,0.843-2.207,0-3.05 3352 C6.902,18.996,5.537,18.988,4.694,19.84z"/> 3353 <circle cx="21.364" cy="6.218" r="0.924"/> 3354 </g> 3355</g> 3356<g> 3357</g> 3358<g> 3359</g> 3360<g> 3361</g> 3362<g> 3363</g> 3364<g> 3365</g> 3366<g> 3367</g> 3368<g> 3369</g> 3370<g> 3371</g> 3372<g> 3373</g> 3374<g> 3375</g> 3376<g> 3377</g> 3378<g> 3379</g> 3380<g> 3381</g> 3382<g> 3383</g> 3384<g> 3385</g> 3386</svg> 3387 </label>
3388 </div> 3389 3390 </form> 3391 3392 <input type="hidden" id="MainPos" value="PremiumTowerApartHotel"> 3393 3394 3395 </div> 3396 3397 3398 3399<div id="dataconfig" product-timezone="America/Argentina/Buenos_Aires" urldispo="id=19433&RateID=34027&start=2026-09-26" class="nodisplay" lng="en" DatePickerStart="0"></div> 3400 3401<link rel="stylesheet" href="https://unpkg.com/tippy.js@6/animations/scale.css" />
3402<script src="https://unpkg.com/@popperjs/core@2"></script>
vendor: 1 bytes, line 3402
3402
3403<script src="https://unpkg.com/tippy.js@6"></script>
3403 3404
3404<script defer src="/neo_modules/marketplace_buscador_v8/js.js?filev=1778144039" type="text/javascript"></script>
3404 3405<style>/* ------------ VARIABLES ------------ */ 3406@import url("https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"); 3407.px-mk-buscador-container { 3408 font-size: 12px; 3409} 3410 3411#MinNightsError { 3412 float: left; 3413 width: calc(100% - 22px); 3414 padding: 10px; 3415 border: 1px solid #982828; 3416 line-height: 20px; 3417 background: #f3e8e8; 3418 color: #000; 3419} 3420 3421.NotValidChildrens { 3422 width: 100%; 3423 float: left; 3424 text-align: center; 3425 color: #800; 3426 font-size: 1em; 3427 font-weight: bold; 3428 padding: 10px 0px; 3429} 3430 3431.update-search-span { 3432 font-weight: 400; 3433 margin-right: 10px; 3434} 3435 3436.ChildrensAgesSelect.notvalid { 3437 border: 1px solid #b51212 !important; 3438} 3439 3440.buscar_lp .buscar_lp_beforerate { 3441 display: none; 3442} 3443 3444.buscar_lp .NochesError { 3445 display: none; 3446} 3447 3448#NochesError { 3449 background: white; 3450 border-right: 1px solid #ccc; 3451 display: flex; 3452 justify-content: center; 3453 align-items: center; 3454} 3455 3456.buscar_lp .TextoFormulario { 3457 float: left; 3458 width: auto; 3459 margin-right: 10px; 3460 text-transform: capitalize; 3461 padding-top: 5px; 3462 font-size: 13px; 3463} 3464 3465.buscar_lp .imput_text_rooms { 3466 font-size: 1em; 3467 padding: 4px 2px; 3468 border: 1px solid #eaeaea; 3469 margin-right: 10px; 3470 float: left; 3471 max-width: 35px; 3472} 3473 3474.buscar_lp .roomtypecontariner { 3475 float: left; 3476 width: auto; 3477} 3478 3479.buscar_lp .bucle { 3480 float: left; 3481 width: auto; 3482} 3483 3484.button_bucar { 3485 float: right; 3486 width: auto; 3487 border: 1px solid #999; 3488 font-size: 14px; 3489 padding: 4px 10px; 3490 background: #eaeaea; 3491 color: #000; 3492} 3493 3494.button_bucar:hover { 3495 background: #999; 3496 color: #fff; 3497 cursor: pointer; 3498} 3499 3500.ContenidoHab { 3501 overflow: hidden; 3502 width: 100%; 3503 margin-bottom: 5px; 3504} 3505 3506.px-mk-buscador-container.buscar_lp .SelectorInitial { 3507 padding: 1em; 3508 margin: 0; 3509 cursor: pointer; 3510 border: none; 3511 box-sizing: border-box; 3512 font-size: 1.1em; 3513 text-overflow: ellipsis; 3514 overflow: hidden; 3515 min-width: 150px; 3516 text-align: left; 3517 padding-right: 2rem !important; 3518 width: 100%; 3519 height: 100%; 3520 display: flex; 3521 background: transparent !important; 3522 align-items: center; 3523} 3524.px-mk-buscador-container.buscar_lp .SelectorInitial .texto { 3525 font-weight: bold; 3526} 3527 3528.px-mk-buscador-container.buscar_lp .RoomsSelectContainer { 3529 width: 100%; 3530 padding-bottom: 5px; 3531 margin-bottom: 5px; 3532 border-bottom: 1px dotted #ccc; 3533 display: flex; 3534 align-items: center; 3535} 3536.px-mk-buscador-container.buscar_lp .RoomsSelectContainer .RoomNameContainer { 3537 width: calc(40% - 10px); 3538 margin-right: 10px; 3539 text-transform: capitalize; 3540 font-size: 1em; 3541 color: #444; 3542} 3543.px-mk-buscador-container.buscar_lp .RoomsSelectContainer .texto { 3544 float: left; 3545 width: 100%; 3546 padding-bottom: 3px; 3547 font-size: 14px; 3548 color: #444; 3549} 3550.px-mk-buscador-container.buscar_lp .RoomsSelectContainer select { 3551 border: 1px solid #d0d0d0; 3552 width: 100%; 3553 border-radius: 4px; 3554 padding: 2px; 3555 color: #666; 3556 font-size: 11px; 3557 margin-bottom: 5px; 3558 cursor: pointer; 3559} 3560.px-mk-buscador-container.buscar_lp .RoomsSelectContainer .hostContainer { 3561 width: 60%; 3562} 3563.px-mk-buscador-container.buscar_lp .RoomsSelectContainer .hostContainer .hostPeopleContainer .AdultsContainer, 3564.px-mk-buscador-container.buscar_lp .RoomsSelectContainer .hostContainer .hostPeopleContainer .ChildrensContainers { 3565 display: flex; 3566 flex-direction: column; 3567 justify-content: center; 3568 align-items: center; 3569 flex: 1; 3570 margin: 3px; 3571} 3572.px-mk-buscador-container.buscar_lp .RoomsSelectContainer .hostContainer .hostPeopleContainer .AdultsContainer > *, 3573.px-mk-buscador-container.buscar_lp .RoomsSelectContainer .hostContainer .hostPeopleContainer .ChildrensContainers > * { 3574 flex-grow: 1; 3575 width: 100%; 3576} 3577.px-mk-buscador-container.buscar_lp .RoomsSelectContainer .hostContainer .ChildrensAges { 3578 float: left; 3579 width: 100%; 3580 margin-top: 5px; 3581} 3582.px-mk-buscador-container.buscar_lp .RoomsSelectContainer .hostContainer .ChildrensAges .ChildrensAgesSelect { 3583 float: left; 3584 width: calc(50% - 5px) !important; 3585 margin-right: 5px; 3586 margin-bottom: 5px; 3587} 3588.px-mk-buscador-container.buscar_lp .RoomsSelectContainer .hostContainer .ChildrensAges .ChildrensAgesSelect:nth-child(even) { 3589 float: right !important; 3590 margin-right: 0px; 3591} 3592.px-mk-buscador-container.buscar_lp .RoomsSelectContainer .hostContainer .ChildrensAges .texto { 3593 float: left; 3594 width: 100%; 3595 padding-bottom: 3px; 3596 font-size: 14px; 3597 color: #444; 3598} 3599 3600.px-mk-buscador-container.buscar_lp .px-mk-addnewroom, 3601.px-mk-buscador-container.buscar_lp .px-mk-removeroom { 3602 flex: 1; 3603 cursor: pointer; 3604 margin: 3px; 3605} 3606.px-mk-buscador-container.buscar_lp .px-mk-addnewroom.nodisplay, 3607.px-mk-buscador-container.buscar_lp .px-mk-removeroom.nodisplay { 3608 display: none; 3609} 3610.px-mk-buscador-container.buscar_lp .px-mk-addnewroom svg, 3611.px-mk-buscador-container.buscar_lp .px-mk-removeroom svg { 3612 height: 18px; 3613 width: 18px; 3614 fill: currentColor; 3615 margin-left: 3px; 3616} 3617.px-mk-buscador-container.buscar_lp .px-mk-addnewroom button, 3618.px-mk-buscador-container.buscar_lp .px-mk-removeroom button { 3619 width: 100%; 3620 display: flex; 3621 align-items: center; 3622 justify-content: center; 3623 text-align: center; 3624 background: #f3f3f3; 3625 border: 1px solid #ccc; 3626 padding: 5px 0px; 3627 box-sizing: border-box; 3628 border-radius: 30px; 3629 color: #444; 3630 font-size: 0.9em; 3631 text-transform: capitalize; 3632 cursor: pointer; 3633} 3634.px-mk-buscador-container.buscar_lp .px-mk-addnewroom button span, 3635.px-mk-buscador-container.buscar_lp .px-mk-removeroom button span { 3636 text-transform: capitalize; 3637 line-height: 1; 3638} 3639 3640.px-mk-buscador-container.buscar_lp { 3641 display: flex; 3642 align-items: center; 3643 height: 100%; 3644 padding: 3px; 3645 box-sizing: border-box; 3646 transition: 0.3s ease-out; 3647} 3648.px-mk-buscador-container.buscar_lp #MultiplePartySelect { 3649 float: left; 3650 flex-direction: column; 3651 display: flex; 3652 width: calc(100% - 12px); 3653 padding: 5px; 3654 background: #fff; 3655 border: 1px solid #ddd; 3656 margin: 0px; 3657 position: absolute; 3658 top: 100%; 3659 min-width: 250px; 3660 z-index: 11; 3661 box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08); 3662} 3663.px-mk-buscador-container.buscar_lp #MultiplePartySelect.nodisplay { 3664 display: none; 3665} 3666.px-mk-buscador-container.buscar_lp .PartyTypeSimulatorSelect { 3667 background: #fff; 3668 border: 1px solid #ddd; 3669 margin: 0px; 3670 position: absolute; 3671 top: 100%; 3672 left: 0; 3673 display: flex; 3674 z-index: 99; 3675 flex-direction: column; 3676} 3677.px-mk-buscador-container.buscar_lp .PartyTypeSimulatorSelect .px-sm-inputcontainer { 3678 height: 50px;
3679 border-right: none; 3680 border-bottom: 1px solid #ccc; 3681 cursor: pointer; 3682 padding: 1em 4em 1em 1em; 3683 box-sizing: border-box; 3684} 3685.px-mk-buscador-container.buscar_lp .PartyTypeSimulatorSelect .px-sm-inputcontainer:last-child { 3686 border-bottom: none; 3687} 3688.px-mk-buscador-container.buscar_lp .PartyTypeSimulatorSelect .px-sm-inputcontainer .texto { 3689 padding: 0px; 3690 display: flex; 3691 align-items: center; 3692 text-align: left; 3693 font-size: 14px; 3694 color: #888; 3695} 3696.px-mk-buscador-container.buscar_lp .PartyTypeSimulatorSelect .px-sm-inputcontainer .texto:hover { 3697 color: #444; 3698} 3699.px-mk-buscador-container.buscar_lp .PartyTypeSimulatorSelect.nodisplay { 3700 display: none; 3701} 3702.px-mk-buscador-container.buscar_lp .px-mk-searchform { 3703 float: none; 3704 width: auto; 3705 display: flex; 3706 align-items: center; 3707 height: 60px; 3708 box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08); 3709} 3710.px-mk-buscador-container.buscar_lp .px-mk-searchform > * { 3711 height: 100%; 3712 margin: 0; 3713 float: none; 3714 position: relative; 3715 flex-shrink: 0; 3716 flex-grow: 1; 3717} 3718.px-mk-buscador-container.buscar_lp .px-mk-searchform .px-sm-searchbtn { 3719 min-width: 18em; 3720} 3721 3722.ModuloWrap_marketplace_buscador_v3.isolate::after { 3723 content: ""; 3724 position: fixed; 3725 top: 0; 3726 left: 0; 3727 width: 100vw; 3728 height: 100vh; 3729 background: rgba(0, 0, 0, 0.3); 3730 z-index: -1; 3731 bottom: 0; 3732 right: 0; 3733 -webkit-backdrop-filter: blur(5px); 3734 backdrop-filter: blur(5px); 3735 animation: appearIsolate 1s cubic-bezier(0.165, 0.84, 0.44, 1) forwards; 3736} 3737 3738@keyframes appearIsolate { 3739 from { 3740 opacity: 0; 3741 } 3742 to { 3743 opacity: 1; 3744 } 3745} 3746.px-sm-inputcontainer { 3747 display: flex; 3748 position: relative; 3749 border-right: 1px solid #ccc; 3750 transition: 0.3s ease-out; 3751 cursor: pointer; 3752 flex-direction: column; 3753 justify-content: center; 3754 align-items: flex-start; 3755 text-align: left; 3756 box-sizing: border-box; 3757 background-color: white; 3758} 3759.px-sm-inputcontainer .hasDatepicker { 3760 cursor: pointer !important; 3761} 3762.px-sm-inputcontainer input { 3763 border-bottom: none !important; 3764 box-shadow: none !important; 3765} 3766.px-sm-inputcontainer label.error { 3767 background: #bf0000; 3768 float: none; 3769 min-width: 100%; 3770 margin: 0px; 3771 left: 0; 3772 padding: 10px 20px; 3773 box-sizing: border-box; 3774 top: 100%; 3775 bottom: initial; 3776 right: auto; 3777 transform: translatey(0); 3778 color: white; 3779 font-weight: 400; 3780 text-transform: uppercase; 3781 font-size: 10px; 3782 letter-spacing: 2px; 3783 position: absolute; 3784 line-height: 1.6em; 3785} 3786.px-sm-inputcontainer.px-mk-fixedwidth-inputcontainer { 3787 width: 11em; 3788} 3789.px-sm-inputcontainer.px-mk-fixedwidth-inputcontainer-max { 3790 width: 18em; 3791} 3792.px-sm-inputcontainer.w-padding { 3793 padding: 0.6em 1em; 3794} 3795.px-sm-inputcontainer .px-mk-labelinput { 3796 margin-bottom: 3px; 3797 font-size: 13px; 3798 opacity: 1; 3799 cursor: pointer; 3800 margin-top: 3px; 3801} 3802.px-sm-inputcontainer .px-mk-inputicon { 3803 position: absolute; 3804 z-index: 2; 3805 right: 1.2em; 3806 color: #aaa; 3807 top: 50%; 3808 transform: translatey(-50%); 3809 font-size: 1.2em; 3810 transition: 0.3s ease-out; 3811 cursor: pointer; 3812} 3813.px-sm-inputcontainer .px-mk-inputicon svg { 3814 height: 1.2em; 3815 width: 1.2em; 3816 fill: currentColor; 3817} 3818.px-sm-inputcontainer.nodisplay { 3819 display: none; 3820} 3821.px-sm-inputcontainer:last-child { 3822 border-right: none; 3823} 3824.px-sm-inputcontainer input, 3825.px-sm-inputcontainer select, 3826.px-sm-inputcontainer textarea { 3827 position: relative; 3828 -webkit-appearance: none; 3829 -moz-appearance: none; 3830 border: none; 3831 box-sizing: border-box; 3832 font-size: 1.1em; 3833 text-overflow: ellipsis; 3834 height: auto; 3835 transition: inherit; 3836 background-color: transparent; 3837 max-width: 100%; 3838 width: 100%; 3839} 3840.px-sm-inputcontainer input option, 3841.px-sm-inputcontainer select option, 3842.px-sm-inputcontainer textarea option { 3843 background-color: #fff; 3844} 3845.px-sm-inputcontainer input[type=text]:not(.hasDatepicker), 3846.px-sm-inputcontainer select[type=text]:not(.hasDatepicker), 3847.px-sm-inputcontainer textarea[type=text]:not(.hasDatepicker) { 3848 cursor: text; 3849} 3850.px-sm-inputcontainer input { 3851 padding: 0px; 3852 margin: 0px !important; 3853} 3854.px-sm-inputcontainer > select { 3855 padding: 1em 4em 1em 1em; 3856 height: 100%; 3857 width: 100%; 3858 cursor: pointer; 3859 white-space: initial; 3860} 3861.px-sm-inputcontainer > select::-ms-expand { 3862 display: none; 3863 /* hide the default arrow in ie10 and ie11 */ 3864} 3865.px-sm-inputcontainer:hover { 3866 background-color: #f0f0f0; 3867} 3868.px-sm-inputcontainer:hover label {
3869 color: #e0ae1b; 3870} 3871 3872.px-mk-searchinfo + .px-mk-buscador-container .px-mk-searchform { 3873 width: 100%; 3874} 3875.px-mk-searchinfo .px-mk-searchinfo-inner { 3876 width: 100%; 3877 height: 40px; 3878 background: #fafafa; 3879 box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08); 3880 border-radius: 2px; 3881 text-transform: uppercase; 3882 font-size: 1em; 3883 box-sizing: border-box; 3884 font-weight: 600; 3885} 3886.px-mk-searchinfo .px-mk-searchinfo-inner > div { 3887 text-align: center; 3888 border-right: 1px solid #ccc; 3889 padding: 0 20px; 3890 box-sizing: border-box; 3891 height: 100%; 3892} 3893.px-mk-searchinfo .px-mk-searchinfo-inner i { 3894 color: goldenrod; 3895 margin-right: 10px; 3896 font-size: 20px; 3897} 3898.px-mk-searchinfo .px-mk-searchinfo-inner > .searchinfo-title { 3899 flex-grow: 0; 3900 background: #eee; 3901 color: #000; 3902} 3903.px-mk-searchinfo .px-mk-searchinfo-inner > .px-sm-searchbtn { 3904 width: auto; 3905 font-weight: 400; 3906 text-align: center; 3907 justify-content: center; 3908} 3909.px-mk-searchinfo .px-mk-searchinfo-inner.px-mk-searchinfo-column { 3910 height: auto; 3911 flex-wrap: wrap; 3912 width: 100%; 3913} 3914.px-mk-searchinfo .px-mk-searchinfo-inner.px-mk-searchinfo-column > * { 3915 height: 3em; 3916 border-bottom: 1px solid #ccc; 3917 padding: 1em; 3918 width: 50%; 3919 text-align: left; 3920 line-height: 1.2; 3921} 3922.px-mk-searchinfo .px-mk-searchinfo-inner.px-mk-searchinfo-column > * .px-mk-iconchangesearch { 3923 height: 1.2em; 3924 width: 1.2em; 3925} 3926 3927.px-mk-iconchangesearch { 3928 color: goldenrod; 3929 height: 1.5em; 3930 width: 1.5em; 3931 margin-right: 0.5em; 3932} 3933.px-mk-iconchangesearch svg { 3934 fill: currentColor; 3935 height: 100%; 3936 width: 100%; 3937} 3938 3939div.ui-datepicker#ui-datepicker-div .ui-widget-header { 3940 background: transparent !important; 3941 border: none !important; 3942} 3943div.ui-datepicker#ui-datepicker-div .ui-datepicker-next, 3944div.ui-datepicker#ui-datepicker-div .ui-datepicker-prev { 3945 border-radius: 40px !important; 3946 cursor: pointer !important; 3947} 3948div.ui-datepicker#ui-datepicker-div .ui-state-default, 3949div.ui-datepicker#ui-datepicker-div .ui-widget-content .ui-state-default, 3950div.ui-datepicker#ui-datepicker-div .ui-widget-header .ui-state-default { 3951 border-radius: 8px; 3952 border: none; 3953 background-color: rgba(0, 0, 0, 0.02); 3954 text-align: center; 3955 display: inline-flex; 3956 justify-content: center; 3957 align-items: center; 3958 width: 90%; 3959 font-size: 1em; 3960 transition: 0.3s ease-out; 3961 border: 1px solid #eee; 3962} 3963div.ui-datepicker#ui-datepicker-div .ui-state-focus, 3964div.ui-datepicker#ui-datepicker-div .ui-state-hover, 3965div.ui-datepicker#ui-datepicker-div .ui-widget-content .ui-state-focus, 3966div.ui-datepicker#ui-datepicker-div .ui-widget-content .ui-state-hover, 3967div.ui-datepicker#ui-datepicker-div .ui-widget-header .ui-state-focus, 3968div.ui-datepicker#ui-datepicker-div .ui-widget-header .ui-state-hover { 3969 background: white; 3970 border: 1px solid #000 !important; 3971} 3972div.ui-datepicker#ui-datepicker-div .ui-state-active, 3973div.ui-datepicker#ui-datepicker-div .ui-widget-content .ui-state-active, 3974div.ui-datepicker#ui-datepicker-div .ui-widget-header .ui-state-active, 3975div.ui-datepicker#ui-datepicker-div .ui-state-highlight, 3976div.ui-datepicker#ui-datepicker-div .ui-widget-content .ui-state-highlight, 3977div.ui-datepicker#ui-datepicker-div .ui-widget-header .ui-state-highlight { 3978 background: #000; 3979 color: white; 3980} 3981div.ui-datepicker#ui-datepicker-div td { 3982 text-align: center; 3983} 3984 3985.px-mk-searchloader { 3986 animation: spinStep steps(1) 1s infinite; 3987 height: 1em; 3988 width: 1em; 3989 transform-origin: top; 3990} 3991 3992.neo_m_buscador .neo_marketplace_buscador_v3 { 3993 padding: 30px 20px; 3994 justify-content: center; 3995 align-items: center; 3996} 3997 3998@keyframes spinStep { 3999 0% { 4000 transform: translatey(-50%); 4001 } 4002 12.5% { 4003 transform: rotate(45deg) translatey(-50%); 4004 } 4005 25% { 4006 transform: rotate(90deg) translatey(-50%); 4007 } 4008 37.5% { 4009 transform: rotate(135deg) translatey(-50%); 4010 } 4011 50% { 4012 transform: rotate(180deg) translatey(-50%); 4013 } 4014 62.5% { 4015 transform: rotate(225deg) translatey(-50%); 4016 } 4017 75% { 4018 transform: rotate(270deg) translatey(-50%); 4019 } 4020 87.5% { 4021 transform: rotate(315deg) translatey(-50%); 4022 } 4023 100% { 4024 transform: rotate(360deg) translatey(-50%); 4025 } 4026} 4027.px-sm-searchbtn { 4028 height: 100%; 4029 box-sizing: border-box; 4030 display: flex; 4031 text-align: left; 4032 align-items: flex-start; 4033 justify-content: center; 4034 text-transform: uppercase; 4035 font-size: 1em; 4036 letter-spacing: 1px; 4037 line-height: 1; 4038 background-color: #000; 4039 color: white; 4040 cursor: pointer; 4041 transition: 0.3s ease-out; 4042 border: none; 4043 width: 11em; 4044 padding: 1em 4em 1em 1em; 4045 flex: 1; 4046} 4047.px-sm-searchbtn .px-mk-inputicon svg { 4048 height: 1em; 4049 width: 1em; 4050 fill: white !important; 4051} 4052.px-sm-searchbtn:hover { 4053 background-color: #a37a00; 4054} 4055 4056.ModuloWrap_marketplace_list { 4057 width: 100%; 4058} 4059 4060.buscar_lp:not(.px-mk-buscador-vertical) .PartyTypeSimulator { 4061 height: 100%; 4062} 4063 4064.buscar_lp.px-mk-buscador-vertical { 4065 box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08); 4066 border-radius: 2px; 4067 padding: 0; 4068 margin: 3px; 4069 height: auto; 4070 width: auto; 4071} 4072.buscar_lp.px-mk-buscador-vertical .px-mk-searchform { 4073 transition: 1s cubic-bezier(0.17, 0.84, 0.44, 1); 4074 height: auto; 4075 width: 100%; 4076 flex-wrap: wrap; 4077} 4078.buscar_lp.px-mk-buscador-vertical .px-mk-searchform > * { 4079 width: 100%; 4080 height: 4.5em; 4081}
4082.buscar_lp.px-mk-buscador-vertical .px-mk-searchform .wrap_PartyTypeSimulator { 4083 height: auto; 4084 min-height: 4.5em; 4085 width: 50%; 4086 box-sizing: border-box; 4087} 4088.buscar_lp.px-mk-buscador-vertical .px-mk-searchform .wrap_PartyTypeSimulator .SelectorInitial { 4089 min-height: 4.5em; 4090 padding: 0.6em 1em; 4091} 4092.buscar_lp.px-mk-buscador-vertical .px-mk-searchform .wrap_PartyTypeSimulator .PartyTypeSimulatorSelect, 4093.buscar_lp.px-mk-buscador-vertical .px-mk-searchform .wrap_PartyTypeSimulator #MultiplePartySelect { 4094 position: static; 4095 background: rgba(248, 248, 248, 0.9725490196); 4096} 4097.buscar_lp.px-mk-buscador-vertical .px-sm-inputcontainer { 4098 border-bottom: 1px solid #ccc; 4099 border-right: none; 4100 max-width: none; 4101 width: 100%; 4102} 4103.buscar_lp.px-mk-buscador-vertical .px-sm-inputcontainer.fechas_ancho_entrada, .buscar_lp.px-mk-buscador-vertical .px-sm-inputcontainer.fechas_ancho_salida { 4104 width: 100%; 4105 box-sizing: border-box; 4106 margin: 0px; 4107} 4108.buscar_lp.px-mk-buscador-vertical .px-sm-inputcontainer.fechas_ancho_salida { 4109 border-left: 1px solid #ccc; 4110} 4111.buscar_lp.px-mk-buscador-vertical .px-sm-inputcontainer.px-mk-productidhidden { 4112 height: 0px; 4113 width: 100%; 4114} 4115.buscar_lp.px-mk-buscador-vertical .px-sm-inputcontainer input, 4116.buscar_lp.px-mk-buscador-vertical .px-sm-inputcontainer select, 4117.buscar_lp.px-mk-buscador-vertical .px-sm-inputcontainer textarea { 4118 max-width: 100%; 4119} 4120 4121.px-mk-filter-disabled { 4122 pointer-events: none !important; 4123 opacity: 0.5 !important; 4124} 4125 4126.px-mk-buscador-vertical.px-mk-searchform .px-sm-inputcontainer:last-child, 4127.px-mk-buscador-vertical .px-sm-inputcontainer:last-child { 4128 border-bottom: none; 4129 border-right: none; 4130} 4131 4132.px-mk-hidesearchform { 4133 opacity: 0; 4134 pointer-events: none; 4135 max-height: 0px; 4136 overflow: hidden; 4137} 4138 4139.ignoreclick { 4140 pointer-events: none; 4141} 4142 4143.px-sm-searchbtn > i { 4144 font-size: 20px; 4145 position: relative; 4146 left: 0; 4147 top: -1px; 4148 margin-right: 20px; 4149 margin-left: -10px; 4150} 4151 4152.btn-searching span { 4153 opacity: 0; 4154 max-width: 0px; 4155 overflow: hidden; 4156 transition: 0.3s ease-out; 4157} 4158 4159#ProductID option { 4160 text-transform: none; 4161} 4162 4163#ProductID option[value=everyproduct] { 4164 font-weight: 600; 4165} 4166 4167#ProductID option[value=""][disabled] { 4168 background-color: #eee; 4169 color: #555; 4170} 4171 4172.px-mk-disabled-temp { 4173 background-color: #eee; 4174 cursor: not-allowed; 4175 pointer-events: none; 4176 color: #bbb; 4177} 4178 4179.px-mk-productid.px-sm-inputcontainer.px-mk-productidhidden { 4180 opacity: 0; 4181 max-width: 0px; 4182 pointer-events: none; 4183 padding: 0px; 4184 margin: 0px; 4185 border: none; 4186} 4187 4188.px-mk-productid.px-sm-inputcontainer { 4189 max-width: 300px; 4190 transition: 0.3s ease; 4191 overflow: hidden; 4192} 4193 4194.px-mk-locationdropdown { 4195 position: absolute; 4196 top: calc(100% + 0.1em); 4197 left: 0; 4198 padding: 0; 4199 line-height: 1.2; 4200 background: white; 4201 box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08); 4202 z-index: 999; 4203 border-radius: 0 0 4px 4px; 4204 max-height: 50vh; 4205 overflow: auto; 4206 transition: 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); 4207 opacity: 0; 4208 pointer-events: none; 4209 transform: translateY(-1em); 4210 width: 100%; 4211} 4212.px-mk-locationdropdown.activeAC { 4213 transform: none; 4214 pointer-events: initial; 4215 opacity: 1; 4216} 4217.px-mk-locationdropdown > * { 4218 padding: 1.2em 1.5em; 4219 white-space: nowrap; 4220 max-width: 400px; 4221 overflow: hidden; 4222 text-overflow: ellipsis; 4223 width: 100%; 4224 cursor: pointer; 4225 display: flex; 4226 align-items: center; 4227 justify-content: flex-start; 4228 box-sizing: border-box; 4229} 4230.px-mk-locationdropdown > *.suggestion_hover { 4231 background-color: #f2f2f2; 4232} 4233.px-mk-locationdropdown > *:hover { 4234 background-color: #f2f2f2; 4235} 4236.px-mk-locationdropdown > *:hover .px-mk-locationimg { 4237 fill: goldenrod; 4238} 4239.px-mk-locationdropdown > * .px-mk-locationtxt { 4240 width: 100%; 4241 overflow: hidden; 4242 text-overflow: ellipsis; 4243} 4244.px-mk-locationdropdown > * .px-mk-locationimg { 4245 height: 1.1em; 4246 width: 1.1em; 4247 margin-right: 0.6em; 4248 flex-shrink: 0; 4249 fill: #aaa; 4250 margin-right: 0.8em; 4251} 4252.px-mk-locationdropdown > * .px-mk-locationimg svg { 4253 height: 100%; 4254 width: 100%; 4255 -o-object-fit: contain; 4256 object-fit: contain; 4257} 4258 4259.px-mk-locationautocomplete { 4260 height: 100%; 4261 width: 100%; 4262 box-sizing: border-box; 4263 padding-right: 2em; 4264} 4265.px-mk-locationautocomplete input { 4266 height: 100%; 4267 padding: 0em 1em; 4268 width: 100%; 4269} 4270 4271.ui-datepicker { 4272 font-size: 16px !important; 4273 box-shadow: 0 2px 20px rgba(0, 0, 0, 0.2); 4274 width: auto; 4275 border-radius: 0px !important; 4276 padding: 5px !important; 4277 width: auto !important; 4278 box-sizing: border-box; 4279} 4280 4281.ui-datepicker td { 4282 margin: 0px !important; 4283 padding: 0px; 4284} 4285 4286.ui-datepicker td > * { 4287 height: 40px; 4288 width: 40px !important; 4289 border-radius: 0px !important; 4290 border: 1px solid transparent !important; 4291 box-sizing: border-box; 4292} 4293 4294.ui-datepicker table { 4295 margin: 0px !important; 4296} 4297 4298.neo_marketplace_buscador_v3 * { 4299 font-size: 13px !important; 4300} 4301 4302.neo_marketplace_buscador_v3 input, .neo_marketplace_buscador_v3 select { 4303 font-size: 16px !important; 4304} 4305 4306.neo_modules_cart_hotel_v2 .cart_top_hotel_v2 .PartyTypeSimulator { 4307 width: 100%; 4308} 4309 4310.neo_marketplace_buscador_v3 .PartyTypeSimulatorSelect { 4311 position: absolute; 4312 z-index: 999; 4313 top: 55px; 4314 left: 0px; 4315 padding: 5px; 4316 background: #fff; 4317 margin: 0px; 4318 box-shadow: 0 2px 16px rgba(0, 0, 0, 0.15); 4319 padding: 20px 25px; 4320 line-height: 1.5; 4321 box-sizing: border-box; 4322 width: 300px; 4323 max-width: 100vw; 4324} 4325 4326.txtPartyGroup { 4327 white-space: nowrap; 4328 overflow: hidden; 4329 text-overflow: ellipsis; 4330 margin-right: auto; 4331 padding-right: 30px; 4332} 4333 4334input.neo_partyselector_quantity { 4335 padding: 15px 10px; 4336 font-size: 18px; 4337 text-align: center; 4338 border: none; 4339 background: transparent; 4340 width: 60px; 4341 -moz-appearance: textfield; 4342} 4343input.neo_partyselector_quantity::-webkit-outer-spin-button, 4344input.neo_partyselector_quantity::-webkit-inner-spin-button { 4345 -webkit-appearance: none; 4346 margin: 0; 4347} 4348input.neo_partyselector_quantity:focus { 4349 outline: none; 4350 background-color: rgba(0, 0, 0, 0.03); 4351 border-radius: 5px; 4352} 4353 4354.ChildrensAges { 4355 max-height: 180px; 4356 overflow-y: auto; 4357 overflow-x: hidden; 4358 padding-right: 5px; 4359} 4360.ChildrensAges::-webkit-scrollbar {
4361 width: 6px; 4362} 4363.ChildrensAges::-webkit-scrollbar-track { 4364 background: #f1f1f1; 4365 border-radius: 10px; 4366} 4367.ChildrensAges::-webkit-scrollbar-thumb { 4368 background: #888; 4369 border-radius: 10px; 4370} 4371.ChildrensAges::-webkit-scrollbar-thumb:hover { 4372 background: #555; 4373} 4374 4375@media only screen and (max-width: 650px) { 4376 .PartyTypeSimulatorContainer { 4377 height: auto !important; 4378 } 4379 .PartyTypeSimulatorContainer .PartyTypeSimulatorSelect { 4380 position: static !important; 4381 width: 100%; 4382 } 4383 .px-mk-locationdropdown { 4384 width: 100%; 4385 box-shadow: 0 4px 9px rgba(0, 0, 0, 0.5); 4386 } 4387 .neo_marketplace_buscador_v3 * { 4388 font-size: 15px !important; 4389 } 4390 .neo_marketplace_buscador_v3 input, .neo_marketplace_buscador_v3 select { 4391 font-size: 16px !important; 4392 } 4393 .neo_marketplace_buscador_v3 { 4394 width: 100%; 4395 display: flex; 4396 } 4397 .ui-datepicker { 4398 font-size: 19px !important; 4399 z-index: 1000 !important; 4400 width: calc(100vw - 30px) !important; 4401 left: 10px !important; 4402 box-shadow: 0 2px 20px rgba(0, 0, 0, 0.5); 4403 padding: 10px !important; 4404 box-sizing: border-box; 4405 } 4406 4407 /* Ajustes para el selector de party en mobile */ 4408 .neo_marketplace_buscador_v3 .txtPartyGroup, 4409 .PartyTypeSimulator .txtPartyGroup, 4410 .SelectorInitial .txtPartyGroup { 4411 white-space: normal !important; 4412 overflow: visible !important; 4413 text-overflow: clip !important; 4414 padding-right: 10px !important; 4415 font-size: 10px !important; 4416 line-height: 1.4 !important; 4417 display: flex !important; 4418 flex-wrap: wrap !important; 4419 align-items: center !important; 4420 gap: 2px !important; 4421 max-width: calc(100% - 40px) !important; 4422 } 4423 4424 .neo_marketplace_buscador_v3 .txtPartyGroup span, 4425 .PartyTypeSimulator .txtPartyGroup span, 4426 .SelectorInitial .txtPartyGroup span { 4427 white-space: nowrap !important; 4428 font-size: 15px !important; 4429 } 4430 4431 .neo_marketplace_buscador_v3 .txtPartyGroup .mdi-circle-small, 4432 .PartyTypeSimulator .txtPartyGroup .mdi-circle-small, 4433 .SelectorInitial .txtPartyGroup .mdi-circle-small { 4434 font-size: 12px !important; 4435 margin: 0 -3px !important; 4436 } 4437 4438 .neo_marketplace_buscador_v3 .SelectorInitial, 4439 .PartyTypeSimulator .SelectorInitial { 4440 min-height: 55px !important; 4441 padding: 8px 40px 8px 10px !important; 4442 display: flex !important; 4443 align-items: center !important; 4444 } 4445 4446 .neo_marketplace_buscador_v3 .PartyTypeSimulatorContainer, 4447 .PartyTypeSimulatorContainer { 4448 overflow: visible !important; 4449 } 4450 4451 .px-mk-buscador-container { 4452 font-size: 16px; 4453 } 4454 .px-mk-buscador-container select, 4455 .px-mk-buscador-container textarea, 4456 .px-mk-buscador-container input[type=text], 4457 .px-mk-buscador-container input[type=password], 4458 .px-mk-buscador-container input[type=datetime], 4459 .px-mk-buscador-container input[type=datetime-local], 4460 .px-mk-buscador-container input[type=date], 4461 .px-mk-buscador-container input[type=month], 4462 .px-mk-buscador-container input[type=time], 4463 .px-mk-buscador-container input[type=week], 4464 .px-mk-buscador-container input[type=number], 4465 .px-mk-buscador-container input[type=email], 4466 .px-mk-buscador-container input[type=url], 4467 .px-mk-buscador-container input[type=search], 4468 .px-mk-buscador-container input[type=tel], 4469 .px-mk-buscador-container input[type=color] { 4470 font-size: 1em; 4471 } 4472}/*# sourceMappingURL=css.css.map */</style>
4473<script> 4474 (function() { 4475 function run() { 4476 try { 4477 var span = document.querySelector('#PxMkAcion_Search .update-search-span'); 4478 var btn = document.getElementById('PxMkAcion_Search'); 4479 if (!span) return; 4480 4481 var themeHex = '#b29e73'; 4482 4483 function parseHex(hex) { 4484 if (!hex) return null; 4485 hex = String(hex).trim(); 4486 if (hex.startsWith('#')) hex = hex.slice(1); 4487 if (hex.length === 3) { 4488 hex = hex.split('').map(function(ch) { 4489 return ch + ch; 4490 }).join(''); 4491 } 4492 if (hex.length !== 6) return null; 4493 var r = parseInt(hex.slice(0, 2), 16); 4494 var g = parseInt(hex.slice(2, 4), 16); 4495 var b = parseInt(hex.slice(4, 6), 16); 4496 if ([r, g, b].some(function(v) { 4497 return isNaN(v); 4498 })) return null; 4499 return { 4500 r: r, 4501 g: g, 4502 b: b 4503 }; 4504 } 4505 4506 function relL(rgb) { 4507 function toLin(c) { 4508 c = c / 255; 4509 return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); 4510 } 4511 var R = toLin(rgb.r), 4512 G = toLin(rgb.g), 4513 B = toLin(rgb.b); 4514 return 0.2126 * R + 0.7152 * G + 0.0722 * B; 4515 } 4516 4517 function contrast(L1, L2) { 4518 var a = Math.max(L1, L2); 4519 var b = Math.min(L1, L2); 4520 return (a + 0.05) / (b + 0.05); 4521 } 4522 4523 var rgb = parseHex(themeHex); 4524 if (!rgb) { 4525 if (btn) { 4526 var bg = window.getComputedStyle(btn).backgroundColor; // rgb(a) 4527 var m = bg && bg.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/i); 4528 if (m) { 4529 rgb = { 4530 r: parseInt(m[1], 10), 4531 g: parseInt(m[2], 10), 4532 b: parseInt(m[3], 10) 4533 }; 4534 } 4535 } 4536 } 4537 if (!rgb) return; 4538 4539 var Lbg = relL(rgb); 4540 var Lwhite = relL({ 4541 r: 255, 4542 g: 255, 4543 b: 255 4544 }); 4545 var Lblack = relL({ 4546 r: 0, 4547 g: 0, 4548 b: 0 4549 }); 4550 var cWhite = contrast(Lbg, Lwhite); 4551 var cBlack = contrast(Lbg, Lblack); 4552 4553 var textColor = cBlack >= cWhite ? '#000000' : '#FFFFFF'; 4554 span.style.setProperty('color', textColor, 'important'); 4555 if (btn) { 4556 btn.style.setProperty('color', textColor, 'important'); 4557 4558 // Recolor inline SVG icons (search and loading) to match the contrast color 4559 function paintInlineSVG(container, color) { 4560 try { 4561 var svgs = container.querySelectorAll('svg'); 4562 svgs.forEach(function(svg) { 4563 // Support SVGs that use currentColor 4564 svg.style.setProperty('color', color, 'important'); 4565 svg.setAttribute('color', color); 4566 // Force fill/stroke via style to override inline attrs 4567 svg.style.setProperty('fill', color, 'important'); 4568 svg.style.setProperty('stroke', color, 'important'); 4569 // Update common shape elements 4570 svg.querySelectorAll('path, circle, rect, polygon, line, polyline, ellipse, g').forEach(function(node) { 4571 node.style.setProperty('fill', color, 'important'); 4572 node.style.setProperty('stroke', color, 'important'); 4573 }); 4574 // Also override attributes for stubborn icons 4575 svg.querySelectorAll('[fill]').forEach(function(node) { 4576 node.setAttribute('fill', color); 4577 }); 4578 svg.querySelectorAll('[stroke]').forEach(function(node) { 4579 node.setAttribute('stroke', color); 4580 }); 4581 }); 4582 } catch (e) { 4583 /* ignore */ 4584 } 4585 } 4586 4587 var iconLabel = btn.querySelector('.px-mk-searchicon'); 4588 var loaderLabel = btn.querySelector('.px-mk-searchloader'); 4589 if (iconLabel) paintInlineSVG(iconLabel, textColor); 4590 if (loaderLabel) paintInlineSVG(loaderLabel, textColor); 4591 } 4592 } catch (e) { 4593 /* ignore */ 4594 } 4595 } 4596 4597 if (document.readyState === 'loading') { 4598 document.addEventListener('DOMContentLoaded', run); 4599 } else { 4600 run(); 4601 } 4602 })(); 4603</script>
4603 4604
4604<script> 4605 if (localStorage.getItem('tradename')) { 4606 localStorage.removeItem('tradename'); 4607 } 4608 </script>
4608 4609 4610<!-- Scripts para el mapa -->
4611<script src="https://unpkg.com/[email protected]/dist/leaflet.js" integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==" crossorigin=""></script>
vendor: 1 bytes, line 4611
4611
4612<script> 4613 (function() { 4614 // Desactivar logs dentro de este módulo (solo en este scope) 4615 var console = { 4616 log: function() {}, 4617 warn: function() {}, 4618 error: function() {} 4619 }; 4620 // Variables para el mapa 4621 let map; 4622 let marker; 4623 let selectedLat = 0; 4624 let selectedLng = 0; 4625 let radiusCircle; // Variable para el cÃrculo del radio 4626 const defaultZoom = 13; 4627 // Coordenadas por defecto: Mendoza, Argentina 4628 const DEFAULT_LAT = -32.889458; 4629 const DEFAULT_LNG = -68.845839; 4630 const DEFAULT_RADIUS = 50000; // 50km en metros 4631 4632 // Elementos del DOM 4633 const mapModal = document.getElementById('map-modal'); 4634 const mapBtn = document.getElementById('map-search-btn'); 4635 const closeBtn = document.querySelector('.map-close'); 4636 const confirmBtn = document.getElementById('confirm-location'); 4637 const enableLocationGuideBtn = document.getElementById('enable-location-guide'); 4638 const centerLocationBtn = document.getElementById('center-location'); 4639 const locationPermissionsGuide = document.getElementById('location-permissions-guide'); 4640 const browserGuideContent = document.getElementById('browser-guide-content'); 4641 const closeGuideBtn = document.getElementById('close-guide'); 4642 const latitudeInput = document.getElementById('webroot_latitude'); 4643 const longitudeInput = document.getElementById('webroot_longitude'); 4644 const radiusInput = document.getElementById('webroot_distance_radius'); 4645 const locationInput = document.getElementById('webroot_location_search'); 4646 const locationGoogleSearch = document.getElementById('location_google_search'); 4647 4648 // Variables para rastrear estado de permisos 4649 let locationPermissionsDenied = false; 4650 let locationPermissionsEnabled = false; 4651 4652 // Función para detectar el navegador 4653 function detectBrowser() { 4654 const userAgent = navigator.userAgent.toLowerCase(); 4655 if (userAgent.includes('chrome') && !userAgent.includes('edg')) return 'chrome'; 4656 if (userAgent.includes('firefox')) return 'firefox'; 4657 if (userAgent.includes('safari') && !userAgent.includes('chrome')) return 'safari'; 4658 if (userAgent.includes('edg')) return 'edge'; 4659 return 'chrome'; 4660 } 4661 4662 // Función para obtener el contenido de la guÃa según el navegador 4663 function getBrowserGuideContent(browser) { 4664 const guides = { 4665 chrome: { 4666 title: 'Google Chrome', 4667 steps: [ 4668 'Haz clic en el icono de candado en la barra de direcciones', 4669 'Selecciona "Configuración del sitio" o "Permisos"', 4670 'Cambia "Ubicación" de "Bloquear" a "Permitir"', 4671 'Recarga la página' 4672 ], 4673 link: 'https://support.google.com/chrome/answer/142065' 4674 }, 4675 firefox: { 4676 title: 'Mozilla Firefox', 4677 steps: [ 4678 'Haz clic en el icono de escudo en la barra de direcciones', 4679 'Selecciona "Configuración mejorada de seguimiento"', 4680 'Habilita los permisos de ubicación para este sitio', 4681 'Recarga la página' 4682 ], 4683 link: 'https://support.mozilla.org/es/kb/compartir-ubicacion-con-sitios-web' 4684 }, 4685 safari: { 4686 title: 'Safari', 4687 steps: [ 4688 'Ve a Safari > Preferencias > Sitios web', 4689 'Selecciona "Ubicación" en la barra lateral', 4690 'Encuentra este sitio y cambia a "Permitir"', 4691 'Recarga la página' 4692 ], 4693 link: 'https://support.apple.com/es-es/guide/safari/ibrw1056/mac' 4694 }, 4695 edge: { 4696 title: 'Microsoft Edge', 4697 steps: [ 4698 'Haz clic en el icono de candado en la barra de direcciones', 4699 'Selecciona "Permisos para este sitio"', 4700 'Cambia "Ubicación" a "Permitir"', 4701 'Recarga la página' 4702 ], 4703 link: 'https://support.microsoft.com/es-es/microsoft-edge/ubicaci%C3%B3n-y-privacidad-en-microsoft-edge-31b5d9e7-bb24-43a0-8b0e-d9f4b38f6cf5' 4704 } 4705 }; 4706 return guides[browser] || guides.chrome; 4707 } 4708 4709 // Función para mostrar la guÃa de permisos 4710 function showLocationPermissionsGuide() { 4711 const browser = detectBrowser(); 4712 const guide = getBrowserGuideContent(browser); 4713 4714 let content = ` 4715 <div style="margin: 10px 0; padding: 15px; background: white; border-radius: 6px; border: 1px solid #e5e7eb;"> 4716 <h5 style="margin: 0 0 8px 0; color: #374151; font-size: 16px; font-weight: 600;">Instrucciones para ${guide.title}</h5> 4717 <p style="margin: 0 0 12px 0; color: #6b7280; font-size: 13px;">Sigue estos pasos para habilitar los permisos:</p> 4718 <ol style="margin: 8px 0 8px 20px; padding: 0;"> 4719 `; 4720 4721 guide.steps.forEach(step => { 4722 content += `<li style="margin: 6px 0; font-size: 14px; color: #4b5563;">${step}</li>`; 4723 }); 4724 4725 content += ` 4726 </ol> 4727 <a href="${guide.link}" target="_blank" style="display: inline-block; margin-top: 10px; color: #3b82f6; text-decoration: none; font-size: 13px;"> 4728 Ver guÃa oficial de ${guide.title} â 4729 </a> 4730 </div> 4731 `; 4732 4733 if (browserGuideContent) { 4734 browserGuideContent.innerHTML = content; 4735 } 4736 4737 if (locationPermissionsGuide) { 4738 locationPermissionsGuide.style.display = 'block'; 4739 } 4740 } 4741 4742 // Función para ocultar la guÃa de permisos 4743 function hideLocationPermissionsGuide() { 4744 if (locationPermissionsGuide) { 4745 locationPermissionsGuide.style.display = 'none'; 4746 } 4747 } 4748 4749 // Función para centrar el mapa en la ubicación actual 4750 function centerMapOnCurrentLocation() { 4751 if (!navigator.geolocation) { 4752 alert('Tu navegador no soporta geolocalización.'); 4753 return; 4754 } 4755 4756 // Mostrar loader en el botón centrar 4757 if (centerLocationBtn) { 4758 const loader = centerLocationBtn.querySelector('.center-btn-loader'); 4759 const text = centerLocationBtn.querySelector('.center-btn-text'); 4760 if (loader && text) { 4761 loader.style.display = 'inline-block'; 4762 text.style.display = 'none'; 4763 } 4764 centerLocationBtn.disabled = true; 4765 } 4766 4767 navigator.geolocation.getCurrentPosition( 4768 async function(position) { 4769 const lat = position.coords.latitude; 4770 const lng = position.coords.longitude; 4771 4772 // Centrar el mapa en la nueva ubicación 4773 if (map) {
4774 map.setView([lat, lng], defaultZoom); 4775 4776 // Remover marcador anterior si existe 4777 if (marker) { 4778 map.removeLayer(marker); 4779 } 4780 4781 // Añadir nuevo marcador 4782 marker = L.marker([lat, lng], { 4783 draggable: true 4784 }).addTo(map); 4785 4786 // Actualizar posición del cÃrculo 4787 if (radiusCircle) { 4788 radiusCircle.setLatLng([lat, lng]); 4789 } else { 4790 // Si por alguna razón no existe, crearlo 4791 const radiusSelect = document.getElementById('radius-select'); 4792 const currentRadius = radiusSelect ? parseInt(radiusSelect.value) : DEFAULT_RADIUS; 4793 radiusCircle = L.circle([lat, lng], { 4794 color: '#3388ff', 4795 fillColor: '#3388ff', 4796 fillOpacity: 0.2, 4797 radius: currentRadius 4798 }).addTo(map); 4799 } 4800 4801 // Actualizar coordenadas seleccionadas 4802 selectedLat = lat; 4803 selectedLng = lng; 4804 4805 // Obtener información de ubicación para el marcador 4806 try { 4807 const locationName = await getAddressFromCoordinates(lat, lng); 4808 if (locationName && !locationName.includes(lat.toString())) { 4809 marker.bindPopup(locationName).openPopup(); 4810 } 4811 } catch (error) { 4812 console.log('â ï¸ No se pudo obtener información de ubicación para el marcador'); 4813 } 4814 4815 // Actualizar coordenadas al arrastrar el marcador 4816 marker.on('dragend', async function(e) { 4817 const position = marker.getLatLng(); 4818 selectedLat = position.lat; 4819 selectedLng = position.lng; 4820 4821 // Actualizar posición del cÃrculo 4822 if (radiusCircle) { 4823 radiusCircle.setLatLng(position); 4824 } 4825 4826 // Actualizar popup al arrastrar 4827 try { 4828 const newLocationName = await getAddressFromCoordinates(selectedLat, selectedLng); 4829 if (newLocationName && !newLocationName.includes(selectedLat.toString())) { 4830 marker.setPopupContent(newLocationName); 4831 } 4832 } catch (error) { 4833 console.log('â ï¸ No se pudo actualizar información al arrastrar'); 4834 } 4835 }); 4836 4837 // Actualizar coordenadas al arrastrar el marcador 4838 marker.on('dragend', async function(e) { 4839 const position = marker.getLatLng(); 4840 selectedLat = position.lat; 4841 selectedLng = position.lng; 4842 4843 // Actualizar popup al arrastrar 4844 try { 4845 const newLocationName = await getAddressFromCoordinates(selectedLat, selectedLng); 4846 if (newLocationName && !newLocationName.includes(selectedLat.toString())) { 4847 marker.setPopupContent(newLocationName); 4848 } 4849 } catch (error) { 4850 console.log('â ï¸ No se pudo actualizar información al arrastrar'); 4851 } 4852 }); 4853 } 4854 4855 // Ocultar loader del botón 4856 if (centerLocationBtn) { 4857 const loader = centerLocationBtn.querySelector('.center-btn-loader'); 4858 const text = centerLocationBtn.querySelector('.center-btn-text'); 4859 if (loader && text) { 4860 loader.style.display = 'none'; 4861 text.style.display = 'inline-block'; 4862 } 4863 centerLocationBtn.disabled = false; 4864 } 4865 }, 4866 function(error) { 4867 console.log('Error al obtener ubicación actual:', error); 4868 alert('No se pudo obtener tu ubicación actual. Verifica que los permisos estén habilitados.'); 4869 4870 // Ocultar loader del botón 4871 if (centerLocationBtn) { 4872 const loader = centerLocationBtn.querySelector('.center-btn-loader'); 4873 const text = centerLocationBtn.querySelector('.center-btn-text'); 4874 if (loader && text) { 4875 loader.style.display = 'none'; 4876 text.style.display = 'inline-block'; 4877 } 4878 centerLocationBtn.disabled = false; 4879 } 4880 } 4881 ); 4882 } 4883 4884 console.log('Botón de mapa:', mapBtn); // Debug para verificar que el botón existe 4885 4886 // Asegurar que el modal existe en el DOM 4887 if (!mapModal) { 4888 console.error('Modal de mapa no encontrado en el DOM'); 4889 // Añadir el modal al final del body si no existe 4890 const modalHTML = ` 4891 <div id="map-modal" class="map-modal"> 4892 <div class="map-modal-content"> 4893 <span class="map-close">×</span> 4894 <h3>Selecciona una ubicación en el mapa</h3> 4895 <div id="map-container"></div> 4896 <div class="map-footer">
4897 <div class="map-footer-controls"> 4898 <button id="center-location" style="display: none; padding: 6px 12px; color: white; background-color: #10b981; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; margin-right: 10px;"> 4899 <span class="center-btn-loader" style="display: none; width: 12px; height: 12px; border: 2px solid rgba(255, 255, 255, 0.3); border-radius: 50%; border-top-color: white; animation: spin 1s ease-in-out infinite; margin-right: 6px;"></span> 4900 <span class="center-btn-text">Localizarme</span> 4901 </button> 4902 <div class="radius-selector"> 4903 <label for="radius-select" style="margin-right: 5px; font-weight: bold;">Radio:</label> 4904 <select id="radius-select" style="padding: 8px; border-radius: 4px; border: 1px solid #ccc;"> 4905 <option value="10000">10 km</option> 4906 <option value="30000">30 km</option> 4907 <option value="50000" selected>50 km</option> 4908 <option value="100000">100 km</option> 4909 </select> 4910 </div> 4911 </div> 4912 <button id="confirm-location" class="neo_bgcolor_primary"> 4913 <span class="btn-loader"></span> 4914 <span class="btn-text">Buscar en esta zona</span> 4915 </button> 4916 </div> 4917 </div> 4918 </div> 4919 `; 4920 document.body.insertAdjacentHTML('beforeend', modalHTML); 4921 } 4922 4923 // Función para inicializar el mapa 4924 function initMap(lat, lng) { 4925 // Limpiar mapa existente de manera segura 4926 if (map) { 4927 try { 4928 map.remove(); 4929 } catch (e) { 4930 console.log('Error al remover mapa:', e); 4931 } 4932 map = null; 4933 } 4934 4935 // Reset marker 4936 marker = null; 4937 4938 // Coordenadas por defecto (si no hay seleccionadas): Mendoza 4939 lat = (typeof lat === 'number' ? lat : null) ?? DEFAULT_LAT; 4940 lng = (typeof lng === 'number' ? lng : null) ?? DEFAULT_LNG; 4941 4942 // Crear mapa con un timeout para asegurar que el contenedor está visible 4943 setTimeout(() => { 4944 try { 4945 // Verificar que el contenedor principal existe 4946 const mapContainer = document.getElementById('map-container'); 4947 if (!mapContainer) { 4948 console.error('Contenedor del mapa no encontrado'); 4949 return; 4950 } 4951 4952 // Crear un nuevo contenedor para evitar el error de "already initialized" 4953 const mapId = 'map-instance-' + Date.now(); 4954 mapContainer.innerHTML = `<div id="${mapId}" style="height: 100%; width: 100%;"></div>`; 4955 4956 // Crear el mapa en el nuevo contenedor 4957 map = L.map(mapId, { 4958 scrollWheelZoom: true 4959 }).setView([lat, lng], defaultZoom); 4960 4961 // Invalidar tamaño inmediatamente para asegurar renderizado correcto 4962 map.invalidateSize(); 4963 4964 // Añadir capa de mapa base (OpenStreetMap) 4965 L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { 4966 attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' 4967 }).addTo(map); 4968 4969 // Añadir marcador SIEMPRE (incluido Mendoza por defecto) y preparar comportamiento 4970 marker = L.marker([lat, lng], { 4971 draggable: true 4972 }).addTo(map); 4973 4974 // Dibujar cÃrculo de radio inicial 4975 const radiusSelect = document.getElementById('radius-select'); 4976 const initialRadius = radiusSelect ? parseInt(radiusSelect.value) : DEFAULT_RADIUS; 4977 4978 radiusCircle = L.circle([lat, lng], { 4979 color: '#3388ff', 4980 fillColor: '#3388ff', 4981 fillOpacity: 0.2, 4982 radius: initialRadius 4983 }).addTo(map); 4984 4985 // Evento para actualizar el radio cuando cambia el select 4986 if (radiusSelect) { 4987 // Remover listeners anteriores para evitar duplicados 4988 const newRadiusSelect = radiusSelect.cloneNode(true); 4989 radiusSelect.parentNode.replaceChild(newRadiusSelect, radiusSelect); 4990 4991 newRadiusSelect.addEventListener('change', function() { 4992 const newRadius = parseInt(this.value); 4993 if (radiusCircle) { 4994 radiusCircle.setRadius(newRadius); 4995 } 4996 }); 4997 } 4998 4999 // Obtener información de ubicación para el marcador inicial 5000 (async () => { 5001 try { 5002 const locationName = await getAddressFromCoordinates(lat, lng); 5003 if (locationName && !locationName.includes(lat.toString())) { 5004 marker.bindPopup(locationName);
5005 console.log('ð Información inicial del marcador:', locationName); 5006 } 5007 } catch (error) { 5008 console.log('â ï¸ No se pudo obtener información inicial del marcador'); 5009 } 5010 })(); 5011 5012 // Actualizar coordenadas al arrastrar el marcador 5013 marker.on('dragend', async function(e) { 5014 const position = marker.getLatLng(); 5015 selectedLat = position.lat; 5016 selectedLng = position.lng; 5017 5018 // Actualizar posición del cÃrculo 5019 if (radiusCircle) { 5020 radiusCircle.setLatLng(position); 5021 } 5022 5023 // Actualizar popup al arrastrar 5024 try { 5025 const newLocationName = await getAddressFromCoordinates(selectedLat, selectedLng); 5026 if (newLocationName && !newLocationName.includes(selectedLat.toString())) { 5027 marker.setPopupContent(newLocationName); 5028 } 5029 } catch (error) { 5030 console.log('â ï¸ No se pudo actualizar información al arrastrar'); 5031 } 5032 }); 5033 5034 selectedLat = lat; 5035 selectedLng = lng; 5036 5037 // Añadir evento de clic al mapa 5038 map.on('click', async function(e) { 5039 // Si ya existe un marcador, lo eliminamos 5040 if (marker) { 5041 map.removeLayer(marker); 5042 } 5043 5044 // Añadir nuevo marcador en la posición del clic 5045 marker = L.marker(e.latlng, { 5046 draggable: true 5047 }).addTo(map); 5048 5049 // Actualizar posición del cÃrculo 5050 if (radiusCircle) { 5051 radiusCircle.setLatLng(e.latlng); 5052 } else { 5053 // Si por alguna razón no existe, crearlo 5054 const radiusSelect = document.getElementById('radius-select'); 5055 const currentRadius = radiusSelect ? parseInt(radiusSelect.value) : DEFAULT_RADIUS; 5056 radiusCircle = L.circle(e.latlng, { 5057 color: '#3388ff', 5058 fillColor: '#3388ff', 5059 fillOpacity: 0.2, 5060 radius: currentRadius 5061 }).addTo(map); 5062 } 5063 5064 // Guardar coordenadas seleccionadas 5065 selectedLat = e.latlng.lat; 5066 selectedLng = e.latlng.lng; 5067 5068 // Intentar obtener y mostrar información de ubicación en el marcador 5069 try { 5070 const locationName = await getAddressFromCoordinates(selectedLat, selectedLng); 5071 if (locationName && !locationName.includes(selectedLat.toString())) { 5072 marker.bindPopup(locationName).openPopup(); 5073 console.log('ð Información del marcador establecida:', locationName); 5074 } 5075 } catch (error) { 5076 console.log('â ï¸ No se pudo obtener información de ubicación para el marcador'); 5077 } 5078 5079 // Actualizar coordenadas al arrastrar el marcador 5080 marker.on('dragend', async function(e) { 5081 const position = marker.getLatLng(); 5082 selectedLat = position.lat; 5083 selectedLng = position.lng; 5084 5085 // Actualizar posición del cÃrculo 5086 if (radiusCircle) { 5087 radiusCircle.setLatLng(position); 5088 } 5089 5090 // Actualizar popup al arrastrar 5091 try { 5092 const newLocationName = await getAddressFromCoordinates(selectedLat, selectedLng); 5093 if (newLocationName && !newLocationName.includes(selectedLat.toString())) { 5094 marker.setPopupContent(newLocationName); 5095 } 5096 } catch (error) { 5097 console.log('â ï¸ No se pudo actualizar información al arrastrar'); 5098 } 5099 }); 5100 }); 5101 5102 // Invalidar tamaño para asegurar que se renderiza correctamente 5103 setTimeout(() => { 5104 if (map) { 5105 map.invalidateSize(); 5106 } 5107 }, 100); 5108 // Segundo intento para móviles lentos 5109 setTimeout(() => { 5110 if (map) { 5111 map.invalidateSize(); 5112 } 5113 }, 500); 5114 } catch (e) { 5115 console.error('Error al inicializar el mapa:', e); 5116 } 5117 }, 500); // Aumentar timeout para dar más tiempo al modal 5118 } 5119 5120 // Evento clic en botón de mapa (consolidado en un único listener) 5121 if (mapBtn) { 5122 console.log('Asignando evento click al botón de mapa'); 5123 5124 function openMapModalHandler(e) { 5125 console.log('Botón de mapa clickeado'); 5126 e.preventDefault(); 5127 e.stopPropagation(); 5128 mapModal.style.display = 'flex'; 5129 5130 // Resetear estado de permisos y ocultar elementos al abrir el modal 5131 locationPermissionsDenied = false;
5132 locationPermissionsEnabled = false; 5133 if (enableLocationGuideBtn) enableLocationGuideBtn.style.display = 'none'; 5134 if (centerLocationBtn) centerLocationBtn.style.display = 'none'; 5135 hideLocationPermissionsGuide(); 5136 5137 // Si ya hay coordenadas guardadas, las usamos 5138 const currentLat = latitudeInput.value ? parseFloat(latitudeInput.value) : null; 5139 const currentLng = longitudeInput.value ? parseFloat(longitudeInput.value) : null; 5140 5141 if (currentLat && currentLng) { 5142 initMap(currentLat, currentLng); 5143 } else { 5144 // Inicializar inmediatamente con Mendoza para evitar mapa en blanco 5145 initMap(DEFAULT_LAT, DEFAULT_LNG); 5146 5147 // Mostrar botón de centrar si la geolocalización está disponible en el navegador 5148 if (navigator.geolocation) { 5149 if (centerLocationBtn) centerLocationBtn.style.display = 'inline-block'; 5150 } 5151 } 5152 return false; 5153 } 5154 5155 // Agregar un único listener 5156 mapBtn.addEventListener('click', openMapModalHandler); 5157 } else { 5158 console.error('El botón de mapa no se encontró en el DOM'); 5159 } 5160 5161 // Event listeners para los botones de la guÃa 5162 if (enableLocationGuideBtn) { 5163 enableLocationGuideBtn.addEventListener('click', function() { 5164 showLocationPermissionsGuide(); 5165 }); 5166 } 5167 5168 if (closeGuideBtn) { 5169 closeGuideBtn.addEventListener('click', function() { 5170 hideLocationPermissionsGuide(); 5171 }); 5172 } 5173 5174 // Event listener para el botón "Centrar" 5175 if (centerLocationBtn) { 5176 centerLocationBtn.addEventListener('click', function() { 5177 centerMapOnCurrentLocation(); 5178 }); 5179 } 5180 5181 // Cerrar modal 5182 if (closeBtn) { 5183 closeBtn.addEventListener('click', function() { 5184 mapModal.style.display = 'none'; 5185 // Resetear estado al cerrar 5186 locationPermissionsDenied = false; 5187 locationPermissionsEnabled = false; 5188 if (enableLocationGuideBtn) enableLocationGuideBtn.style.display = 'none'; 5189 if (centerLocationBtn) centerLocationBtn.style.display = 'none'; 5190 hideLocationPermissionsGuide(); 5191 // Limpiar mapa al cerrar 5192 if (map) { 5193 try { 5194 map.remove(); 5195 } catch (e) { 5196 console.log('Error al limpiar mapa:', e); 5197 } 5198 map = null; 5199 marker = null; 5200 } 5201 }); 5202 } 5203 5204 // Cerrar modal al hacer clic fuera del contenido 5205 window.addEventListener('click', function(event) { 5206 if (event.target === mapModal) { 5207 mapModal.style.display = 'none'; 5208 // Resetear estado al cerrar 5209 locationPermissionsDenied = false; 5210 locationPermissionsEnabled = false; 5211 if (enableLocationGuideBtn) enableLocationGuideBtn.style.display = 'none'; 5212 if (centerLocationBtn) centerLocationBtn.style.display = 'none'; 5213 hideLocationPermissionsGuide(); 5214 // Limpiar mapa al cerrar 5215 if (map) { 5216 try { 5217 map.remove(); 5218 } catch (e) { 5219 console.log('Error al limpiar mapa:', e); 5220 } 5221 map = null; 5222 marker = null; 5223 } 5224 } 5225 }); 5226 5227 // Confirmar ubicación seleccionada 5228 if (confirmBtn) { 5229 confirmBtn.addEventListener('click', async function() { 5230 if (selectedLat && selectedLng) { 5231 // Mostrar loader y deshabilitar botón 5232 confirmBtn.classList.add('loading'); 5233 confirmBtn.disabled = true; 5234 5235 try { 5236 // Guardar coordenadas en los campos hidden 5237 latitudeInput.value = selectedLat; 5238 longitudeInput.value = selectedLng; 5239 const radiusSelect = document.getElementById('radius-select'); 5240 radiusInput.value = radiusSelect ? radiusSelect.value : DEFAULT_RADIUS; 5241 5242 // Intentar obtener información del marcador primero 5243 let address = ''; 5244 5245 // Verificar si el marcador tiene información de ubicación 5246 if (marker && marker.getPopup && marker.getPopup()) { 5247 const popupContent = marker.getPopup().getContent(); 5248 if (popupContent && typeof popupContent === 'string' && popupContent.trim() !== '') { 5249 address = popupContent; 5250 console.log('ð Usando información del marcador:', address); 5251 } 5252 } 5253 5254 // Si el mapa no proporcionó información, hacer reverse geocoding 5255 if (!address || address.includes('lat') || address.includes('lng')) { 5256 console.log('ðºï¸ Obteniendo dirección para coordenadas:', selectedLat, selectedLng); 5257 address = await getAddressFromCoordinates(selectedLat, selectedLng); 5258 console.log('ðï¸ Dirección obtenida via geocoding:', address); 5259 } 5260 5261 locationInput.value = address; 5262 5263 // Si existe el campo visible de búsqueda, también lo actualizamos 5264 if (locationGoogleSearch) { 5265 console.log('ð Actualizando campo visible con:', address); 5266 locationGoogleSearch.value = address; 5267 } 5268 5269 // Definimos el tipo de búsqueda 5270 const searchTypeInput = document.getElementById('SearchType'); 5271 if (searchTypeInput) { 5272 searchTypeInput.value = 'lat_lng'; 5273 } 5274 5275 // Pequeña pausa para mostrar que el proceso se completó 5276 await new Promise(resolve => setTimeout(resolve, 500)); 5277 5278 // Cerrar el modal 5279 mapModal.style.display = 'none'; 5280 5281 // Limpiar mapa después de confirmar 5282 if (map) { 5283 try { 5284 map.remove(); 5285 } catch (e) { 5286 console.log('Error al limpiar mapa después de confirmar:', e); 5287 } 5288 map = null; 5289 marker = null; 5290 } 5291 } catch (error) { 5292 console.error('Error al procesar la ubicación:', error); 5293 alert('Error al procesar la ubicación. Por favor, inténtelo de nuevo.'); 5294 } finally { 5295 // Ocultar loader y rehabilitar botón 5296 confirmBtn.classList.remove('loading'); 5297 confirmBtn.disabled = false;
5298 } 5299 } else { 5300 alert('Por favor, seleccione una ubicación en el mapa antes de confirmar.'); 5301 } 5302 }); 5303 } 5304 5305 // Función para obtener la dirección aproximada a partir de coordenadas 5306 async function getAddressFromCoordinates(lat, lng) { 5307 try { 5308 console.log('ð Solicitando dirección para:', lat, lng); 5309 5310 // Intentar con el servicio que ya está funcionando en el autocomplete 5311 const response = await fetch(`https://ipapi.co/${lat},${lng}/json/`); 5312 5313 if (!response.ok) { 5314 throw new Error(`HTTP ${response.status}`); 5315 } 5316 5317 const data = await response.json(); 5318 console.log('ð¥ Respuesta de ipapi.co:', data); 5319 5320 if (data && !data.error) { 5321 let locationName = ''; 5322 5323 // Extraer información útil en orden de preferencia 5324 if (data.city) { 5325 locationName = data.city; 5326 } else if (data.region) { 5327 locationName = data.region; 5328 } 5329 5330 // Agregar región/estado si existe y es diferente 5331 if (data.region && data.region !== locationName && locationName) { 5332 locationName += `, ${data.region}`; 5333 } 5334 5335 // Agregar paÃs si existe 5336 if (data.country_name) { 5337 locationName += locationName ? `, ${data.country_name}` : data.country_name; 5338 } 5339 5340 const finalResult = locationName || `${lat.toFixed(4)}, ${lng.toFixed(4)}`; 5341 console.log('â Dirección procesada:', finalResult); 5342 return finalResult; 5343 } else { 5344 throw new Error('No data received or API error'); 5345 } 5346 } catch (error) { 5347 console.warn('â ï¸ Error con ipapi.co, intentando con método alternativo:', error); 5348 5349 // Fallback: usar reverse geocoding simplificado 5350 try { 5351 // Intentar con un servicio público que sà permite CORS 5352 const response = await fetch(`https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${lat}&longitude=${lng}&localityLanguage=es`); 5353 const data = await response.json(); 5354 console.log('ð¥ Respuesta de BigDataCloud:', data); 5355 5356 if (data) { 5357 let locationName = ''; 5358 5359 if (data.city) { 5360 locationName = data.city; 5361 } else if (data.locality) { 5362 locationName = data.locality; 5363 } else if (data.principalSubdivision) { 5364 locationName = data.principalSubdivision; 5365 } 5366 5367 // Agregar paÃs 5368 if (data.countryName && locationName) { 5369 locationName += `, ${data.countryName}`; 5370 } else if (data.countryName) { 5371 locationName = data.countryName; 5372 } 5373 5374 const finalResult = locationName || `${lat.toFixed(4)}, ${lng.toFixed(4)}`; 5375 console.log('â Dirección obtenida con BigDataCloud:', finalResult); 5376 return finalResult; 5377 } 5378 } catch (secondError) { 5379 console.error('ð¥ Error con ambos servicios:', secondError); 5380 } 5381 5382 // Si todo falla, devolver coordenadas simplificadas 5383 const errorResult = `${lat.toFixed(4)}, ${lng.toFixed(4)}`; 5384 console.log('ð¯ Usando coordenadas como último recurso:', errorResult); 5385 return errorResult; 5386 } 5387 } 5388 5389 // Mover el modal de mapa al final del body para evitar problemas de desbordamiento 5390 document.addEventListener("DOMContentLoaded", function() { 5391 if (mapModal && document.body) { 5392 document.body.appendChild(mapModal); 5393 } 5394 }); 5395 })(); 5396</script>
5396 5397 5398<!-- Script independiente para limpiar modal si no hay botón de mapa -->
5399<script> 5400 (function() { 5401 // Función robusta para limpiar el modal 5402 function cleanupMapModal() { 5403 try { 5404 // Verificar si existe el botón del mapa 5405 const mapBtn = document.getElementById('map-search-btn'); 5406 5407 if (!mapBtn) { 5408 console.log('ðï¸ Botón del mapa no encontrado - removiendo modal del mapa...'); 5409 // Si no existe el botón, remover el modal del mapa 5410 const mapModal = document.getElementById('map-modal'); 5411 if (mapModal) { 5412 mapModal.remove(); 5413 console.log('â Modal del mapa removido correctamente'); 5414 return true; // Indica que se completó la limpieza 5415 } 5416 } else { 5417 console.log('â Botón del mapa encontrado - modal del mapa disponible'); 5418 return true; // Indica que se completó la verificación 5419 } 5420 } catch (error) { 5421 console.error('Error al limpiar modal del mapa:', error); 5422 } 5423 return false; // Indica que no se pudo completar 5424 } 5425 5426 // Estrategia 1: Ejecutar inmediatamente si el DOM ya está listo 5427 if (document.readyState === 'loading') { 5428 // El DOM aún se está cargando, usar múltiples eventos 5429 let cleaned = false; 5430 5431 // Función que se ejecuta una sola vez 5432 function tryCleanup() { 5433 if (!cleaned && cleanupMapModal()) { 5434 cleaned = true; 5435 } 5436 } 5437 5438 // Estrategia 2: Múltiples eventos para garantizar ejecución 5439 document.addEventListener('DOMContentLoaded', tryCleanup); 5440 document.addEventListener('readystatechange', function() { 5441 if (document.readyState === 'interactive' || document.readyState === 'complete') { 5442 tryCleanup(); 5443 } 5444 }); 5445 window.addEventListener('load', tryCleanup); 5446 5447 // Estrategia 3: Verificación periódica como respaldo 5448 let attempts = 0; 5449 const maxAttempts = 20; // Máximo 2 segundos 5450 const checkInterval = setInterval(function() { 5451 attempts++; 5452 if (cleaned || attempts >= maxAttempts) { 5453 clearInterval(checkInterval); 5454 return; 5455 } 5456 5457 // Verificar si el DOM está listo 5458 if (document.readyState === 'interactive' || document.readyState === 'complete') { 5459 if (cleanupMapModal()) { 5460 cleaned = true; 5461 clearInterval(checkInterval); 5462 } 5463 } 5464 }, 100); 5465 5466 } else { 5467 // El DOM ya está listo, ejecutar inmediatamente 5468 cleanupMapModal(); 5469 } 5470 })(); 5471</script>
vendor: 1 bytes, line 5471
5471
5472<script> 5473 (function() { 5474 function run() { 5475 try { 5476 var span = document.querySelector('#PxMkAcion_Search .update-search-span'); 5477 var btn = document.getElementById('PxMkAcion_Search'); 5478 if (!span) return; 5479 5480 var themeHex = '#b29e73'; 5481 5482 function parseHex(hex) { 5483 if (!hex) return null; 5484 hex = String(hex).trim(); 5485 if (hex.startsWith('#')) hex = hex.slice(1); 5486 if (hex.length === 3) { 5487 hex = hex.split('').map(function(ch) { 5488 return ch + ch; 5489 }).join(''); 5490 } 5491 if (hex.length !== 6) return null; 5492 var r = parseInt(hex.slice(0, 2), 16); 5493 var g = parseInt(hex.slice(2, 4), 16); 5494 var b = parseInt(hex.slice(4, 6), 16); 5495 if ([r, g, b].some(function(v) { 5496 return isNaN(v); 5497 })) return null; 5498 return { 5499 r: r, 5500 g: g, 5501 b: b 5502 }; 5503 } 5504 5505 function relL(rgb) { 5506 function toLin(c) { 5507 c = c / 255; 5508 return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); 5509 } 5510 var R = toLin(rgb.r), 5511 G = toLin(rgb.g), 5512 B = toLin(rgb.b); 5513 return 0.2126 * R + 0.7152 * G + 0.0722 * B; 5514 } 5515 5516 function contrast(L1, L2) { 5517 var a = Math.max(L1, L2); 5518 var b = Math.min(L1, L2); 5519 return (a + 0.05) / (b + 0.05); 5520 } 5521 5522 var rgb = parseHex(themeHex); 5523 if (!rgb) { 5524 if (btn) { 5525 var bg = window.getComputedStyle(btn).backgroundColor; // rgb(a) 5526 var m = bg && bg.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/i); 5527 if (m) { 5528 rgb = { 5529 r: parseInt(m[1], 10), 5530 g: parseInt(m[2], 10), 5531 b: parseInt(m[3], 10) 5532 }; 5533 } 5534 } 5535 } 5536 if (!rgb) return; 5537 5538 var Lbg = relL(rgb); 5539 var Lwhite = relL({ 5540 r: 255, 5541 g: 255, 5542 b: 255 5543 }); 5544 var Lblack = relL({ 5545 r: 0, 5546 g: 0, 5547 b: 0 5548 }); 5549 var cWhite = contrast(Lbg, Lwhite); 5550 var cBlack = contrast(Lbg, Lblack); 5551 5552 var textColor = cBlack >= cWhite ? '#000000' : '#FFFFFF'; 5553 span.style.setProperty('color', textColor, 'important'); 5554 if (btn) { 5555 btn.style.setProperty('color', textColor, 'important'); 5556 5557 // Recolor inline SVG icons (search and loading) to match contrast color 5558 function paintInlineSVG(container, color) { 5559 try { 5560 var svgs = container.querySelectorAll('svg'); 5561 svgs.forEach(function(svg) { 5562 // Support SVGs that use currentColor 5563 svg.style.setProperty('color', color, 'important'); 5564 svg.setAttribute('color', color); 5565 // Force fill/stroke 5566 svg.style.setProperty('fill', color, 'important'); 5567 svg.style.setProperty('stroke', color, 'important'); 5568 // Update common shape elements 5569 svg.querySelectorAll('path, circle, rect, polygon, line, polyline, ellipse, g').forEach(function(node) { 5570 node.style.setProperty('fill', color, 'important'); 5571 node.style.setProperty('stroke', color, 'important'); 5572 }); 5573 5574 // Override attributes if they exist 5575 svg.querySelectorAll('[fill]').forEach(function(node) { 5576 node.setAttribute('fill', color); 5577 }); 5578 svg.querySelectorAll('[stroke]').forEach(function(node) { 5579 node.setAttribute('stroke', color); 5580 }); 5581 }); 5582 } catch (e) { 5583 /* ignore */ 5584 } 5585 } 5586 5587 var iconLabel = btn.querySelector('.px-mk-searchicon'); 5588 var loaderLabel = btn.querySelector('.px-mk-searchloader'); 5589 if (iconLabel) paintInlineSVG(iconLabel, textColor); 5590 if (loaderLabel) paintInlineSVG(loaderLabel, textColor); 5591 } 5592 } catch (e) { 5593 /* ignore */ 5594 } 5595 } 5596 5597 if (document.readyState === 'loading') { 5598 document.addEventListener('DOMContentLoaded', run); 5599 } else { 5600 run(); 5601 } 5602 })(); 5603</script>
5603 </div> 5604 </div></div></div> 5605 5606 5607<div id='Overlay' class="hidden" onclick='activeSearch()'></div> 5608 5609</div> 5610 5611</div> 5612 <div class="main_wraper_content" id="main_wraper_content"> 5613 5614 5615<div class="neo_template_container neo_template_ computer"> 5616 5617 5618<div class="content-hab" ><div class="img-hab" ><div class='container-neo-slider' Slide='TopHabitaciones' Width='1900' Height='500' Loop='true' Effect='Fade '> 5619 <div class="neo_template_block neo_neo_swiper pxModule_include ModuloWrap_neo_swiper" id="neo_swiper" > 5620 5621 5622<!-- Module Start --> 5623 5624<div class="megacontainer-neo-swiper"> 5625 <div class="swiper-container-4376"> <!-- le asignamos el numero random al contenedor --> 5626 5627 <div class="swiper-wrapper"> 5628 <div class="swiper-slide slide-one-pic"> 5629 <img src="https://images-new.pxsol.com/gf_aN1psl83xgToHsgACYFY8AoT43sn49TRjs6c7YMo/rs:fill:1900:500:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F343989361871a3087eedb360eb49120ee2975221ef.jpg@jpg" 5630 width="1900" 5631 height="500" 5632 style="aspect-ratio: 1900/500;" 5633 alt="Hotel Premium Tower Suites"> 5634 </div> 5635 </div> 5636 <!-- Add Arrows --> 5637 5638 </div> 5639 <!-- Asà mismo para dataconfig-swiper le pasamos el numero random para identificarlo de otros --> 5640 <div class="dataconfig-swiper" data-id="4376" data-loop="true" data-speed=800 data-effect="fade" data-delay=5000 style="display:none" ></div> 5641</div> 5642 5643 5644 </div> 5645 </div></div><div class="text-hab" >Rooms</div></div> 5646 5647 5648<div class="content-bg-color" ><div class="bg-color nohome" ></div></div> 5649 5650 5651<div class="container-hab" ><div class="desc-habitacion" ></div><div class='' Swiper='true' Servicios='true' Boton='reservar' Modo='horizontal' SrcBoton='es' FiltroTitulo='' TextoBoton='Ver Tarifas' URLBoton='' Descripcion='true'> 5652 <div class="neo_template_block neo_neo_habitaciones pxModule_include ModuloWrap_neo_habitaciones" id="neo_habitaciones" > 5653 5654 <div class="neo_hab full"> 5655 <div class="neo_hab_container full flex flex-wrap flex-m-center"> 5656 <div id="85586" class="neo_hab_item neo_hab_item_horizontal flex margin-bottom-20 margin-md-right-20 neo_hab_item_horizontal xs-100 max-lg-45 "> 5657 <div class="neo_hab_item_imgcontainer full neo_hab_item_horizontal"> 5658 <div class="swiper-initializer" slides="" swiperid="habslider_1430807888"> 5659 </div> 5660 <div class="swiper-container full" id="habslider_1430807888"> 5661 <div class="swiper-wrapper full"> 5662 <div class="neo_hab_item_swiper_item swiper-slide full"> 5663 <img src="https://images-new.pxsol.com/sQeTI1OJzuR9gbANzfkAIRNnICvOOGHfo6zE_LA1P1Q/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F15959235267fcec06303ea353efbb57233bd4224e8a.jpg@jpg" alt="Habitación Ejecutiva "> 5664 </div> 5665 <div class="neo_hab_item_swiper_item swiper-slide full"> 5666 <img src="https://images-new.pxsol.com/a7cXCwLcVJUEeL5o11jM72RKMv0eu4t9Q6mMJMDfGG0/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F1203963294123fa55ee5e43ce78bfbbfa97691b9f9b.jpg@jpg" alt="Habitación Ejecutiva "> 5667 </div> 5668 <div class="neo_hab_item_swiper_item swiper-slide full"> 5669 <img src="https://images-new.pxsol.com/2YhYDSQpjsAKr8Ni0Mmvz6ld_ZKj2D2pWun1hCJMY74/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F10319680776c36e38f1b062096d843d49eaa180072c.jpg@jpg" alt="Habitación Ejecutiva "> 5670 </div> 5671 <div class="neo_hab_item_swiper_item swiper-slide full"> 5672 <img src="https://images-new.pxsol.com/31OThZxyzhEUWGCdRWZnP5Xfni1l6rW5bsPQARniKkA/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F3439895122c947eefc8b081c8ce88f4340f026999b.jpg@jpg" alt="Habitación Ejecutiva "> 5673 </div> 5674 <div class="neo_hab_item_swiper_item swiper-slide full"> 5675 <img src="https://images-new.pxsol.com/Srgm2S2WF54b5l3CSCp8qEfsVVYoqUwznxA8xkO7CM
5675I/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F85997342700044139e596dd8f1453b9737cb50b0a2.jpg@jpg" alt="Habitación Ejecutiva "> 5676 </div> 5677 <div class="neo_hab_item_swiper_item swiper-slide full"> 5678 <img src="https://images-new.pxsol.com/Y5XDsqUVEpYr4SQJIyHG2UpMXH2WELMOPdi0iXtgcEg/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F343989371283c0c7ae749b66985e07d3f0a1c3a1b4.jpg@jpg" alt="Habitación Ejecutiva "> 5679 </div> 5680 </div> 5681 <button type="button" class="swiper-prev"><i class="mdi mdi-chevron-left"></i></button> 5682 <button type="button" class="swiper-next"><i class="mdi mdi-chevron-right"></i></button> 5683 </div> 5684 </div> 5685 <div class="neo_hab_item_info flex-grow flex-column padding-20"> 5686 <div class="neo_hab_item_title">Executive room</div> 5687 5688 5689 <div style="white-space: pre-line" class="neo_hab_item_description"> 5690 The executive/studio apartment has everything you need for a comfortable, practical and pleasant stay. An ideal alternative for your getaway to Mendoza. Equipped kitchen, bathroom, safe, amenities, individual air conditioning and heating system.</div> 5691 <div class="flex flex-wrap neo_hab_item_amenities"> 5692 5693 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center active size"> 5694 <i class="fas fa-expand-arrows-alt fa-2x"></i> 5695 <div class="flex-column"> 5696 <div class="neo_hab_amenity_textsmall"> 5697 Tamaño </div> 5698 <div class="neo_hab_amenity_textbig"> 5699 32 <span class="units"> 5700 m<span class="superi">2</span> 5701 </span> 5702 </div> 5703 </div> 5704 </div> 5705 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center breakfast "> 5706 <i class="fas fa-coffee fa-2x"></i> 5707 <div class="flex-column"> 5708 <div class="neo_hab_amenity_textsmall"> 5709 Desayuno Incluido </div> 5710 <div class="neo_hab_amenity_textbig"> 5711 Si </div> 5712 </div> 5713 </div> 5714 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center smoke"> 5715 <i class="fas fa-2x 5716 fa-smoking-ban"></i> 5717 <div class="flex-column"> 5718 <div class="neo_hab_amenity_textsmall"> 5719 Fumadores </div> 5720 <div class="neo_hab_amenity_textbig"> 5721 No </div> 5722 </div> 5723 </div> 5724 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center tv "> 5725 <i class="fas fa-tv fa-2x"></i> 5726 <div class="flex-column"> 5727 <div class="neo_hab_amenity_textsmall"> 5728 TV </div> 5729 <div class="neo_hab_amenity_textbig"> 5730 Si </div> 5731 </div> 5732 </div> 5733 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center private "> 5734 <i class="fas fa-bath fa-2x"></i> 5735 <div class="flex-column"> 5736 <div class="neo_hab_amenity_textsmall"> 5737 Baño Privado </div> 5738 <div class="neo_hab_amenity_textbig"> 5739 Si </div> 5740 </div> 5741 </div> 5742 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center conditionair "> 5743 <i class="fas fa-snowflake fa-2x"></i> 5744 <div class="flex-column"> 5745 <div class="neo_hab_amenity_textsmall"> 5746 Air conditioner </div> 5747 <div class="neo_hab_amenity_textbig"> 5748 Si </div> 5749 </div> 5750 </div> 5751 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center safe"> 5752 <i class="fas fa-lock fa-2x"></i> 5753 <div class="flex-column"> 5754 <div class="neo_hab_amenity_textsmall"> 5755 Caja de Seguridad </div> 5756 <div class="neo_hab_amenity_textbig"> 5757 Si </div> 5758 </div> 5759 </div> 5760 </div> 5761 <div class="flex-grow"></div> 5762 <div class="neo_hab_item_actions flex flex-m-end flex-s-center full"> 5763 5764 <a href="#bookRoom_85586" class="neo_hab_item_cta pxb-cta neo_bgcolor_primary padding-10 toggle_search toggleMenuWindow cta_gotosearch " menu-window-id="neo_m_buscador"> 5765 <i class="mdi mdi-room-service-outline margin-right-10 fontsize-20px"></i> 5766 Check Rates </a> 5767 </div> 5768 </div> 5769 5770 </div> 5771 <div id="85585" class="neo_hab_item neo_hab_item_horizontal flex margin-bottom-20 margin-md-right-20 neo_hab_item_horizontal xs-100 max-lg-45 "> 5772 <div class="neo_hab_item_imgcontainer full neo_hab_item_horizontal"> 5773 <div class="swiper-initializer" slides="" swiperid="habslider_463621306"> 5774 </div> 5775 <div class="swiper-container full" id="habslider_463621306"> 5776 <div class="swiper-wrapper full"> 5777 <div class="neo_hab_item_swiper_item swiper-slide full"> 5778 <img src="https://images-new.pxsol.com/tIrDTo68YN7PAkFmKi1VSC97wqxQ8q99F38ACV-_zxw/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F1031968091465cded503bd3b7a35ee74c165a04864b.jpg@jpg" alt="Habitación Suite Doble"> 5779 </div> 5780 <div class="neo_hab_item_swiper_item swiper-slide full"> 5781 <img src="https://images-new.pxsol.com/qurThcrtD5HuVjrkQLPiYKEN1j6V0Jp_j_mSDGX8EzY/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F27519167712dcdda9c67a671d06a4f5d1289543af86.jpg@jpg" alt="Habitación Suite Doble"> 5782 </div> 5783 <div class="neo_hab_item_swiper_item swiper-slide full"> 5784 <img src="https://images-new.pxsol.com/pdGa8AByWXZgl_wVcbp-Zzo4ZiFLaAFt4oiS9YFDKmc/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F22359309141b6ec61b90ba08b4629c43d81ef7e0a16.jpg@jpg" alt="Habitación Suite Doble"> 5785 </div> 5786 <div class="neo_hab_item_swiper_item swiper-slide full"> 5787 <img src="https://images-new.pxsol.com/OeovxoHCm3GrNNwo9e-0ViFW_OHrtxwus27nhEk6qEk/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F230522304870acc2320e233cde2fddc89e0f298aa76.jpg@jpg" alt="Habitación Suite Doble"> 5788 </div> 5789 <div class="neo_hab_item_swiper_item swiper-slide full"> 5790 <img src="https://images-new.pxsol.com/S8N9Lro2j04LYyCBnxOwXfjX2gthV0EpRd3ij8TyQnw/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F6879787416749423e18c0bab01d1e454284fc768a5.jpg@jpg" alt="Habitación Suite Doble"> 5791 </div> 5792 <div class="neo_hab_item_swiper_item swiper-slide full"> 5793 <img src="https://images-new.pxsol.com/Srgm2S2WF54b5l3CSCp8qEfsVVYoqUwznxA8xkO7CM
5793I/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F85997342700044139e596dd8f1453b9737cb50b0a2.jpg@jpg" alt="Habitación Suite Doble"> 5794 </div> 5795 <div class="neo_hab_item_swiper_item swiper-slide full"> 5796 <img src="https://images-new.pxsol.com/yXQI3b3gNayOt-lmq0mBEBpY4Q2Kxr4DpOivUFD7zS4/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F531974550690be06e04c6d89451bf0884f1d23cb98.jpg@jpg" alt="Habitación Suite Doble"> 5797 </div> 5798 </div> 5799 <button type="button" class="swiper-prev"><i class="mdi mdi-chevron-left"></i></button> 5800 <button type="button" class="swiper-next"><i class="mdi mdi-chevron-right"></i></button> 5801 </div> 5802 </div> 5803 <div class="neo_hab_item_info flex-grow flex-column padding-20"> 5804 <div class="neo_hab_item_title">Double Suite Room</div> 5805 5806 5807 <div style="white-space: pre-line" class="neo_hab_item_description"> 5808 The two-room suite apartment is the best option for long stays. It has a large living room, a two-seater sofa, a fully equipped kitchen and a bathroom. This apartment stands out for having the bedroom located in a separate room from the others, providing comfort.</div> 5809 <div class="flex flex-wrap neo_hab_item_amenities"> 5810 5811 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center active size"> 5812 <i class="fas fa-expand-arrows-alt fa-2x"></i> 5813 <div class="flex-column"> 5814 <div class="neo_hab_amenity_textsmall"> 5815 Tamaño </div> 5816 <div class="neo_hab_amenity_textbig"> 5817 41 <span class="units"> 5818 m<span class="superi">2</span> 5819 </span> 5820 </div> 5821 </div> 5822 </div> 5823 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center breakfast "> 5824 <i class="fas fa-coffee fa-2x"></i> 5825 <div class="flex-column"> 5826 <div class="neo_hab_amenity_textsmall"> 5827 Desayuno Incluido </div> 5828 <div class="neo_hab_amenity_textbig"> 5829 Si </div> 5830 </div> 5831 </div> 5832 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center smoke"> 5833 <i class="fas fa-2x 5834 fa-smoking-ban"></i> 5835 <div class="flex-column"> 5836 <div class="neo_hab_amenity_textsmall"> 5837 Fumadores </div> 5838 <div class="neo_hab_amenity_textbig"> 5839 No </div> 5840 </div> 5841 </div> 5842 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center tv "> 5843 <i class="fas fa-tv fa-2x"></i> 5844 <div class="flex-column"> 5845 <div class="neo_hab_amenity_textsmall"> 5846 TV </div> 5847 <div class="neo_hab_amenity_textbig"> 5848 Si </div> 5849 </div> 5850 </div> 5851 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center private "> 5852 <i class="fas fa-bath fa-2x"></i> 5853 <div class="flex-column"> 5854 <div class="neo_hab_amenity_textsmall"> 5855 Baño Privado </div> 5856 <div class="neo_hab_amenity_textbig"> 5857 Si </div> 5858 </div> 5859 </div> 5860 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center conditionair "> 5861 <i class="fas fa-snowflake fa-2x"></i> 5862 <div class="flex-column"> 5863 <div class="neo_hab_amenity_textsmall"> 5864 Air conditioner </div> 5865 <div class="neo_hab_amenity_textbig"> 5866 Si </div> 5867 </div> 5868 </div> 5869 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center safe"> 5870 <i class="fas fa-lock fa-2x"></i> 5871 <div class="flex-column"> 5872 <div class="neo_hab_amenity_textsmall"> 5873 Caja de Seguridad </div> 5874 <div class="neo_hab_amenity_textbig"> 5875 Si </div> 5876 </div> 5877 </div> 5878 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center heating "> 5879 <i class="mdi mdi-radiator"></i> 5880 <div class="flex-column"> 5881 <div class="neo_hab_amenity_textsmall"> 5882 Calefacción </div> 5883 <div class="neo_hab_amenity_textbig"> 5884 Si </div> 5885 </div> 5886 </div> 5887 </div> 5888 <div class="flex-grow"></div> 5889 <div class="neo_hab_item_actions flex flex-m-end flex-s-center full"> 5890 5891 <a href="#bookRoom_85585" class="neo_hab_item_cta pxb-cta neo_bgcolor_primary padding-10 toggle_search toggleMenuWindow cta_gotosearch " menu-window-id="neo_m_buscador"> 5892 <i class="mdi mdi-room-service-outline margin-right-10 fontsize-20px"></i> 5893 Check Rates </a> 5894 </div> 5895 </div> 5896 5897 </div> 5898 <div id="85591" class="neo_hab_item neo_hab_item_horizontal flex margin-bottom-20 margin-md-right-20 neo_hab_item_horizontal xs-100 max-lg-45 "> 5899 <div class="neo_hab_item_imgcontainer full neo_hab_item_horizontal"> 5900 <div class="swiper-initializer" slides="" swiperid="habslider_885561937"> 5901 </div> 5902 <div class="swiper-container full" id="habslider_885561937"> 5903 <div class="swiper-wrapper full"> 5904 <div class="neo_hab_item_swiper_item swiper-slide full"> 5905 <img src="https://images-new.pxsol.com/JRRctTDHHoPIhuEwWWuIfCzfJxIWahWFiK_7XYpfNuo/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F265987230302681125b68aa6ce3baf1eb849e71f971.jpg@jpg" alt="Habitación Suite Triple"> 5906 </div> 5907 <div class="neo_hab_item_swiper_item swiper-slide full"> 5908 <img src="https://images-new.pxsol.com/Y5XDsqUVEpYr4SQJIyHG2UpMXH2WELMOPdi0iXtgcEg/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F343989371283c0c7ae749b66985e07d3f0a1c3a1b4.jpg@jpg" alt="Habitación Suite Triple"> 5909 </div> 5910 <div class="neo_hab_item_swiper_item swiper-slide full"> 5911 <img src="https://images-new.pxsol.com/pdGa8AByWXZgl_wVcbp-Zzo4ZiFLaAFt4oiS9YFDKmc/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F22359309141b6ec61b90ba08b4629c43d81ef7e0a16.jpg@jpg" alt="Habitación Suite Triple"> 5912 </div> 5913 <div class="neo_hab_item_swiper_item swiper-slide full"> 5914 <img src="https://images-new.pxsol.com/TpsrQTsJ-C35eD1fEI1hQNnvr1O7J0zho159PJV_nrw/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F27519167696a3dab614cadea4850a4d5507e15d1941.jpg@jpg" alt="Habitación Suite Triple"> 5915 </div> 5916 <div class="neo_hab_item_swiper_item swiper-slide full"> 5917 <img src="https://images-new.pxsol.com/MtqtY3ghBVeGzDiS6QOhnYFdYwVLeMNkojVGV4P9j9M/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F7092992520c6fa69ab2d608ea8e6a5c40466c6d161.jpg@jpg" alt="Habitación Suite Triple"> 5918 </div> 5919 </div> 5920 <button type="button" class="swiper-prev"><i class="mdi mdi-chevron-left"></i></button> 5921 <button type="button" class="swiper-next"><i class="mdi mdi-chevron-right"></i></button> 5922 </div> 5923 </div> 5924 <div class="neo_hab_item_info flex-grow flex-column padding-20"> 5925 <div class="neo_hab_item_title">Triple Suite Room</div> 5926 5927 5928 <div style="white-space: pre-line" class="neo_hab_item_description"> 5929 The two-room suite apartment is the best option for long stays. It has a large living room, fully equipped kitchen and bathroom. This apartment stands out for having the bedroom located in a separate room from the others, providing comfort and a single bed in the living room.</div> 5930 <div class="flex flex-wrap neo_hab_item_amenities"> 5931 5932 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center active size"> 5933 <i class="fas fa-expand-arrows-alt fa-2x"></i> 5934 <div class="flex-column"> 5935 <div class="neo_hab_amenity_textsmall"> 5936 Tamaño </div> 5937 <div class="neo_hab_amenity_textbig"> 5938 41 <sp
5938an class="units"> 5939 m<span class="superi">2</span> 5940 </span> 5941 </div> 5942 </div> 5943 </div> 5944 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center breakfast "> 5945 <i class="fas fa-coffee fa-2x"></i> 5946 <div class="flex-column"> 5947 <div class="neo_hab_amenity_textsmall"> 5948 Desayuno Incluido </div> 5949 <div class="neo_hab_amenity_textbig"> 5950 Si </div> 5951 </div> 5952 </div> 5953 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center smoke"> 5954 <i class="fas fa-2x 5955 fa-smoking-ban"></i> 5956 <div class="flex-column"> 5957 <div class="neo_hab_amenity_textsmall"> 5958 Fumadores </div> 5959 <div class="neo_hab_amenity_textbig"> 5960 No </div> 5961 </div> 5962 </div> 5963 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center tv "> 5964 <i class="fas fa-tv fa-2x"></i> 5965 <div class="flex-column"> 5966 <div class="neo_hab_amenity_textsmall"> 5967 TV </div> 5968 <div class="neo_hab_amenity_textbig"> 5969 Si </div> 5970 </div> 5971 </div> 5972 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center private "> 5973 <i class="fas fa-bath fa-2x"></i> 5974 <div class="flex-column"> 5975 <div class="neo_hab_amenity_textsmall"> 5976 Baño Privado </div> 5977 <div class="neo_hab_amenity_textbig"> 5978 Si </div> 5979 </div> 5980 </div> 5981 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center conditionair "> 5982 <i class="fas fa-snowflake fa-2x"></i> 5983 <div class="flex-column"> 5984 <div class="neo_hab_amenity_textsmall"> 5985 Air conditioner </div> 5986 <div class="neo_hab_amenity_textbig"> 5987 Si </div> 5988 </div> 5989 </div> 5990 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center safe"> 5991 <i class="fas fa-lock fa-2x"></i> 5992 <div class="flex-column"> 5993 <div class="neo_hab_amenity_textsmall"> 5994 Caja de Seguridad </div> 5995 <div class="neo_hab_amenity_textbig"> 5996 Si </div> 5997 </div> 5998 </div> 5999 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center heating "> 6000 <i class="mdi mdi-radiator"></i> 6001 <div class="flex-column"> 6002 <div class="neo_hab_amenity_textsmall"> 6003 Calefacción </div> 6004 <div class="neo_hab_amenity_textbig"> 6005 Si </div> 6006 </div> 6007 </div> 6008 </div> 6009 <div class="flex-grow"></div> 6010 <div class="neo_hab_item_actions flex flex-m-end flex-s-center full"> 6011 6012 <a href="#bookRoom_85591" class="neo_hab_item_cta pxb-cta neo_bgcolor_primary padding-10 toggle_search toggleMenuWindow cta_gotosearch " menu-window-id="neo_m_buscador"> 6013 <i class="mdi mdi-room-service-outline margin-right-10 fontsize-20px"></i> 6014 Check Rates </a> 6015 </div> 6016 </div> 6017 6018 </div> 6019 <div id="85808" class="neo_hab_item neo_hab_item_horizontal flex margin-bottom-20 margin-md-right-20 neo_hab_item_horizontal xs-100 max-lg-45 "> 6020 <div class="neo_hab_item_imgcontainer full neo_hab_item_horizontal"> 6021 <div class="swiper-initializer" slides="" swiperid="habslider_1002852723"> 6022 </div> 6023 <div class="swiper-container full" id="habslider_1002852723"> 6024 <div class="swiper-wrapper full"> 6025 <div class="neo_hab_item_swiper_item swiper-slide full"> 6026 <img src="https://images-new.pxsol.com/UxfhRmuNZ4fzzhH7jp01v0gSllkTHnlwC7raJjtsDeE/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F21278983164062c253326dd14ad862b8853677dce8c.jpg@jpg" alt="Habitacion Premium"> 6027 </div> 6028 <div class="neo_hab_item_swiper_item swiper-slide full"> 6029 <img src="https://images-new.pxsol.com/4EbASvSF7A1GkgPGgqX-D2Cj1yWS1HTVO5zTurxbO58/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F3546497202a16d1cad89b2e8ea965574f95ec881d7.jpg@jpg" alt="Habitacion Premium"> 6030 </div> 6031 <div class="neo_hab_item_swiper_item swiper-slide full"> 6032 <img src="https://images-new.pxsol.com/pdGa8AByWXZgl_wVcbp-Zzo4ZiFLaAFt4oiS9YFDKmc/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F22359309141b6ec61b90ba08b4629c43d81ef7e0a16.jpg@jpg" alt="Habitacion Premium"> 6033 </div> 6034 <div class="neo_hab_item_swiper_item swiper-slide full"> 6035 <img src="https://images-new.pxsol.com/S4HRPL_dBuTDbzS2diNrzPyMgblxjPBfxFIskhkTaIY/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F2305223195682579bbfccbad355a0d5f1e2e581c555.jpg@jpg" alt="Habitacion Premium"> 6036 </div> 6037 <div class="neo_hab_item_swiper_item swiper-slide full"> 6038 <img src="https://images-new.pxsol.com/t8sB0tgtvmPakmush60oHdJs7eAqDC-zCeoyUVA8wWI/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F28371977760d31ce40d1a49cf47ef7c5298f037fe5f.jpg@jpg" alt="Habitacion Premium"> 6039 </div> 6040 <div class="neo_hab_item_swiper_item swiper-slide full"> 6041 <img src="https://images-new.pxsol.com/Y5XDsqUVEpYr4SQJIyHG2UpMXH2WELMOPdi0iXtgcEg/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F343989371283c0c7ae749b66985e07d3f0a1c3a1b4.jpg@jpg" alt="Habitacion Premium"> 6042 </div> 6043 <div class="neo_hab_item_swiper_item swiper-slide full"> 6044 <img src="https://images-new.pxsol.com/v-bF0DjG6CW2xDtZVHE_fHlHxz2tJAhuh9UvssKiKgY/rs:fill:600:400:1/q:80/plain/https%3A%2F%2Ffiles-p.pxsol.com%2F18413%2Fcompany%2Flibrary%2Fuser%2F10639492110dc5979574880347255322d1e583ded1b.jpg@jpg" alt="Habitacion Premium"> 6045 </div> 6046 </div> 6047 <button type="button" class="swiper-prev"><i class="mdi mdi-chevron-left"></i></button> 6048 <button type="button" class="swiper-next"><i class="mdi mdi-chevron-right"></i></button> 6049 </div> 6050 </div> 6051 <div class="neo_hab_item_info flex-grow flex-column padding-20"> 6052 <div class="neo_hab_item_title">Premium Room</div> 6053 6054 6055 <div style="white-space: pre-line" class="neo_hab_item_description"> 6056 The Premium room is the best alternative for the family group, as it has two bedrooms, two bathrooms, a fully equipped kitchen and a very spacious living room with a two-seater sofa.</div> 6057 <div class="flex flex-wrap neo_hab_item_amenities"> 6058 6059 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center active size"> 6060 <i class="fas fa-expand-arrows-alt fa-2x"></i> 6061 <div class="flex-column"> 6062 <div class="neo_hab_amenity_textsmall"> 6063 Tamaño </div> 6064 <div class="neo_hab_amenity_textbig"> 6065 62 <sp
6065an class="units"> 6066 m<span class="superi">2</span> 6067 </span> 6068 </div> 6069 </div> 6070 </div> 6071 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center breakfast "> 6072 <i class="fas fa-coffee fa-2x"></i> 6073 <div class="flex-column"> 6074 <div class="neo_hab_amenity_textsmall"> 6075 Desayuno Incluido </div> 6076 <div class="neo_hab_amenity_textbig"> 6077 Si </div> 6078 </div> 6079 </div> 6080 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center smoke"> 6081 <i class="fas fa-2x 6082 fa-smoking-ban"></i> 6083 <div class="flex-column"> 6084 <div class="neo_hab_amenity_textsmall"> 6085 Fumadores </div> 6086 <div class="neo_hab_amenity_textbig"> 6087 No </div> 6088 </div> 6089 </div> 6090 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center private "> 6091 <i class="fas fa-bath fa-2x"></i> 6092 <div class="flex-column"> 6093 <div class="neo_hab_amenity_textsmall"> 6094 Baño Privado </div> 6095 <div class="neo_hab_amenity_textbig"> 6096 Si </div> 6097 </div> 6098 </div> 6099 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center conditionair "> 6100 <i class="fas fa-snowflake fa-2x"></i> 6101 <div class="flex-column"> 6102 <div class="neo_hab_amenity_textsmall"> 6103 Air conditioner </div> 6104 <div class="neo_hab_amenity_textbig"> 6105 Si </div> 6106 </div> 6107 </div> 6108 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center safe"> 6109 <i class="fas fa-lock fa-2x"></i> 6110 <div class="flex-column"> 6111 <div class="neo_hab_amenity_textsmall"> 6112 Caja de Seguridad </div> 6113 <div class="neo_hab_amenity_textbig"> 6114 Si </div> 6115 </div> 6116 </div> 6117 <div class="neo_hab_amenity xs-100 lg-50 flex flex-s-center heating "> 6118 <i class="mdi mdi-radiator"></i> 6119 <div class="flex-column"> 6120 <div class="neo_hab_amenity_textsmall"> 6121 Calefacción </div> 6122 <div class="neo_hab_amenity_textbig"> 6123 Si </div> 6124 </div> 6125 </div> 6126 </div> 6127 <div class="flex-grow"></div> 6128 <div class="neo_hab_item_actions flex flex-m-end flex-s-center full"> 6129 6130 <a href="#bookRoom_85808" class="neo_hab_item_cta pxb-cta neo_bgcolor_primary padding-10 toggle_search toggleMenuWindow cta_gotosearch " menu-window-id="neo_m_buscador"> 6131 <i class="mdi mdi-room-service-outline margin-right-10 fontsize-20px"></i> 6132 Check Rates </a> 6133 </div> 6134 </div> 6135 6136 </div> 6137 <div id="175694" class="neo_hab_item neo_hab_item_horizontal flex margin-bottom-20 margin-md-right-20 neo_hab_item_horizontal xs-100 max-lg-45 "> 6138 <div class="neo_hab_item_imgcontainer full neo_hab_item_horizontal"> 6139 </div> 6140 <div class="neo_hab_item_info flex-grow flex-column padding-20"> 6141 <div class="neo_hab_item_title">Auxiliar</div> 6142 6143 6144 <div style="white-space: pre-line" class="neo_hab_item_description"> 6145 AUXILIAR</div> 6146 <div class="flex-grow"></div> 6147 <div class="neo_hab_item_actions flex flex-m-end flex-s-center full"> 6148 6149 <a href="#bookRoom_175694" class="neo_hab_item_cta pxb-cta neo_bgcolor_primary padding-10 toggle_search toggleMenuWindow cta_gotosearch " menu-window-id="neo_m_buscador"> 6150 <i class="mdi mdi-room-service-outline margin-right-10 fontsize-20px"></i> 6151 Check Rates </a> 6152 </div> 6153 </div> 6154 6155 </div> 6156 </div> 6157 </div> 6158 6159 </div> 6160 </div></div> 6161 6162</div> 6163 6164 </div> 6165 6166 6167 6168 <div class="main_wraper_footer" id="main_wraper_footer"> 6169 6170 6171<div class="neo_template_container neo_template_ computer"> 6172 6173 6174<div class="megacontainer-footer" ><div class="container-info-footer" ><div class="contact" ><div class='' > 6175 <div class="neo_template_block neo_neo_contact_info pxModule_include ModuloWrap_neo_contact_info" id="neo_contact_info" > 6176 6177<div class="neo-contact-container"> 6178 <h4 class="neo-contact-title"> 6179 Premium Tower Suites Mendoza </h4> 6180 <ul> 6181 6182 <li> 6183 <a href="tel:+54 261 248 0888"> 6184 <i class="mdi mdi-phone-in-talk"></i> 6185 +54 261 248 0888 </a> 6186 </li> 6187 6188 <li> 6189 <a href="tel: +54 261 248 1006"> 6190 <i class="mdi mdi-phone-in-talk"></i> 6191 +54 261 248 1006 6192 </a> 6193 </li> 6194 6195 <li>
6196 <a href="https://api.whatsapp.com/send?phone=542612480888" target="_blank"> 6197 <i class="mdi mdi-whatsapp"></i> 6198 +54 261 248 0888 </a> 6199 </li> 6200 6201 <li> 6202 <a href="https://www.google.com/maps/search/Hotel Premium Tower Suites, Av. España 948, M5500 Mendoza, Argentina Mendoza - Argentina" target="_blank"> 6203 <i class="mdi mdi-map-marker"></i> 6204 Av. España 948, M5500 Mendoza, Argentina </a> 6205 </li> 6206 6207 <li> 6208 <a href="/cdn-cgi/l/email-protection#b8caddcbddcaced9cbf8c8caddd5d1cdd5ccd7cfddcadfcad7cdc896dbd7d596d9ca"> 6209 <i class="mdi mdi-email"></i> 6210 <span class="__cf_email__" data-cfemail="94e6f1e7f1e6e2f5e7d4e4e6f1f9fde1f9e0fbe3f1e6f3e6fbe1e4baf7fbf9baf5e6">[email protected]</span> </a> 6211 </li> 6212 </ul> 6213</div> 6214 </div> 6215 </div></div><div class="logo" > <img loading="lazy" class="" lazy-src="https://picsv3.pxsol.com/18413/company/library/user/34464345120d57352cb6880b02f98dd39a87e622c7.png?ixlib=js-2.3.2&s=8403b09995ab0dc78d81a586e8eaddac" alt="PremiumTowerApartHotel" > </image></div><div class="social" ><div class="" ><div class='' > 6216 <div class="neo_template_block neo_neo_social_links pxModule_include ModuloWrap_neo_social_links" id="neo_social_links" > 6217 6218 6219<div class="neo_social_links_container social_block"> 6220 <ul class="neo_links_list"> 6221 <li class="facebook_page"> 6222 <a href="https://www.facebook.com/PremiumTowerSuites/" target="_blank"> 6223 <i class="mdi mdi-facebook"></i> 6224 </a> 6225 </li> 6226 <li class="instagram_page"> 6227 <a href="https://www.instagram.com/premiumtower/" target="_blank"> 6228 <i class="mdi mdi-instagram"></i> 6229 </a> 6230 </li> 6231 <li class="tripadvisor_page"> 6232 <a href="https://www.tripadvisor.com.ar/Hotel_Review-g312781-d1027928-Reviews-Premium_Tower_Suites_Mendoza-Mendoza_Province_of_Mendoza_Cuyo.html" target="_blank"> 6233 <svg version="1.1" x="0px" y="0px" width="32px" height="32px" viewBox="0 0 98.566 98.566" style="enable-background:new 0 0 98.566 98.566;" xml:space="preserve"> 6234 <g> 6235 <g> 6236 <path d="M60.401,20.996c2.751,0.389,5.445,1.08,8.107,1.898c4.647,1.431,9.032,3.419,13.156,5.998 6237 c0.287,0.178,0.67,0.291,1.008,0.291c4.844,0.02,9.686,0.013,14.526,0.017c0.39,0,0.778,0.041,1.167,0.063 6238 c0,0.095,0.014,0.135-0.002,0.157c-0.226,0.348-0.455,0.691-0.682,1.038c-1.643,2.52-3.047,5.156-3.876,8.07 6239 c-0.09,0.313-0.109,0.575,0.103,0.882c4.312,6.192,5.688,12.99,3.886,20.318c-1.58,6.427-5.264,11.438-10.862,14.986 6240 c-4.001,2.537-8.421,3.745-13.143,3.771c-1.984,0.012-3.958-0.255-5.896-0.757c-4.722-1.225-8.77-3.579-12.106-7.144 6241 c-0.44-0.468-0.854-0.957-1.323-1.486c-1.764,2.629-3.5,5.215-5.278,7.869c-1.771-2.646-3.483-5.207-5.191-7.758 6242 c-0.118,0.062-0.152,0.069-0.175,0.091c-0.039,0.032-0.072,0.071-0.103,0.108c-4.035,4.765-9.111,7.686-15.295,8.663 6243 c-3.44,0.545-6.847,0.349-10.188-0.572c-4.735-1.301-8.759-3.799-12.01-7.485c-3.177-3.604-5.153-7.788-5.895-12.545 6244 c-0.849-4.44,0.185-8.721,0.443-9.76c0.748-3.02,2.052-5.793,3.842-8.343c0.126-0.181,0.17-0.501,0.11-0.717 6245 c-0.73-2.677-1.988-5.112-3.461-7.444c-0.374-0.593-0.822-1.142-1.236-1.711c0-0.065,0-0.132,0-0.198 6246 c0.083,0.01,0.165,0.026,0.246,0.026c4.956,0.002,9.911,0.004,14.867-0.006c0.216,0,0.456-0.089,0.64-0.207 6247 c3.482-2.234,7.192-4.004,11.09-5.382c2.811-0.992,5.681-1.766,8.608-2.333c2.834-0.548,5.683-0.934,8.562-1.124 6248 C51.059,19.73,56.669,20.473,60.401,20.996z M54.188,53.727c0,10.883,8.83,19.774,19.674,19.732 6249 c10.885-0.039,19.675-8.68,19.667-19.683c-0.008-11.339-9.206-19.863-20.089-19.642C62.696,34.357,54.286,43.017,54.188,53.727z 6250 M24.677,34.059C14.091,33.967,4.861,42.802,5.046,54.056c0.172,10.495,8.822,19.392,19.851,19.297 6251 c10.784-0.092,19.452-8.898,19.472-19.562C44.386,42.835,35.612,34.059,24.677,34.059z M25.653,28.925 6252 c5.98,0.365,11.233,2.449,15.671,6.485c4.429,4.028,7.024,9.053,7.967,14.962c0.97-5.839,3.497-10.817,7.843-14.805 6253 c4.353-3.992,9.536-6.087,15.418-6.53c-6.98-3.103-14.34-4.421-21.916-4.567C42.026,24.301,33.651,25.57,25.653,28.925z" /> 6254 <path d="M73.822,41.311c6.735-0.011,12.19,5.415,12.19,12.143c0,6.754-5.362,11.975-11.688,12.216 6255 c-7.065,0.271-12.718-5.358-12.716-12.186C61.614,46.578,67.307,41.197,73.822,41.311z M81.766,53.484 6256 c-0.003-4.39-3.552-7.958-7.912-7.958c-4.41,0-8,3.549-8.018,7.926c-0.016,4.358,3.592,7.984,7.961,7.996 6257 C78.173,61.465,81.768,57.866,81.766,53.484z" /> 6258 <path d="M24.417,41.311c6.731-0.007,12.194,5.429,12.177,12.156c-0.019,6.809-5.386,11.916-11.601,
625812.199 6259 c-7.093,0.324-12.816-5.33-12.803-12.195C12.204,46.516,17.936,41.195,24.417,41.311z M32.352,53.457 6260 c-0.013-4.417-3.585-7.938-8.044-7.93c-4.301,0.008-7.905,3.638-7.895,7.955c0.011,4.367,3.611,7.958,7.992,7.97 6261 C28.759,61.462,32.363,57.836,32.352,53.457z" /> 6262 <path d="M73.828,49.443c2.232-0.002,4.062,1.829,4.041,4.048c-0.022,2.224-1.821,4.026-4.016,4.027 6263 c-2.26,0-4.077-1.786-4.072-3.999C69.785,51.223,71.55,49.445,73.828,49.443z" /> 6264 <path d="M24.396,49.407c2.266-0.002,4.087,1.808,4.096,4.067c0.009,2.24-1.829,4.079-4.084,4.084 6265 c-2.309,0.005-4.09-1.779-4.088-4.1C20.32,51.179,22.097,49.41,24.396,49.407z" /> 6266 </g> 6267 </g> 6268 </svg> 6269 </a> 6270 </li> 6271 </ul> 6272</div> 6273 <div class="wsp_floating"> 6274 <a href="https://api.whatsapp.com/send?phone=542612480888" target="_blank"> 6275 <i class="mdi mdi-whatsapp"></i> 6276 </a> 6277 </div> 6278 </div> 6279 </div></div><div class="" ><div class='' ><div class='pxModule_include ModuloWrap_newsletter '><div id="content_news"> 6280 <div class="left full titlenewsletter">SUBSCRIBE TO OUR NEWSLETTER</div> 6281 <form id="form_suscribe" name="form_suscribe" method="post" action="/contact/newsletter"> 6282 <div class="wrap_imputs"> 6283 <div class="wrap_emails"> 6284 <input name="email" type="text" id="email" class="input_newsletter" value="" placeholder="Enter your Email" /> 6285 </div> 6286 <div class="SuscribeTitle"> 6287 <div id="newsletter-recaptcha" data-sitekey="6LfWJEIUAAAAANStHukodcdKv4tnwSFLknAMB_FM"></div> 6288 <button type="submit" onClick="ga('send','event','click','boton_suscribirse','form_suscribirse');" class="boton_newsletter" id="Import">to subscribe</button> 6289 <input name="company_id" type="hidden" id="company_id" value="18413" /> 6290 </div> 6291 </div> 6292 </form> 6293</div> 6294</div></div></div></div></div><div class="leyenda-container" ><span class='' >RENTAPART MENDOZA SAS - Todos los derechos reservados</span></div></div> 6295 6296</div> 6297 6298 <div id="footer_px" class="noprint footer_px_fix" style="max-width: 100vw; box-sizing: border-box; overflow-x: hidden;"> 6299 <div class="wraper_footerpx flex-column flex-center"> 6300 6301 6302 <div class="texto_footerpx"> 6303 By using this website, you agree to the use of cookies. <a target="_blank" rel="nofollow" href="/cookiespolicies.php?pos=PremiumTowerApartHotel" class="footer_link">Cookies policy</a> | <a target="_blank" rel="nofollow" href="/terms.php?pos=PremiumTowerApartHotel" class="footer_link">Terminos y Condiciones</a> | <a target="_blank" rel="nofollow" href="/policies.php?pos=PremiumTowerApartHotel" class="footer_link">Privacy Policy</a> | <span>Cache: 6304 2026-09-26 02:10:50 | </span><a href="" rel="nofollow" target="_blank">Textos</a> | <span class="framework_f">Framework: 3 | <span class="framework_f">Tag: <span class="tag_cookie">..</span> </span> </span> 6305 </div> 6306 6307 <div class="pxsol_link_f"> 6308 <a style="text-decoration: underline !important;" target="_blank" href="https://www.pxsol.com/pos_source=PremiumTowerApartHotel" class="footer_link">Sistema Hotelero</a> 6309 por <a href="/" target="_blank" class="footer_link footer_logo_svg" title="Sistema Hotelero"> 6310 <?xml version="1.0" encoding="UTF-8" standalone="no"?> 6311<svg 6312 xmlns:dc="http://purl.org/dc/elements/1.1/" 6313 xmlns:cc="http://creativecommons.org/ns#" 6314 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 6315 xmlns:svg="http://www.w3.org/2000/svg" 6316 xmlns="http://www.w3.org/2000/svg" 6317 viewBox="0 0 752.42535 358.37866" 6318 height="50px" 6319 width="23px" 6320 xml:space="preserve" 6321 id="svg2" 6322 version="1.1"><metadata 6323 id="metadata8"><rdf:RDF><cc:Work 6324 rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type 6325 rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs 6326 id="defs6"><clipPath 6327 id="clipPath18" 6328 clipPathUnits="userSpaceOnUse"><path 6329 id="path16" 6330 d="M 0,268.784 H 564.319 V 0 H 0 Z" /></clipPath></defs><g 6331 transform="matrix(1.3333333,0,0,-1.3333333,0,358.37867)" 6332 id="g10"><g 6333 id="g12"><g 6334 clip-path="url(#clipPath18)" 6335 id="g14"><g 6336 transform="translate(23.3438,154.8828)" 6337 id="g20"><path 6338 id="path22" 6339 style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" 6340 d="m 0,0 h 12.405 c 11.978,0 20.768,1.891 26.369,5.674 5.601,3.781 8.4,9.691 8.4,17.728 0,7.447 -2.507,13.002 -7.521,16.666 -5.013,3.664 -12.828,5.496 -23.44,5.496 H 0 Z m 71.202,24.112 c 0,-13.534 -4.884,-23.905 -14.65,-31.115 -9.768,-7.21 -23.67,-10.814 -41.707,-10.814 H 0 V -66.309 H -23.344 V 63.294 h 41.118 c 17.841,0 31.207,-3.311 40.097,-9.929 8.886,-6.619 13.331,-16.37 13.331,-29.253" /></g><g 6341 transform="translate(325.4336,123.7686)" 6342 id="g24"><path 6343 id="path26" 6344 style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none"
6345 d="m 0,0 c 0,-11.524 -4.59,-20.565 -13.773,-27.126 -9.179,-6.561 -21.846,-9.84 -37.994,-9.84 -16.149,0 -29.367,2.274 -39.653,6.824 v 20.036 c 6.509,-2.78 13.43,-4.964 20.754,-6.56 7.327,-1.596 14.147,-2.392 20.462,-2.392 9.246,0 16.068,1.594 20.462,4.785 4.396,3.191 6.595,7.475 6.595,12.853 0,4.847 -2.02,8.956 -6.057,12.323 -4.039,3.369 -12.372,7.358 -25.005,11.968 -13.023,4.787 -22.204,10.252 -27.542,16.4 -5.341,6.145 -8.01,13.532 -8.01,22.161 0,10.815 4.233,19.324 12.698,25.53 8.463,6.205 19.827,9.308 34.087,9.308 13.675,0 27.284,-2.719 40.829,-8.156 L -9.572,70.829 c -12.697,4.844 -24.028,7.269 -33.99,7.269 -7.555,0 -13.285,-1.494 -17.19,-4.477 -3.906,-2.985 -5.86,-6.93 -5.86,-11.834 0,-3.369 0.781,-6.25 2.344,-8.644 1.563,-2.393 4.134,-4.653 7.716,-6.782 3.58,-2.127 10.026,-4.935 19.339,-8.421 10.484,-3.959 18.166,-7.654 23.05,-11.08 4.884,-3.429 8.464,-7.3 10.745,-11.613 C -1.14,10.933 0,5.85 0,0" /></g><g 6346 transform="translate(355.8486,153.5532)" 6347 id="g28"><path 6348 id="path30" 6349 style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" 6350 d="m 0,0 c 0,-15.956 3.547,-28.057 10.646,-36.299 7.097,-8.245 17.614,-12.369 31.548,-12.369 13.87,0 24.335,4.08 31.401,12.235 7.064,8.155 10.598,20.3 10.598,36.433 0,15.897 -3.501,27.953 -10.5,36.168 C 66.693,44.382 56.26,48.49 42.39,48.49 28.391,48.49 17.826,44.382 10.694,36.168 3.564,27.953 0,15.897 0,0 m 109.001,0 c 0,-21.097 -5.811,-37.498 -17.434,-49.198 C 79.946,-60.901 63.486,-66.75 42.194,-66.75 c -21.553,0 -38.108,5.806 -49.667,17.418 -11.558,11.613 -17.334,28.116 -17.334,49.509 0,21.394 5.81,37.823 17.433,49.288 11.622,11.464 28.21,17.198 49.764,17.198 21.227,0 37.635,-5.822 49.227,-17.464 C 103.205,37.556 109.001,21.156 109.001,0" /></g><g 6351 transform="translate(480.5166,88.5742)" 6352 id="g32"><path 6353 id="path34" 6354 style="fill:#231f20;fill-opacity:1;fill-rule:nonzero;stroke:none" 6355 d="M 0,0 V 129.603 H 23.342 V 18.175 H 83.803 V 0 Z" /></g><g 6356 transform="translate(95.5459,218.4404)" 6357 id="g36"><path 6358 id="path38" 6359 style="fill:#ee2735;fill-opacity:1;fill-rule:nonzero;stroke:none" 6360 d="m 0,0 42.967,-58.803 -68.085,-93.3 30.263,-9.074 56.235,77.141 87.961,-120.538 46.28,-13.866 L 79.583,-59.091 159.441,50.344 112.198,36.084 60.982,-33.892 29.65,9.046 Z" /></g></g></g></g></svg> </a> 6361 </div> 6362 6363 </div> 6364</div>
vendor: 111 bytes, lines 6364-6367
6364 6365 6366 6367<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
6367<script> 6368 function loadPxChatWidget() { 6369 const posToGetApiKey = 'PremiumTowerApartHotel'; 6370 const timestamp = '1789161380'; 6371 const urlToGetApiKey = `https://px-chat-widget-prod.pxsol.com/company-widget/apiKey/${posToGetApiKey}?v=${timestamp}`; 6372 6373 fetch(urlToGetApiKey, { 6374 method: 'GET', 6375 headers: { 6376 'Content-Type': 'application/json', 6377 } 6378 }) 6379 .then(response => { 6380 if (!response.ok) { 6381 throw new Error(`HTTP error! status: ${response.status}`); 6382 } 6383 return response.json(); 6384 }) 6385 .then(data => { 6386 const internalKey = data?.data?.api_key; 6387 if (!internalKey) { 6388 throw new Error('API key not found in response'); 6389 } 6390 6391 const script = document.createElement('script'); 6392 script.src = `https://cdn.pxsol.com/dist/chat-widget.min.js?k=${internalKey}&v=${timestamp}`; 6393 script.async = true; 6394 script.onload = () => { 6395 console.log('PxChat widget loaded successfully'); 6396 }; 6397 script.onerror = (error) => { 6398 console.error('Failed to load PxChat widget:', error); 6399 }; 6400 document.body.appendChild(script); 6401 }) 6402 .catch(error => { 6403 console.error('PxChat widget initialization failed:', error.message); 6404 }); 6405 } 6406 document.addEventListener("DOMContentLoaded", loadPxChatWidget); 6407 </script>
6407 6408 6409<style> 6410 /* El botón flotante de WhatsApp (.wsp_floating) y el launcher del widget de chat (pxChat) 6411 se ubican ambos en la esquina inferior derecha y chocan entre sÃ. Cuando el chat está 6412 activo/montado, ocultamos el botón de WhatsApp para evitar la superposición. */ 6413 body.px-chat-widget-active .wsp_floating { display: none !important; } 6414</style>
6415<script> 6416 (function () { 6417 // El widget pxChat monta su launcher/panel bajo #px-widget-root (clase .widget-launcher-button). 6418 function chatWidgetPresent() { 6419 return !!( 6420 document.getElementById('px-widget-root') || 6421 document.querySelector('.widget-launcher-button, [class*="widget-launcher"]') 6422 ); 6423 } 6424 var applied = false; 6425 var observer = null; 6426 var fallbackTimer = null; 6427 function apply() { 6428 if (applied || !document.body || !chatWidgetPresent()) return; 6429 document.body.classList.add('px-chat-widget-active'); 6430 applied = true; 6431 if (observer) observer.disconnect(); 6432 if (fallbackTimer) clearTimeout(fallbackTimer); 6433 } 6434 function start() { 6435 apply(); 6436 if (applied || !('MutationObserver' in window) || !document.body) return; 6437 // El widget carga async (fetch de apiKey + inyección del
6437<script>), asà que observamos 6438 // el DOM hasta que aparezca. Si a los 20s no montó, dejamos de observar. 6439 observer = new MutationObserver(apply); 6440 observer.observe(document.body, { childList: true, subtree: true }); 6441 fallbackTimer = setTimeout(function () { 6442 if (observer) observer.disconnect(); 6443 }, 20000); 6444 } 6445 if (document.readyState === 'loading') { 6446 document.addEventListener('DOMContentLoaded', start); 6447 } else { 6448 start(); 6449 } 6450 })(); 6451</script>
6451 6452
6453<script src="https://cdn.pxsol.com/js/domready.js"></script>
vendor: 1 bytes, line 6453
6453
6454<script> 6455 var head = document.getElementsByTagName('head')[0]; 6456 6457 function initializeFontAwesome() { 6458 var link = document.createElement('link'); 6459 link.id = "fawesome"; 6460 link.rel = 'stylesheet'; 6461 link.type = 'text/css'; 6462 link.href = 'https://use.fontawesome.com/releases/v5.7.1/css/all.css'; 6463 head.appendChild(link); 6464 } 6465 6466 function initializeMDI() { 6467 var link = document.createElement('link'); 6468 link.id = "fawesome"; 6469 link.rel = 'stylesheet'; 6470 link.type = 'text/css'; 6471 link.href = '/css/materialdesignicons.min.css'; 6472 head.appendChild(link); 6473 } 6474 6475 function initializeToast() { 6476 // check if jquery is loaded 6477 if (typeof jQuery == 'function') { 6478 let link = document.createElement('link'); 6479 link.id = "jqToastCss"; 6480 link.rel = 'stylesheet'; 6481 link.type = 'text/css'; 6482 link.href = '/includes/toast/jquery.toast.min.css'; 6483 head.appendChild(link); 6484 let script = document.createElement('script'); 6485 script.id = "jqToastJs"; 6486 script.type = 'text/javascript'; 6487 script.defer = true; 6488 script.async = true; 6489 script.src = '/includes/toast/jquery.toast.min.js'; 6490 head.appendChild(script); 6491 } else { 6492 console.log('jQuery is not loaded. Toast could not be initialized.'); 6493 } 6494 } 6495 6496 DomReady.ready(function() { 6497 var link = document.createElement('link'); 6498 link.id = "siteCss"; 6499 link.rel = 'stylesheet'; 6500 link.type = 'text/css'; 6501 6502 link.href = 6503 '/css_3.css?pos=PremiumTowerApartHotel&device=computer&posv=1789161380_2026-04-24T21:33:04.000Z&filev=1782498034'; 6504 head.appendChild(link); 6505 6506 if (typeof deferFontAwesome !== "undefined") { 6507 if (!deferFontAwesome) { 6508 initializeFontAwesome(); 6509 } 6510 } else { 6511 initializeFontAwesome(); 6512 } 6513 6514 if (typeof deferMDI !== "undefined") { 6515 if (!deferMDI) { 6516 initializeMDI(); 6517 } 6518 } else { 6519 initializeMDI(); 6520 } 6521 6522 if (typeof deferToast !== "undefined") { 6523 if (!deferToast) { 6524 initializeToast(); 6525 } 6526 } else { 6527 initializeToast(); 6528 } 6529 6530 }); 6531</script>
vendor: 1 bytes, line 6531
6531
6532<script> 6533 (function(){ 6534 console.log('%c[pxChat] ð Chat tracking script loaded (Chromium optimized)', 'color: #4CAF50; font-weight: bold; font-size: 14px;'); 6535 window.dataLayer = window.dataLayer || []; 6536 function generateId(prefix){ 6537 const rnd = ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c => 6538 (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) 6539 ); 6540 return (prefix || 'id_') + rnd; 6541 } 6542 function getPxContext(){ 6543 try { return window.pxContext || {}; } catch(e){ return {}; } 6544 } 6545 function getSessionId(){ 6546 const ctx = getPxContext(); 6547 if (ctx.session_id) return ctx.session_id; 6548 let sid = sessionStorage.getItem('px_session_id'); 6549 if (!sid){ sid = generateId('s_'); sessionStorage.setItem('px_session_id', sid); } 6550 return sid; 6551 } 6552 function getChatSessionId(){ 6553 let cid = sessionStorage.getItem('px_chat_session_id'); 6554 if (!cid){ cid = generateId('c_'); sessionStorage.setItem('px_chat_session_id', cid); } 6555 return cid; 6556 } 6557 function basePayload(){ 6558 const ctx = getPxContext(); 6559 const pos = (ctx.pos || 'PremiumTowerApartHotel') || null; 6560 const hotelId = (ctx.product_id || '19433') || null; 6561 return { 6562 session_id: getSessionId(), 6563 search_id: ctx.search_id || ctx.SearchID || null, 6564 pos: pos, 6565 post: pos, 6566 hotel_id: hotelId, 6567 page_url: location.href 6568 }; 6569 } 6570 function pushEvent(name, extra){ 6571 const params = Object.assign({}, basePayload(), extra || {}); 6572 // Dedupe: evita repetidos en ±1s por sesión/mensaje 6573 try { 6574 const keyId = params.chat_session_id || params.chat_id || ''; 6575 const key = name + '|' + String(keyId); 6576 const now = Date.now(); 6577 window.__px_evt_dedupe = window.__px_evt_dedupe || {}; 6578 const last = window.__px_evt_dedupe[key] || 0; 6579 if (now - last < 1000) { 6580 return; 6581 } 6582 window.__px_evt_dedupe[key] = now; 6583 } catch(_e){ 6584 console.error('[pxChat] Error in pushEvent dedupe:', _e); 6585 } 6586 // Evitar duplicados: si pxTrack existe, delegamos y NO empujamos a dataLayer aquà 6587 if (typeof window.pxTrack === 'function') { 6588 try { 6589 console.log('[pxChat] ð¤ Calling pxTrack for', name, 'with params:', params); 6590 window.pxTrack(name, params); 6591 console.log('%c[pxChat] â ' + name + ' event dispatched successfully', 'color: #4CAF50; font-weight: bold;'); 6592 } catch(e){ 6593 console.error('[pxChat] â Error calling window.pxTrack for', name, ':', e); 6594 } 6595 return; 6596 } 6597 const payload = Object.assign({ event: name }, params); 6598 console.log('[pxChat] ð¤ Pushing to dataLayer:', payload); 6599 window.dataLayer.push(payload); 6600 console.log('%c[pxChat] â ' + name + ' event pushed to dataLayer', 'color: #4CAF50; font-weight: bold;'); 6601 } 6602 let chatOpenTsMs = null; 6603 let chatIsOpen = false; 6604 let lastOpenPushMs = 0; 6605 let closeGuardTimer = null; 6606 let lastStateChangeMs = 0; 6607 let lastCloseCallMs = 0; // Guard para prevenir múltiples llamadas rápidas a handleChatClose 6608 let lastOpenCallMs = 0; // Guard para prevenir múltiples llamadas rápidas a handleChatOpen 6609 let MIN_CHAT_DURATION_MS = 3000; // MÃnimo 3 segundos entre chat_open y chat_close (previene falsos positivos en Chrome) 6610 let OPEN_DEBOUNCE_MS = 300; // Debounce para chat_open (300ms - solo para múltiples llamadas rápidas) 6611 let CLOSE_DEBOUNCE_MS = 400; // Debounce para chat_close (400ms - solo para múltiples llamadas rápidas) 6612 let pendingOpenTimer = null; // Timer para debounce de open 6613 let pendingCloseTimer = null; // Timer para debounce de close 6614 let openCallCount = 0; // Contador de llamadas rápidas a open 6615 let closeCallCount = 0; // Contador de llamadas rápidas a close 6616 function syncChatState(){ 6617 try { 6618 // Guard mÃnimo: no sincronizar si acabamos de cambiar estado hace menos de 200ms 6619 const now = Date.now(); 6620 if (now - lastStateChangeMs < 200) { 6621 console.log('[pxChat] syncChatState throttled (' + (now - lastStateChangeMs) + 'ms ago)'); 6622 return; 6623 } 6624 // Priorizar estado del launcher: clase --open 6625 // Buscar el botón con múltiples selectores 6626 const btn = document.querySelector('.widget-launcher-button') || 6627 document.querySelector('[class*="widget-launcher"]') || 6628 document.querySelector('[class*="launcher-button"]'); 6629 if (btn && btn.classList) { 6630 const isOpenBtn = btn.classList.contains('widget-launcher-button--open') || 6631 btn.classList.toString().indexOf('--open') !== -1; 6632 console.log('[pxChat] syncChatState: button state check:', { 6633 isOpenBtn: isOpenBtn, 6634 chatIsOpen: chatIsOpen,
6635 buttonClasses: btn.className 6636 }); 6637 if (isOpenBtn && !chatIsOpen) { 6638 console.log('[pxChat] syncChatState: button is open but chatIsOpen is false, calling handleChatOpen'); 6639 lastStateChangeMs = now; 6640 return handleChatOpen(); 6641 } 6642 if (!isOpenBtn && chatIsOpen) { 6643 // Guard mÃnimo: no cerrar si el chat se abrió hace menos de 3 segundos 6644 const startMs = chatOpenTsMs || lastOpenPushMs || null; 6645 if (startMs && (now - startMs < 3000)) { 6646 console.log('[pxChat] syncChatState: chat_close blocked - chat opened too recently (' + Math.round((now - startMs) / 1000) + 's ago, minimum 3s)'); 6647 return; 6648 } 6649 // CRÃTICO: Esperar y verificar nuevamente que el botón realmente está cerrado 6650 // Esto previene disparos prematuros cuando el DOM aún se está actualizando 6651 setTimeout(function() { 6652 const btnCheck = document.querySelector('.widget-launcher-button') || 6653 document.querySelector('[class*="widget-launcher"]') || 6654 document.querySelector('[class*="launcher-button"]'); 6655 const isStillOpen = btnCheck && btnCheck.classList && ( 6656 btnCheck.classList.contains('widget-launcher-button--open') || 6657 btnCheck.classList.toString().indexOf('--open') !== -1 6658 ); 6659 const ifrCheck = findChatIframe(); 6660 const isIframeVisible = isElementVisible(ifrCheck); 6661 6662 console.log('[pxChat] syncChatState: delayed verification after button close:', { 6663 isStillOpen: isStillOpen, 6664 isIframeVisible: isIframeVisible, 6665 chatIsOpen: chatIsOpen 6666 }); 6667 6668 if (isStillOpen) { 6669 console.log('[pxChat] syncChatState: chat_close CANCELLED - button still shows as open after delay'); 6670 return; 6671 } 6672 if (isIframeVisible) { 6673 console.log('[pxChat] syncChatState: chat_close CANCELLED - iframe still visible after delay'); 6674 return; 6675 } 6676 if (!chatIsOpen) { 6677 console.log('[pxChat] syncChatState: chat_close CANCELLED - chatIsOpen is already false'); 6678 return; 6679 } 6680 6681 console.log('[pxChat] syncChatState: button confirmed closed after delay, calling handleChatClose'); 6682 lastStateChangeMs = Date.now(); 6683 handleChatClose(); 6684 }, 600); // Esperar 600ms para confirmar que el DOM se actualizó completamente 6685 return; 6686 } 6687 } 6688 // CRÃTICO: NO usar iframe como fallback si hay un botón disponible 6689 // El iframe puede no ser visible incluso cuando el chat está abierto 6690 // Solo confiar en el botón launcher para determinar el estado 6691 if (!btn) { 6692 // Solo si NO hay botón, intentar buscar el botón de nuevo con un selector más amplio 6693 const btnRetry = document.querySelector('.widget-launcher-button, [class*="widget-launcher"], [class*="launcher-button"]'); 6694 if (btnRetry && btnRetry.classList) { 6695 const isOpenBtnRetry = btnRetry.classList.contains('widget-launcher-button--open') || 6696 btnRetry.classList.toString().indexOf('--open') !== -1; 6697 console.log('[pxChat] syncChatState: retry button found:', { 6698 isOpenBtnRetry: isOpenBtnRetry, 6699 chatIsOpen: chatIsOpen, 6700 buttonClasses: btnRetry.className 6701 }); 6702 if (isOpenBtnRetry && !chatIsOpen) { 6703 console.log('[pxChat] syncChatState: retry button is open but chatIsOpen is false, calling handleChatOpen'); 6704 lastStateChangeMs = now; 6705 return handleChatOpen(); 6706 } 6707 if (!isOpenBtnRetry && chatIsOpen) { 6708 // Guard mÃnimo: no cerrar si el chat se abrió hace menos de 3 segundos 6709 const startMs = chatOpenTsMs || lastOpenPushMs || null; 6710 if (startMs && (now - startMs < 3000)) { 6711 console.log('[pxChat] syncChatState: chat_close blocked - chat opened too recently (' + Math.round((now - startMs) / 1000) + 's ago, minimum 3s)'); 6712 return; 6713 } 6714 // Verificar nuevamente antes de cerrar 6715 setTimeout(function() { 6716 const btnCheck = document.querySelector('.widget-launcher-button, [class*="widget-launcher"], [class*="launcher-button"]'); 6717 const isStillOpen = btnCheck && (btnCheck.classList.contains('widget-launcher-button--open') || 6718 btnCheck.classList.toString().indexOf('--open') !== -1); 6719 6720 if (isStillOpen || !chatIsOpen) { 6721 console.log('[pxChat] syncChatState: chat_close CANCELLED - button still open or chatIsOpen is false'); 6722 return; 6723 } 6724 6725 console.log('[pxChat] syncChatState: retry button confirmed closed after delay, calling handleChatClose'); 6726 lastStateChangeMs = Date.now(); 6727 handleChatClose(); 6728 }, 600); 6729 return; 6730 } 6731 } 6732 6733 // ÃLTIMO RECURSO: Solo usar iframe si NO hay botón Y el chat está abierto 6734 // Y solo para abrir, NUNCA para cerrar (el iframe no es confiable para cerrar) 6735 const ifr = findChatIframe(); 6736 const visible = isElementVisible(ifr); 6737 console.log('[pxChat] syncChatState: iframe LAST RESORT check (only for opening):', { 6738 visible: visible, 6739 chatIsOpen: chatIsOpen, 6740 hasIframe: !!ifr 6741 }); 6742 // Solo usar iframe para detectar apertura, NUNCA para cerrar 6743 if (visible && !chatIsOpen) { 6744 console.log('[pxChat] syncChatState: iframe visible but chatIsOpen is false, calling handleChatOpen'); 6745 lastStateChangeMs = now; 6746 return handleChatOpen(); 6747 } 6748 // NO usar iframe para cerrar - solo confiar en el botón 6749 if (!visible && chatIsOpen) { 6750 console.log('[pxChat] syncChatState: iframe not visible but chatIsOpen is true - IGNORING (iframe not reliable for closing)'); 6751 return; // NO hacer nada - solo el botón puede cerrar 6752 } 6753 } 6754 } catch(_e){ 6755 console.error('[pxChat] syncChatState error:', _e); 6756 } 6757 } 6758 function handleChatOpen(meta){ 6759 console.log('[pxChat] handleChatOpen called:', { chatIsOpen: chatIsOpen, meta: meta }); 6760 6761 // Si ya está abierto, no hacer nada 6762 if (chatIsOpen) { 6763 console.log('[pxChat] handleChatOpen skipped - chat already open'); 6764 return; 6765 } 6766 6767 const now = Date.now(); 6768
6769 // Guard mÃnimo: no abrir si se cerró hace menos de 500ms (solo para prevenir toggle extremo) 6770 if (lastCloseCallMs && (now - lastCloseCallMs < 500)) { 6771 console.log('[pxChat] handleChatOpen blocked - chat closed too recently (' + (now - lastCloseCallMs) + 'ms ago)'); 6772 return; 6773 } 6774 6775 // Throttling mÃnimo: solo prevenir llamadas duplicadas en menos de 200ms 6776 if (now - lastOpenCallMs < 200) { 6777 console.log('[pxChat] handleChatOpen throttled (too soon)'); 6778 return; 6779 } 6780 6781 lastOpenCallMs = now; 6782 6783 // Cancelar cualquier close pendiente 6784 if (pendingCloseTimer) { 6785 clearTimeout(pendingCloseTimer); 6786 pendingCloseTimer = null; 6787 console.log('[pxChat] handleChatOpen: cancelled pending close'); 6788 } 6789 6790 // Disparar inmediatamente (sin debounce para Chromium) 6791 console.log('[pxChat] handleChatOpen: calling doChatOpen immediately'); 6792 doChatOpen(meta); 6793 } 6794 6795 function doChatOpen(meta) { 6796 // Verificar estado del botón (prioridad máxima para Chromium) 6797 // Buscar el botón con múltiples selectores 6798 const btn = document.querySelector('.widget-launcher-button') || 6799 document.querySelector('[class*="widget-launcher"]') || 6800 document.querySelector('[class*="launcher-button"]'); 6801 const isActuallyOpen = btn && btn.classList && ( 6802 btn.classList.contains('widget-launcher-button--open') || 6803 btn.classList.toString().indexOf('--open') !== -1 6804 ); 6805 const ifr = findChatIframe(); 6806 const isIframeVisible = isElementVisible(ifr); 6807 6808 // Log detallado para debugging en Chromium 6809 console.log('[pxChat] doChatOpen called:', { 6810 isActuallyOpen: isActuallyOpen, 6811 isIframeVisible: isIframeVisible, 6812 chatIsOpen: chatIsOpen, 6813 hasButton: !!btn, 6814 buttonClasses: btn ? btn.className : 'no button' 6815 }); 6816 6817 // Si el botón existe y dice que está abierto, proceder 6818 // Si no hay botón pero el iframe es visible, también proceder 6819 if (!isActuallyOpen && !isIframeVisible && btn) { 6820 console.warn('[pxChat] doChatOpen: button exists but not showing as open, proceeding anyway'); 6821 } 6822 6823 // Guardar timestamp ANTES de cambiar el estado (importante para Chrome) 6824 const now = Date.now(); 6825 chatOpenTsMs = now; 6826 lastOpenPushMs = now; 6827 chatIsOpen = true; 6828 const chat_session_id = (meta && (meta.chat_session_id || meta.session_id)) || getChatSessionId(); 6829 6830 // Log para debugging 6831 console.log('[pxChat] ð FIRING chat_open event:', { 6832 chatOpenTsMs: chatOpenTsMs, 6833 lastOpenPushMs: lastOpenPushMs, 6834 timestamp: now, 6835 chat_session_id: chat_session_id 6836 }); 6837 pushEvent('chat_open', { chat_session_id }); 6838 } 6839 function handleChatMessage(meta){ 6840 const chat_id = meta && (meta.chat_id || meta.message_id) || null; 6841 const message_type = meta && (meta.message_type || meta.type) || null; 6842 const payload = { chat_id, message_type }; 6843 pushEvent('chat_message', payload); 6844 } 6845 function handleChatClose(meta){ 6846 console.log('[pxChat] handleChatClose called:', { chatIsOpen: chatIsOpen, meta: meta }); 6847 6848 // Si ya está cerrado, no hacer nada 6849 if (!chatIsOpen) { 6850 console.log('[pxChat] handleChatClose skipped - chat already closed'); 6851 return; 6852 } 6853 6854 const now = Date.now(); 6855 6856 // Guard crÃtico: prevenir que chat_close se dispare inmediatamente después de chat_open 6857 // Aumentado a 3 segundos para evitar disparos prematuros 6858 const startMs = chatOpenTsMs || lastOpenPushMs || null; 6859 if (startMs && (now - startMs < 3000)) { 6860 console.log('[pxChat] handleChatClose blocked - chat opened too recently (' + Math.round((now - startMs) / 1000) + 's ago, minimum 3s required)'); 6861 return; 6862 } 6863 6864 // Verificación adicional: asegurarse de que el botón realmente está cerrado 6865 // Buscar el botón con múltiples selectores 6866 const btn = document.querySelector('.widget-launcher-button') || 6867 document.querySelector('[class*="widget-launcher"]') || 6868 document.querySelector('[class*="launcher-button"]'); 6869 const isActuallyOpen = btn && btn.classList && ( 6870 btn.classList.contains('widget-launcher-button--open') || 6871 btn.classList.toString().indexOf('--open') !== -1 6872 ); 6873 if (isActuallyOpen) { 6874 console.log('[pxChat] handleChatClose blocked - button still shows as open'); 6875 return; 6876 } 6877 6878 // Throttling mÃnimo: solo prevenir llamadas duplicadas en menos de 200ms 6879 if (now - lastCloseCallMs < 200) { 6880 console.log('[pxChat] handleChatClose throttled (too soon)'); 6881 return; 6882 } 6883 6884 lastCloseCallMs = now; 6885 6886 // Cancelar cualquier open pendiente 6887 if (pendingOpenTimer) { 6888 clearTimeout(pendingOpenTimer); 6889 pendingOpenTimer = null; 6890 console.log('[pxChat] handleChatClose: cancelled pending open'); 6891 } 6892 6893 // Disparar inmediatamente (sin debounce para Chromium)
6894 console.log('[pxChat] handleChatClose: calling doChatClose immediately'); 6895 doChatClose(meta, startMs); 6896 } 6897 6898 function doChatClose(meta, startMs) { 6899 // Verificar estado del botón (prioridad máxima para Chromium) 6900 // Buscar el botón con múltiples selectores 6901 const btn = document.querySelector('.widget-launcher-button') || 6902 document.querySelector('[class*="widget-launcher"]') || 6903 document.querySelector('[class*="launcher-button"]'); 6904 const isActuallyOpen = btn && btn.classList && ( 6905 btn.classList.contains('widget-launcher-button--open') || 6906 btn.classList.toString().indexOf('--open') !== -1 6907 ); 6908 const ifr = findChatIframe(); 6909 const isIframeVisible = isElementVisible(ifr); 6910 6911 // Log detallado para debugging en Chromium 6912 console.log('[pxChat] doChatClose called:', { 6913 isActuallyOpen: isActuallyOpen, 6914 isIframeVisible: isIframeVisible, 6915 chatIsOpen: chatIsOpen, 6916 hasButton: !!btn, 6917 buttonClasses: btn ? btn.className : 'no button', 6918 startMs: startMs 6919 }); 6920 6921 // CRÃTICO: Solo proceder si el chat realmente está cerrado 6922 // Si hay un botón, confiar solo en el botón (no en el iframe) 6923 if (btn) { 6924 if (isActuallyOpen) { 6925 console.warn('[pxChat] doChatClose BLOCKED - button still shows as open'); 6926 return; 6927 } 6928 // Si hay botón y no está abierto, proceder (ignorar iframe) 6929 console.log('[pxChat] doChatClose: button exists and is closed, proceeding'); 6930 } else { 6931 // Solo si NO hay botón, verificar iframe 6932 if (isIframeVisible) { 6933 console.warn('[pxChat] doChatClose BLOCKED - iframe still visible (no button found)'); 6934 return; 6935 } 6936 console.log('[pxChat] doChatClose: no button found, iframe not visible, proceeding'); 6937 } 6938 6939 // Guardar timestamp ANTES de cambiar el estado (importante para Chrome) 6940 const now = Date.now(); 6941 const endMs = now; 6942 // Calcular duración antes de resetear variables 6943 const duration_sec = startMs ? Math.max(0, Math.round((endMs - startMs) / 1000)) : null; 6944 // Ahora sà cambiar el estado 6945 chatIsOpen = false; 6946 const chat_session_id = (meta && (meta.chat_session_id || meta.session_id)) || getChatSessionId(); 6947 6948 // Log para debugging 6949 console.log('[pxChat] ð FIRING chat_close event:', { 6950 startMs: startMs, 6951 endMs: endMs, 6952 duration_sec: duration_sec, 6953 chatOpenTsMs: chatOpenTsMs, 6954 lastOpenPushMs: lastOpenPushMs, 6955 calculated: endMs - startMs + 'ms', 6956 chat_session_id: chat_session_id 6957 }); 6958 pushEvent('chat_close', { chat_session_id, duration_sec }); 6959 // Resetear timestamp inmediatamente (ya calculamos la duración) 6960 chatOpenTsMs = null; 6961 lastOpenPushMs = 0; 6962 } 6963 function isElementVisible(el){ 6964 if (!el) return false; 6965 const cs = window.getComputedStyle ? window.getComputedStyle(el) : null; 6966 if (!cs || cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0') return false; 6967 const r = el.getBoundingClientRect(); 6968 return !!(r.width && r.height); 6969 } 6970 function findChatIframe(){ 6971 try { 6972 const ifrs = document.querySelectorAll('iframe'); 6973 for (let i = 0; i < ifrs.length; i++){ 6974 const n = ifrs[i]; 6975 if (isChatIframe(n)) return n; 6976 } 6977 } catch(_e){} 6978 return null; 6979 } 6980 // Detect launcher button presence (instala watcher; no toggle directo) 6981 document.addEventListener('click', function(ev){ 6982 try { 6983 // Detectar click en el botón de cerrar del header 6984 let closeBtn = null; 6985 if (ev.composedPath) { 6986 const path = ev.composedPath(); 6987 for (let i = 0; i < path.length; i++) { 6988 const n = path[i]; 6989 if (n && n.classList && n.classList.contains && n.classList.contains('widget-header-close')) { 6990 closeBtn = n; 6991 break; 6992 } 6993 } 6994 } 6995 if (!closeBtn && ev.target && ev.target.closest) { 6996 closeBtn = ev.target.closest('.widget-header-close'); 6997 } 6998 6999 // Si se hizo click en el botón de cerrar, esperar a que el DOM se actualice 7000 if (closeBtn && chatIsOpen) { 7001 console.log('[pxChat] Close button clicked, waiting for DOM update...'); 7002 // Esperar más tiempo para que el widget actualice el estado del botón 7003 setTimeout(function() { 7004 const launcherBtn = document.querySelector('.widget-launcher-button'); 7005 const isStillOpen = launcherBtn && launcherBtn.classList && launcherBtn.classList.contains('widget-launcher-button--open'); 7006 console.log('[pxChat] After close button click, launcher state:', { 7007 isStillOpen: isStillOpen, 7008 chatIsOpen: chatIsOpen 7009 }); 7010 if (!isStillOpen && chatIsOpen) { 7011 console.log('[pxChat] Close button clicked and launcher is now closed, calling handleChatClose'); 7012 handleChatClose(); 7013 } 7014 }, 500); // Esperar 500ms para que el DOM se actualice 7015 return; 7016 } 7017 7018 // Detectar click en el botón launcher 7019 let btn = null; 7020 if (ev.composedPath) { 7021 const path = ev.composedPath(); 7022 for (let i = 0; i < path.length; i++) { 7023 const n = path[i]; 7024 if (n && n.classList && n.classList.contains && n.classList.contains('widget-launcher-button')) { btn = n; break; } 7025 } 7026 } 7027 if (!btn && ev.target && ev.target.closest) { 7028 btn = ev.target.closest('.widget-launcher-button'); 7029 } 7030 if (btn) { 7031 installButtonListener(btn); 7032 // Si el botón tiene --open, está abierto; si no, está cerrado 7033 const isOpen = btn.classList.contains('widget-launcher-button--open'); 7034 if (isOpen && !chatIsOpen) { 7035 // Chat se está abriendo 7036 console.log('[pxChat] Launcher button clicked (opening), calling handleChatOpen'); 7037 setTimeout(function() { handleChatOpen(); }, 300); 7038 } else if (!isOpen && chatIsOpen) { 7039 // Chat se está cerrando 7040 console.log('[pxChat] Launcher button clicked (closing), waiting for DOM update...'); 7041 setTimeout(function() { 7042 const launcherBtn = document.querySelector('.widget-launcher-button'); 7043 const isStillOpen = launcherBtn && launcherBtn.classList && launcherBtn.classList.contains('widget-launcher-button--open'); 7044 if (!isStillOpen && chatIsOpen) { 7045 console.log('[pxChat] Launcher button clicked and confirmed closed, calling handleChatClose'); 7046 handleChatClose(); 7047 } 7048 }, 500); // Esperar 500ms para confirmar que está cerrado 7049 } 7050 } 7051 } catch(_e){ 7052 console.error('[pxChat] Error in click listener:', _e); 7053 } 7054 }, true); 7055 // Keyboard open on launcher 7056 document.addEventListener('keydown', function(ev){ 7057 try { 7058 if (ev.key !== 'Enter' && ev.key !== ' ') return; 7059 let btn = null; 7060 if (ev.composedPath) { 7061 const path = ev.composedPath(); 7062 for (let i = 0; i < path.length; i++) { 7063 const n = path[i]; 7064 if (n && n.classList && n.classList.contains && n.classList.contains('widget-launcher-button')) { btn = n; break; } 7065 } 7066 } 7067 if (!btn && ev.target && ev.target.closest) { 7068 btn = ev.target.closest('.widget-launcher-button'); 7069 } 7070 if (btn) { 7071 installButtonListener(btn); 7072 // Delay mÃnimo para dar tiempo al widget a actualizar la clase (Chromium) 7073 setTimeout(syncChatState, 200); 7074 } 7075 } catch(_e){} 7076 }, true); 7077 // Bridge postMessage events from the widget iframe 7078 window.addEventListener('message', function(ev){ 7079 const d = ev.data; 7080 try { 7081 if (!d) return; 7082 if (typeof d === 'object') { 7083 const type = d.type || d.event || d.name || d.px_chat_event; 7084 if (!type) return; 7085 const payload = d.payload || d.meta || d; 7086 switch (String(type)) { 7087 case 'chat_opened': 7088 case 'widget_opened': 7089 case 'open': 7090 return handleChatOpen(payload); 7091 case 'message_sent': 7092 case 'chat_message': 7093 case 'message': 7094 case 'message_received': 7095 case 'new_message': 7096 // Extraer message_id del payload 7097 const messageId = payload && (payload.message_id || payload.messageId || payload.id || payload.chat_id); 7098 const messageType = payload && (payload.type || payload.message_type || 'text'); 7099 const from = payload && (payload.from || payload.user_id || payload.userId); 7100 if (messageId) { 7101 detectChatMessage(messageId, messageType, from); 7102 } else { 7103 return handleChatMessage(payload); 7104 } 7105 return; 7106 case 'chat_closed': 7107 case 'widget_closed': 7108 case 'close': 7109 return handleChatClose(payload); 7110 } 7111 // También buscar en propiedades del objeto directamente 7112 if (d.message_id || d.messageId || d.id) { 7113 const messageId = d.message_id || d.messageId || d.id; 7114 const messageType = d.type || d.message_type || 'text'; 7115 const from = d.from || d.user_id || d.userId; 7116 detectChatMessage(messageId, messageType, from); 7117 } 7118 } 7119 if (typeof d === 'string' && d.indexOf('px-chat:') === 0) { 7120 const parts = d.split(':'); 7121 const type = parts[1]; 7122 let payload = null; 7123 if (parts[2]) { try { payload = JSON.parse(parts.slice(2).join(':')); } catch(_e){} } 7124 if (type === 'open') return handleChatOpen(payload); 7125 if (type === 'message') { 7126 if (payload && (payload.message_id || payload.messageId || payload.id)) { 7127 detectChatMessage(payload.message_id || payload.messageId || payload.id, payload.type || 'text', payload.from); 7128 } else { 7129 return handleChatMessage(payload); 7130 } 7131 return; 7132 } 7133 if (type === 'close') return handleChatClose(payload); 7134 } 7135 } catch(_e){} 7136 }); 7137 // Message detection: interceptar mensajes del widget 7138 let lastMessageIds = new Set(); // Track mensajes ya procesados para evitar duplicados 7139 let lastMessageTime = 0; 7140 const MESSAGE_THROTTLE_MS = 500; // Máximo 1 mensaje cada 500ms 7141 7142 function detectChatMessage(messageId, messageType, from) { 7143 if (!messageId) { 7144 console.debug('[pxChat] detectChatMessage: no messageId provided'); 7145 return; 7146 } 7147 7148 // Evitar duplicados usando messageId (verificar primero) 7149 if (messageId && lastMessageIds.has(messageId)) { 7150 console.debug('[pxChat] detectChatMessage: message already processed', messageId); 7151 return; 7152 } 7153 7154 // Throttling: evitar procesar mensajes muy rápidos 7155 const now = Date.now(); 7156 const timeSinceLast = now - lastMessageTime; 7157 if (timeSinceLast < MESSAGE_THROTTLE_MS) { 7158 console.debug('[pxChat] detectChatMessage: throttled', timeSinceLast, 'ms since last'); 7159 return; 7160 } 7161 7162 // Permitir trackear mensajes incluso si el chat no está visualmente abierto 7163 // Los mensajes pueden llegar cuando el chat está minimizado pero activo 7164 // En Chromium, el chat puede estar activo sin que chatIsOpen sea true 7165 const hasChatSession = getChatSessionId() !== null; 7166 const shouldProcess = hasChatSession || chatIsOpen; 7167 7168 if (!shouldProcess) { 7169 // Si no hay sesión y el chat no está abierto, intentar una vez más después de un delay 7170 console.debug('[pxChat] detectChatMessage: no session/open, will retry', { hasChatSession, chatIsOpen }); 7171 setTimeout(function() { 7172 const retryHasSession = getChatSessionId() !== null; 7173 const retryIsOpen = chatIsOpen; 7174 if ((retryHasSession || retryIsOpen) && messageId && !lastMessageIds.has(messageId)) { 7175 console.debug('[pxChat] detectChatMessage: retry after delay', { retryHasSession, retryIsOpen }); 7176 detectChatMessage(messageId, messageType, from); 7177 } else { 7178 console.debug('[pxChat] detectChatMessage: retry failed - conditions not met'); 7179 } 7180 }, 1500); // Aumentado a 1.5s para dar más tiempo en Chromium 7181 return; 7182 } 7183
7184 // Limpiar Set si tiene más de 100 mensajes (evitar memory leak) 7185 if (lastMessageIds.size > 100) { 7186 lastMessageIds.clear(); 7187 } 7188 7189 if (messageId) { 7190 lastMessageIds.add(messageId); 7191 } 7192 lastMessageTime = now; 7193 7194 // Disparar evento 7195 try { 7196 const payload = { 7197 chat_id: messageId, 7198 message_type: messageType || 'text', 7199 from: from 7200 }; 7201 console.debug('[pxChat] detectChatMessage: processing message', payload); 7202 handleChatMessage(payload); 7203 } catch(e) { 7204 console.error('[pxChat] â Error processing message:', e); 7205 } 7206 } 7207 7208 // Listener para eventos personalizados que el widget podrÃa disparar 7209 document.addEventListener('px-chat-message', function(ev) { 7210 try { 7211 const data = ev.detail || ev.data || {}; 7212 detectChatMessage(data.message_id || data.messageId || data.id, data.type || data.message_type, data.from); 7213 } catch(_e){} 7214 }); 7215 7216 // Interceptar logs de console.log para detectar mensajes de Pusher 7217 // El widget loguea mensajes con formato especÃfico que podemos interceptar 7218 try { 7219 const originalConsoleLog = console.log; 7220 let isProcessing = false; // Flag para evitar recursión 7221 let processedMessageIds = new Set(); // Track mensajes ya procesados por el interceptor 7222 7223 console.log = function(...args) { 7224 // Llamar al console.log original primero (siempre) 7225 originalConsoleLog.apply(console, args); 7226 7227 // Evitar procesamiento recursivo 7228 if (isProcessing) return; 7229 7230 try { 7231 isProcessing = true; 7232 7233 let detectedMessageId = null; 7234 let detectedMessageType = 'text'; 7235 let detectedFrom = null; 7236 7237 // Buscar message_id en los argumentos directamente (mejorado para Chromium) 7238 for (let i = 0; i < args.length; i++) { 7239 const arg = args[i]; 7240 if (typeof arg === 'object' && arg !== null && !Array.isArray(arg)) { 7241 // Buscar directamente en el objeto 7242 if (arg.message_id || arg.messageId || arg.id) { 7243 detectedMessageId = arg.message_id || arg.messageId || arg.id; 7244 detectedMessageType = arg.type || arg.message_type || 'text'; 7245 detectedFrom = arg.from || arg.user_id || arg.userId || null; 7246 break; 7247 } 7248 // Buscar en rawData (estructura anidada común en Pusher) 7249 if (arg.rawData && typeof arg.rawData === 'object') { 7250 if (arg.rawData.message_id || arg.rawData.messageId || arg.rawData.id) { 7251 detectedMessageId = arg.rawData.message_id || arg.rawData.messageId || arg.rawData.id; 7252 detectedMessageType = arg.rawData.type || arg.rawData.message_type || 'text'; 7253 detectedFrom = arg.rawData.from || arg.rawData.user_id || arg.rawData.userId || null; 7254 break; 7255 } 7256 } 7257 // Buscar en propiedades anidadas (para Chromium que puede tener estructura diferente) 7258 try { 7259 for (let key in arg) { 7260 if (arg.hasOwnProperty(key) && typeof arg[key] === 'object' && arg[key] !== null) { 7261 if (arg[key].message_id || arg[key].messageId || arg[key].id) { 7262 detectedMessageId = arg[key].message_id || arg[key].messageId || arg[key].id; 7263 detectedMessageType = arg[key].type || arg[key].message_type || 'text'; 7264 detectedFrom = arg[key].from || arg[key].user_id || arg[key].userId || null; 7265 break; 7266 } 7267 } 7268 } 7269 if (detectedMessageId) break; 7270 } catch(_e) {} 7271 } 7272 } 7273 7274 // Si no encontramos en objetos, buscar en strings (solo si contiene patrones de Pusher) 7275 if (!detectedMessageId) { 7276 const logStr = args.map(arg => { 7277 if (typeof arg === 'string') return arg; 7278 if (typeof arg === 'object' && arg !== null) { 7279 try { return JSON.stringify(arg); } catch(_e) { return String(arg); } 7280 } 7281 return String(arg); 7282 }).join(' '); 7283 7284 // Solo procesar si contiene patrones especÃficos de Pusher 7285 if ((logStr.indexOf('[Pusher] ð¨ MENSAJE RECIBIDO') !== -1 || 7286 logStr.indexOf('[Pusher] ð¨ Mensaje recibido') !== -1 || 7287 logStr.indexOf('[Pusher] Body completo:') !== -1 || 7288 logStr.indexOf('[Pusher]') !== -1) && 7289 (logStr.indexOf('message_id') !== -1 || logStr.indexOf('messageId') !== -1)) { 7290 7291 // Intentar extraer message_id del string (múltiples formatos) 7292 try { 7293 // Formato: "message_id": "xxx" 7294 let messageIdMatch = logStr.match(/["']message_id["']\s*:\s
7294*["']([^"']+)["']/); 7295 if (!messageIdMatch) { 7296 // Formato: messageId: "xxx" 7297 messageIdMatch = logStr.match(/["']messageId["']\s*:\s*["']([^"']+)["']/); 7298 } 7299 if (!messageIdMatch) { 7300 // Formato: message_id: xxx (sin comillas) 7301 messageIdMatch = logStr.match(/message_id["']?\s*:\s*["']?([a-zA-Z0-9\-_]+)/); 7302 } 7303 if (messageIdMatch && messageIdMatch[1]) { 7304 detectedMessageId = messageIdMatch[1]; 7305 console.debug('[pxChat] Detected message_id from log string:', detectedMessageId); 7306 } 7307 } catch(_e) {} 7308 } 7309 } 7310 7311 // Procesar solo si encontramos un messageId y no lo hemos procesado antes 7312 if (detectedMessageId && !processedMessageIds.has(detectedMessageId)) { 7313 processedMessageIds.add(detectedMessageId); 7314 // Limpiar Set si tiene más de 50 mensajes 7315 if (processedMessageIds.size > 50) { 7316 processedMessageIds.clear(); 7317 } 7318 7319 console.debug('[pxChat] Detected message from Pusher log:', { 7320 messageId: detectedMessageId, 7321 messageType: detectedMessageType, 7322 from: detectedFrom 7323 }); 7324 7325 setTimeout(function() { 7326 detectChatMessage(detectedMessageId, detectedMessageType, detectedFrom); 7327 }, 300); // Aumentado a 300ms para dar tiempo a que se establezca la sesión 7328 } 7329 } catch(e) { 7330 // Silenciar errores en el interceptor para no romper otros logs 7331 console.debug('[pxChat] Error in console.log interceptor:', e); 7332 } finally { 7333 isProcessing = false; 7334 } 7335 }; 7336 7337 originalConsoleLog('[pxChat] Console.log interceptor installed for Pusher message detection'); 7338 } catch(e) { 7339 console.error('[pxChat] Error setting up console.log interceptor:', e); 7340 } 7341 7342 // MutationObserver para detectar mensajes en el DOM del chat (dentro del iframe) 7343 // Nota: Esto solo funciona si tenemos acceso al contenido del iframe (mismo origen) 7344 try { 7345 const chatMessageObserver = new MutationObserver(function(mutations) { 7346 if (!chatIsOpen) return; 7347 7348 for (let i = 0; i < mutations.length; i++) { 7349 const mutation = mutations[i]; 7350 if (mutation.addedNodes && mutation.addedNodes.length > 0) { 7351 for (let j = 0; j < mutation.addedNodes.length; j++) { 7352 const node = mutation.addedNodes[j]; 7353 if (node.nodeType === 1) { // Element node 7354 // Buscar elementos que parezcan mensajes de chat 7355 // Selectores comunes: .message, .chat-message, [data-message-id], etc. 7356 const messageEl = node.classList && ( 7357 node.classList.contains('message') || 7358 node.classList.contains('chat-message') || 7359 node.classList.contains('msg') || 7360 node.getAttribute('data-message-id') 7361 ) ? node : (node.querySelector && ( 7362 node.querySelector('.message') || 7363 node.querySelector('.chat-message') || 7364 node.querySelector('[data-message-id]') 7365 )); 7366 7367 if (messageEl) { 7368 const messageId = messageEl.getAttribute('data-message-id') || 7369 messageEl.getAttribute('data-id') || 7370 messageEl.id || 7371 null; 7372 const messageType = messageEl.getAttribute('data-type') || 7373 messageEl.getAttribute('data-message-type') || 7374 'text'; 7375 const from = messageEl.getAttribute('data-from') || null; 7376 7377 if (messageId) { 7378 detectChatMessage(messageId, messageType, from); 7379 } 7380 } 7381 } 7382 } 7383 } 7384 } 7385 }); 7386 7387 // Observar el iframe del chat cuando esté disponible 7388 function observeChatIframe() { 7389 const ifr = findChatIframe(); 7390 if (ifr && ifr.contentDocument && ifr.contentDocument.body) { 7391 try { 7392 chatMessageObserver.observe(ifr.contentDocument.body, { 7393 childList: true, 7394 subtree: true 7395 }); 7396 console.debug('[pxChat] Message observer installed on chat iframe'); 7397 } catch(e) { 7398 // Cross-origin: no podemos acceder al contenido del iframe 7399 console.debug('[pxChat] Cannot observe iframe content (cross-origin)'); 7400 } 7401 } 7402 } 7403 7404 // Intentar observar cuando el iframe se carga 7405 const ifr = findChatIframe(); 7406 if (ifr) { 7407 if (ifr.contentDocument && ifr.contentDocument.body) { 7408 observeChatIframe(); 7409 } else { 7410 ifr.addEventListener('load', observeChatIframe); 7411 } 7412 } 7413 7414 // También intentar cuando se detecta un nuevo iframe
7415 const iframeObserver = new MutationObserver(function() { 7416 const ifr = findChatIframe(); 7417 if (ifr && !ifr.__px_chat_message_observed) { 7418 ifr.__px_chat_message_observed = true; 7419 if (ifr.contentDocument && ifr.contentDocument.body) { 7420 observeChatIframe(); 7421 } else { 7422 ifr.addEventListener('load', observeChatIframe); 7423 } 7424 } 7425 }); 7426 iframeObserver.observe(document.body, { childList: true, subtree: true }); 7427 } catch(e) { 7428 console.error('[pxChat] Error setting up message observer:', e); 7429 } 7430 7431 // Expose helpers for manual triggers if needed 7432 window.pxChatOpen = function(meta){ handleChatOpen(meta || {}); }; 7433 window.pxChatMessage = function(meta){ handleChatMessage(meta || {}); }; 7434 window.pxChatClose = function(meta){ handleChatClose(meta || {}); }; 7435 // Expose message detection function for external use 7436 window.pxChatDetectMessage = function(messageId, messageType, from) { 7437 detectChatMessage(messageId, messageType, from); 7438 }; 7439 // Robust DOM observer: button presence and iframe lifecycle 7440 const observedIframes = new Set(); 7441 function isChatIframe(node){ 7442 if (!node || node.nodeName !== 'IFRAME') return false; 7443 try { 7444 const src = node.getAttribute('src') || ''; 7445 return /pxsol|chat|widget/i.test(src); 7446 } catch(_e){ return false; } 7447 } 7448 function installButtonListener(btn){ 7449 if (!btn || btn.__px_chat_hooked) return; 7450 btn.__px_chat_hooked = true; 7451 try { 7452 btn.__px_open_state = !!(btn.classList && btn.classList.contains('widget-launcher-button--open')); 7453 // NO sincronizar estado inicial aquà - solo observar cambios futuros 7454 let buttonChangeTimer = null; 7455 const ob = new MutationObserver(function(muts){ 7456 for (let i = 0; i < muts.length; i++){ 7457 const m = muts[i]; 7458 if (m.type === 'attributes' && m.attributeName === 'class') { 7459 const isOpen = btn.classList.contains('widget-launcher-button--open'); 7460 // Solo disparar si realmente cambió el estado 7461 if (isOpen !== btn.__px_open_state) { 7462 const now = Date.now(); 7463 if (now - lastStateChangeMs < 300) { 7464 console.debug('[pxChat] MutationObserver: change throttled'); 7465 return; // Ignorar cambios muy rápidos 7466 } 7467 7468 // Procesar inmediatamente (sin debounce para Chromium) 7469 if (buttonChangeTimer) { 7470 clearTimeout(buttonChangeTimer); 7471 } 7472 // Delay mÃnimo solo para asegurar que el DOM se actualizó 7473 buttonChangeTimer = setTimeout(function() { 7474 processButtonStateChange(btn, now); 7475 buttonChangeTimer = null; 7476 }, 50); // Delay mÃnimo de 50ms para Chromium 7477 } 7478 } 7479 } 7480 }); 7481 ob.observe(btn, { attributes: true, attributeFilter: ['class'] }); 7482 btn.__px_chat_observer = ob; 7483 } catch(_e){} 7484 } 7485 7486 function processButtonStateChange(btn, timestamp) { 7487 // Verificar que el estado realmente cambió 7488 const currentIsOpen = btn.classList.contains('widget-launcher-button--open') || 7489 btn.classList.toString().indexOf('--open') !== -1; 7490 console.log('[pxChat] processButtonStateChange:', { 7491 currentIsOpen: currentIsOpen, 7492 previousState: btn.__px_open_state, 7493 chatIsOpen: chatIsOpen 7494 }); 7495 7496 if (currentIsOpen === btn.__px_open_state) { 7497 console.log('[pxChat] MutationObserver: state unchanged, skipping'); 7498 return; 7499 } 7500 7501 btn.__px_open_state = currentIsOpen; 7502 lastStateChangeMs = timestamp || Date.now(); 7503 7504 if (currentIsOpen) { 7505 console.log('[pxChat] MutationObserver: button opened, calling handleChatOpen'); 7506 handleChatOpen(); 7507 } else { 7508 // Verificar que chatIsOpen es true antes de intentar cerrar 7509 if (!chatIsOpen) { 7510 console.log('[pxChat] MutationObserver: button closed but chatIsOpen is already false, skipping'); 7511 return; 7512 } 7513 // Guard mÃnimo: no cerrar si el chat se abrió hace menos de 3 segundos 7514 const finalNow = Date.now(); 7515 const startMs = chatOpenTsMs || lastOpenPushMs || null; 7516 if (startMs && (finalNow - startMs < 3000)) { 7517 console.log('[pxChat] MutationObserver: chat_close blocked - chat opened too recently (' + Math.round((finalNow - startMs) / 1000) + 's ago, minimum 3s)'); 7518 return; 7519 } 7520 7521 // CRÃTICO: Esperar y verificar nuevamente que el botón realmente perdió la clase --open 7522 // Esto previene disparos prematuros cuando el DOM aún se está actualizando 7523 setTimeout(function() { 7524 const btnCheck = document.querySelector('.widget-launcher-button') || 7525 document.querySelector('[class*="widget-launcher"]') || 7526 document.querySelector('[class*="launcher-button"]'); 7527 const isStillOpen = btnCheck && btnCheck.classList && ( 7528 btnCheck.classList.contains('widget-launcher-button--open') || 7529 btnCheck.classList.toString().indexOf('--open') !== -1 7530 ); 7531 7532 console.log('[pxChat] MutationObserver: delayed verification after button close:', { 7533 isStillOpen: isStillOpen, 7534 chatIsOpen: chatIsOpen, 7535 hasButton: !!btnCheck 7536 }); 7537 7538 // Solo proceder si el botón realmente está cerrado 7539 // Si hay botón, confiar solo en el botón (no en el iframe) 7540 if (isStillOpen) { 7541 console.log('[pxChat] MutationObserver: chat_close CANCELLED - button still shows as open after delay'); 7542 return; 7543 } 7544 // Solo verificar iframe si NO hay botón 7545 if (!btnCheck) { 7546 const ifr = findChatIframe(); 7547 const isIframeVisible = isElementVisible(ifr); 7548 if (isIframeVisible) { 7549 console.log('[pxChat] MutationObserver: chat_close CANCELLED - iframe still visible after delay (no button found)'); 7550 return; 7551 } 7552 } 7553 if (!chatIsOpen) { 7554 console.log('[pxChat] MutationObserver: chat_close CANCELLED - chatIsOpen is already false'); 7555 return; 7556 } 7557 7558 console.log('[pxChat] MutationObserver: button confirmed closed after delay, calling handleChatClose'); 7559 handleChatClose(); 7560 }, 600); // Esperar 600ms para confirmar que el DOM se actualizó completamente 7561 } 7562 } 7563
7564 function scanExisting(){ 7565 try { 7566 const btn = document.querySelector('.widget-launcher-button'); 7567 if (btn) installButtonListener(btn); 7568 document.querySelectorAll('iframe').forEach(function(ifr){ 7569 if (isChatIframe(ifr) && !observedIframes.has(ifr)) { 7570 observedIframes.add(ifr); 7571 // Delay más largo para evitar falsos positivos 7572 setTimeout(syncChatState, 800); 7573 } 7574 }); 7575 } catch(_e){} 7576 } 7577 const mo = new MutationObserver(function(mutations){ 7578 let anyRemoval = false; 7579 for (const m of mutations) { 7580 if (m.type === 'childList') { 7581 // Added nodes 7582 m.addedNodes && m.addedNodes.forEach(function(n){ 7583 try { 7584 if (!(n instanceof Element)) return; 7585 if (n.classList && n.classList.contains('widget-launcher-button')) { 7586 installButtonListener(n); 7587 } 7588 if (isChatIframe(n) && !observedIframes.has(n)) { observedIframes.add(n); setTimeout(syncChatState, 800); } 7589 // Deep scan 7590 n.querySelectorAll && n.querySelectorAll('.widget-launcher-button,iframe').forEach(function(x){ 7591 if (x.classList && x.classList.contains('widget-launcher-button')) installButtonListener(x); 7592 if (isChatIframe(x) && !observedIframes.has(x)) { observedIframes.add(x); setTimeout(syncChatState, 800); } 7593 }); 7594 } catch(_e){} 7595 }); 7596 // Removed nodes 7597 if (m.removedNodes && m.removedNodes.length) { 7598 anyRemoval = true; 7599 } 7600 } 7601 }
7602 if (anyRemoval) { 7603 // Check if any observed iframe is gone 7604 const still = new Set(); 7605 observedIframes.forEach(function(ifr){ 7606 if (document.body && document.body.contains(ifr)) { 7607 still.add(ifr); 7608 } else { 7609 // Delay más largo cuando se remueve el iframe (chat cerrado) 7610 setTimeout(syncChatState, 500); 7611 } 7612 }); 7613 observedIframes.clear(); 7614 still.forEach(function(x){ observedIframes.add(x); }); 7615 } 7616 }); 7617 // Poller de respaldo acotado: solo durante una ventana corta post-load 7618 // para evitar loops eternos si no aparece el botón. 7619 const CHAT_FALLBACK_POLL_INTERVAL_MS = 500; 7620 const CHAT_FALLBACK_POLL_MAX_MS_AFTER_LOAD = 2000; 7621 let chatFallbackPollIntervalId = null; 7622 let chatFallbackPollStartMs = null; 7623 7624 function stopChatFallbackPoller(reason) { 7625 if (!chatFallbackPollIntervalId) return; 7626 clearInterval(chatFallbackPollIntervalId); 7627 chatFallbackPollIntervalId = null; 7628 console.log('[pxChat] Polling stopped:', reason); 7629 } 7630 7631 function runChatFallbackPollTick() { 7632 const btn = document.querySelector('.widget-launcher-button') || 7633 document.querySelector('[class*="widget-launcher"]') || 7634 document.querySelector('[class*="launcher-button"]'); 7635 // Solo ejecutar syncChatState si NO hay botón (el botón tiene su propio observer) 7636 if (!btn) { 7637 console.log('[pxChat] Polling syncChatState (no button found)'); 7638 syncChatState(); 7639 return; 7640 } 7641 7642 console.debug('[pxChat] Polling skipped - button found, using MutationObserver instead'); 7643 stopChatFallbackPoller('button found'); 7644 } 7645 7646 function startChatFallbackPoller() { 7647 if (chatFallbackPollIntervalId) return; 7648 chatFallbackPollStartMs = Date.now(); 7649 runChatFallbackPollTick(); // Tick inicial inmediato 7650 chatFallbackPollIntervalId = setInterval(function() { 7651 if (Date.now() - chatFallbackPollStartMs > CHAT_FALLBACK_POLL_MAX_MS_AFTER_LOAD) { 7652 stopChatFallbackPoller('load + ' + CHAT_FALLBACK_POLL_MAX_MS_AFTER_LOAD + 'ms timeout'); 7653 return; 7654 } 7655 runChatFallbackPollTick(); 7656 }, CHAT_FALLBACK_POLL_INTERVAL_MS); 7657 } 7658 7659 // Ejecutar solo post-load (o inmediatamente si la página ya terminó de cargar) 7660 if (document.readyState === 'complete') { 7661 startChatFallbackPoller(); 7662 } else { 7663 window.addEventListener('load', function onLoadStartChatFallbackPoller() { 7664 window.removeEventListener('load', onLoadStartChatFallbackPoller); 7665 startChatFallbackPoller(); 7666 }); 7667 } 7668 try { 7669 mo.observe(document.documentElement || document, { childList: true, subtree: true }); 7670 // Initial scan after load tick 7671 if (document.readyState === 'loading') { 7672 document.addEventListener('DOMContentLoaded', scanExisting); 7673 } else { 7674 setTimeout(scanExisting, 0); 7675 } 7676 } catch(_e){} 7677 })(); 7678</script>
vendor: 1 bytes, line 7678
7678
7679<script> 7680 // Override para evitar espejo de chat_* al dataLayer y evitar doble track 7681 (function(){ 7682 if (typeof window.gtag === 'function') { 7683 window.gtag = function(){ 7684 try { window.dataLayer.push(arguments); } catch(_e){} 7685 }; 7686 } 7687 // Redefinir pxTrack: usa gtag si existe; sino, dataLayer 7688 window.pxTrack = function(eventName, params){ 7689 params = params || {}; 7690 if (typeof window.gtag === 'function') { 7691 try { window.gtag('event', eventName, params); } catch(_e){} 7692 } else { 7693 try { window.dataLayer.push(Object.assign({ event: eventName }, params)); } catch(_e){} 7694 } 7695 }; 7696 })(); 7697</script>
7697 7698</script>
7698 </div> 7699 7700 7701 <div id="ContainerRD" class="nodisplay"> 7702 <div class="flex flex-center fullheight"> 7703 <div id="ContainerRDInner"> 7704 <div id="Loader" class="fullheight flex flex-center"> 7705 <img class="animated slideInUp" src="https://cdn.pxsol.com/css/images/logo_loginrd.png" /> 7706 </div> 7707 <div id="CloseRDContainer"><i class="fa fa-times" aria-hidden="true"></i></div> 7708 <iframe style="width: 100%; height: 100%" src="" id="IframeRD" scrolling="no"> 7709 7710 </iframe> 7711 </div> 7712 </div> 7713 </div> 7714 7715 <div id="CortinaCargando" align="center" class="Loading nodisplay"> 7716 <div class="linear-activity"> 7717 <div class="indeterminate"></div> 7718 </div> 7719 </div> 7720 7721 <div id="dialogBox" title="..." class="nodisplay"> 7722 <p><span class="ui-icon ui-icon-alert alerticon"></span>...</p> 7723 </div> 7724 7725
7725<script src='/js_3.js?pos=PremiumTowerApartHotel&device=computer&filev=1790284695&posv=1789161380_2026-04-24T21:33:04.000Z_2026-04-24T21:33:04.000Z' defer="true" async></script>
7725 7726 7727 <div id="diccionario"> 7728 </div> 7729 7730 </div>
7730<script> 7731 window.currentContent = "habitaciones"; 7732 window.currentDevice = "desktop"; 7733 console.log('CurrentState', window.currentContent, window.currentDevice); 7734</script>
7734 7735 7736
7736<script src="/neo_modules/neo_popup/js.js?v=121790284695"></script>
7736 7737<!-- End Popup code --> 7738<div class="EndError left full" style="max-width: 100vw; overflow: auto;"> 7739 </div> 7740 7741
7742<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"b6593a85c8c04e8fa331f3e41badb76a","r":1,"spa":2}' crossorigin="anonymous"></script>
7742 7743</body> 7744<div id="dialogBox" title="..." class="nodisplay"> 7745 <p><span class="ui-icon ui-icon-alert alerticon"></span>...</p> 7746</div> 7747 7748 7749 7750 7751</html> 7752 7753
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.