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