An error occurred while processing the template.
The following has evaluated to null or missing: ==> Charter.Amenidades.Amenidad.IconoAmenidad.getAttribute("alt") [in template "59588314592901#7090972#5069062" at line 30, column 136] ---- Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)?? ---- ---- FTL stack trace ("~" means nesting-related): - Failed at: ${Charter.Amenidades.Amenidad.IconoAm... [in template "59588314592901#7090972#5069062" at line 30, column 134] ----
1<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/css/bootstrap-datepicker.min.css" rel="stylesheet">
2<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/js/bootstrap-datepicker.min.js"></script>
3
4<#assign article_id = randomNamespace >
5
6<div class="container__charters p-4" id="form_charters_${article_id}">
7 <div class="container px-0 ">
8 <div class="row">
9 <div class="col ">
10 <h2 class="charters__title">${Titulo.getData()}</h2>
11 <span class="charters__text">${Parrafo.getData()}<span>
12 </div>
13 </div>
14
15 <form id="chartersForm" class="charters__form" onsubmit="return validarFormCharters(this)" action="" method="post">
16 <div class="contentForm__custom contentForm__custom--charters">
17
18 <p>
19 ${Charter.Descripcin.getData()}
20 </p>
21
22
23 <p class="charters_title--form mb-4">${Charter.Amenidades.TituloAmenidades.getData()}</p>
24 <div class="row d-flex justify-between align-items-center">
25
26 <#if Charter.Amenidades.Amenidad.getSiblings()?has_content>
27 <#list Charter.Amenidades.Amenidad.getSiblings() as cur_Charter_Amenidades>
28 <div class="col-12 col-md-6 col-lg-4 mb-5">
29 <img loading="lazy"
30 alt="${Charter.Amenidades.Amenidad.IconoAmenidad.getAttribute("alt")}"
31 src="${cur_Charter_Amenidades.IconoAmenidad.getData()}" />
32 <span class="pl-2">${cur_Charter_Amenidades.NombreAmenidad.getData()}</span>
33 </div>
34 </#list>
35 </#if>
36 </div>
37
38 <div>
39 <h3 class="charters__title--form text-lg font-semibold mb-4">${Charter.Fotos.TituloFotos.getData()}</h3>
40 <section class="row d-flex justify-content-start align-items-center my-3 mb-3 content__rates--images" id="sliderMobile">
41 <#if Charter.Fotos.Foto.getSiblings()?has_content>
42 <#list Charter.Fotos.Foto.getSiblings() as cur_Charter_Fotos_Foto>
43 <#if (cur_Charter_Fotos_Foto.getData())?? && cur_Charter_Fotos_Foto.getData() != "">
44
45 <div class="col-6 col-md-2 col-sm-3 mb-3 d-flex justify-content-center align-items-center item__rates--images" >
46 <a class="grid-item" href="${cur_Charter_Fotos_Foto.getData()}">
47 <figure class="gallery-image">
48 <img loading="lazy"
49 class="img-fluid thumb"
50 alt="${cur_Charter_Fotos_Foto.getAttribute("alt")}"
51 src="${cur_Charter_Fotos_Foto.getData()}" />
52 </figure>
53 </a>
54 </div>
55
56 </#if>
57 </#list>
58 </#if>
59 </section>
60 </div>
61 </div>
62
63 <div class="contentForm__custom">
64 <div class="form-row">
65 <div class="form-group col-12 col">
66 <h5 class="charters__title--form">Reservación de Charters</h5>
67 </div>
68 </div>
69 <div class="form-row justify-content-end">
70 <div class="form-group col-4 text-end">
71 <button
72 type="button"
73 class="clean__data--custom">
74 Limpiar campos
75 </button>
76 </div>
77 </div>
78 <div class="form-row">
79 <div class="form-group col-12 col-md-4">
80 <label for="nameBuyer">Nombre*</label>
81 <input
82 type="text"
83 class="form-control"
84 name="txtName"
85 id="txtName"
86 placeholder="Agregar nombre"
87 data-error="Debe digitar su nombre(s)"
88 />
89 <small class="form-text text-danger error-message" id="txtName-error-message">
90 </small>
91 </div>
92 <div class="form-group col-12 col-md-4">
93 <label for="txtLastName">Apellidos*</label>
94 <input
95 type="text"
96 class="form-control"
97 name="txtLastName"
98 id="txtLastName"
99 placeholder="Agregar apellidos"
100 data-error="Debe digitar sus apellidos"
101 />
102 <small class="form-text text-danger error-message" id="txtLastName-error-message">
103 </small>
104 </div>
105 <div class="form-group col-12 col-md-4">
106 <label for="txtEmail">Correo electrónico*</label>
107 <input
108 type="text"
109 class="form-control"
110 name="txtEmail"
111 id="txtEmail"
112 placeholder="Agregar correo electrónico"
113 data-error-empty="Debe digitar su e-mail."
114 data-error-invalid="El e-mail digitado es inválido."
115 />
116 <small class="form-text text-danger error-message" id="txtEmail-error-message">
117 </small>
118 </div>
119 </div>
120 <div class="form-row">
121 <div class="form-group col-12 col-md-4">
122 <label for="txtEmailConfirm">Confirmación de correo electrónico*</label>
123 <input
124 type="text"
125 class="form-control"
126 name="txtEmailConfirm"
127 id="txtEmailConfirm"
128 placeholder="Confirmar correo electrónico"
129 data-error-empty="Debe digitar su e-mail."
130 data-error-invalid="El e-mail digitado es inválido."
131 data-error-mismatch="Los correos no son iguales "
132 />
133 <small class="form-text text-danger error-message" id="txtEmailConfirm-error-message">
134 </small>
135 </div>
136 <div class="form-group col-12 col-md-4">
137 <label for="txtPhone">Teléfono</label>
138 <input
139 type="text"
140 class="form-control"
141 name="txtPhone"
142 id="txtPhone"
143 placeholder="Agregar teléfono"
144 data-error="Debe digitar su teléfono"
145 />
146 <small class="form-text text-danger error-message" id="txtPhone-error-message">
147 </small>
148 </div>
149 <div class="form-group col-12 col-md-4">
150 <label for="selCountry">País de Salida:</label>
151 <select
152 class="form-control"
153 name="selCountry"
154 id="selCountry"
155 data-error="Debe seleccionar el país de salida"
156 >
157 <option value="0" selected>Selecciona el país de salida</option>
158 <option value="Costa Rica">Costa Rica</option>
159 <option value="El Salvador">El Salvador</option>
160 <option value="Guatemala">Guatemala</option>
161 <option value="Honduras">Honduras</option>
162 <option value="México">México</option>
163 <option value="Nicaragua">Nicaragua</option>
164 <option value="Panamá">Panamá</option>
165
166 </select>
167
168 <small class="form-text text-danger error-message" id="txtPhone-error-message">
169 </small>
170 </div>
171 </div>
172 <div class="form-row">
173 <div class="form-group col-12 col-md-4">
174 <label for="selCountry2">País de Destino:</label>
175 <select
176 class="form-control"
177 name="selCountry2"
178 id="selCountry2"
179 data-error="Debe seleccionar el país destino"
180 >
181 <option value="0" selected>Selecciona el país destino</option>
182 <option value="Costa Rica">Costa Rica</option>
183 <option value="El Salvador">El Salvador</option>
184 <option value="Guatemala">Guatemala</option>
185 <option value="Honduras">Honduras</option>
186 <option value="México">México</option>
187 <option value="Nicaragua">Nicaragua</option>
188 <option value="Panamá">Panamá</option>
189 </select>
190
191 <small class="form-text text-danger error-message" id="txtPhone-error-message"></small>
192 </div>
193
194 <div class="form-group col-12 col-md-4">
195 <label for="txtCount">Cantidad de pasajeros:</label>
196 <select
197 class="form-control"
198 name="txtCount"
199 id="txtCount"
200 data-error="Debe elegir cantidad de pasajeros">
201 <option value="0" selected>Selecciona cantidad de pasajeros</option>
202 <option value="1">1</option>
203 <option value="2">2</option>
204 <option value="3">3</option>
205 <option value="4">4</option>
206 <option value="5">5</option>
207 <option value="6">6</option>
208 <option value="7">7</option>
209 <option value="8">8</option>
210 <option value="9">9</option>
211 <option value="10">10</option>
212 </select>
213 <small class="form-text text-danger error-message w-100" id="txtCount-error-message">
214 </small>
215 </div>
216 </div>
217 <div class="form-row">
218 <div class="form-group col-12 col-md-4">
219 <label for="txtComment">Descripción del Itinerario:</label>
220 <Textarea
221 rows="5"
222 cols="45"
223 class="form-control"
224 type="text"
225 name="txtComment"
226 id="txtComment"
227 data-error="Debe elegir la descripción del itinerario"></Textarea>
228 <small class="form-text text-danger error-message w-100" id="txtComment-error-message">
229 </small>
230 </div>
231 </div>
232
233 <div class="form-row">
234 <div class="form-group col-12 col-md-4">
235 <button
236 name="btncharters"
237 id="btncharters"
238 type="submit"
239 class="charters__button--custom">
240 Enviar información
241 </button>
242 </div>
243 </div>
244 </div>
245 </form>
246
247 <div class="row contentForm__custom" id="mensaje">
248 <div class="col-12 text-center">
249 <div style="border-radius:10px; border: 1px solid #ccc; background-color:#green, color:#fff;padding:30px 40px">
250 <h3>Gracias por tu interes</h3>
251 <p class="mt-4">En breve nos pondremos en contacto contigo, para dar seguimiento a tu solicitud.</p>
252 </div>
253 </div>
254 </div>
255 </div>
256</div>
257
258
259<!-- Modal -->
260 <div id="lightboxModal" class="lightbox">
261 <span class="close">×</span>
262 <img class="lightbox-img" src="" alt="">
263 <div class="nav">
264 <span class="prev">❮</span>
265 <span class="next">❯</span>
266 </div>
267 </div>
268
269
270
271<style>
272 .container__charters{
273 font-family: "GothamPro", sans-serif;
274 background: #eceff6;
275 & .contentForm__custom{
276 box-shadow: 0px 4px 8px 0px #0D0E0F1A;
277 background: #FAFBFD;
278 border: 1px solid #E3E7F2;
279 padding: 24px;
280 margin-top: 20px;
281 border-radius: 10px;
282 }
283
284 & .contentForm__custom--charters{
285 font-size: 14px;
286 font-weight: 400;
287 line-height: 16.8px;
288 & .charters_title--form{
289 font-weight: 700;
290 }
291 }
292
293
294
295 & .charters__title{
296 font-size: 28px;
297 font-weight: 700;
298 line-height: 26.8px;
299 }
300 & .charters__text{
301 font-size: 12px;
302 font-weight: 400;
303 line-height: 16px;
304 }
305
306 & .content__rates{
307 & .rates__title{
308 font-size: 14px;
309 font-weight: 700;
310 line-height: 16.8px;
311 }
312 & .content_table--charters{
313 overflow-x: auto;
314 max-width: 100%;
315 scrollbar-color: #007bff #f0f0f0; /* Color del manejador y del fondo */
316 scrollbar-width: thin;
317
318 &::-webkit-scrollbar {
319 width: 10px;
320 height: 10px;
321 }
322
323 &::-webkit-scrollbar-track {
324 background: #f0f0f0;
325 border-radius: 10px;
326 }
327
328 &::-webkit-scrollbar-thumb {
329 background: #007bff;
330 border-radius: 10px;
331 }
332
333 &::-webkit-scrollbar-thumb:hover {
334 background: #0056b3;
335 }
336
337 & .table__price--charters{
338 border-collapse: separate;
339 border-spacing: 0;
340 overflow: hidden;
341 box-shadow: 0px 4px 8px 0px #0D0E0F1A;
342 border: 1px solid #E3E7F2;
343 text-align: center;
344 border-radius: 8px;
345 & th{
346 background: #D5E6F7;
347 }
348 }
349 }
350 & .availability__text{
351 font-size: 10px;
352 font-weight: 400;
353 line-height: 12px;
354 }
355 }
356 & .content__rates--images{
357 & .item__rates--images img{
358 max-height: 120px;
359 }
360 }
361 & .charters__form{
362 & .guest-dropdown {
363 position: absolute;
364 z-index: 1000;
365 display: none;
366 background-color: #fff;
367 border: 1px solid rgba(0,0,0,.15);
368 border-radius: .25rem;
369 box-shadow: 0 2px 10px rgba(0,0,0,0.1);
370 margin-top: -38px; /* Ajusta este valor según sea necesario */
371 }
372 & .card {
373 box-shadow: 0 2px 8px rgba(0,0,0,0.1);
374 }
375 & .btn-outline-secondary {
376 border-color: #dee2e6;
377 }
378 & .btn-outline-secondary:hover {
379 background-color: #f8f9fa;
380 border-color: #dee2e6;
381 color: #212529;
382 }
383
384 & .error-message {
385 display: none;
386 }
387 & .charters__title--form{
388 font-size: 16px;
389 font-weight: 700;
390 line-height: 19.2px;
391 text-align: left;
392 }
393 & label{
394 font-size: 12px;
395 font-weight: 700;
396 line-height: 18px;
397 text-align: left;
398 }
399 & input[type='text'], select, textarea{
400 border: 1px solid #DDE0E8;
401 background: #FFFFFF;
402 border-radius: 4px;
403 font-size: 14px;
404 &::placeholder{
405 color: #3C4B52;
406 font-size: 10px;
407 font-weight: 400;
408 line-height: 18px;
409 }
410
411 }
412 & select{
413 color: #3C4B52;
414 font-size: 10px;
415 font-weight: 400;
416 line-height: 18px;
417 }
418 & input.form-check-input{
419 cursor: pointer;
420 background-color: #fff;
421 width: 16px;
422 height: 16px;
423 appearance: none;
424 border: 1px solid #DDE0E8;
425 border-radius: 4px;
426 transition: background-color 0.3s ease-in-out;
427 position: relative;
428 margin-left: 0px;
429 &:checked{
430 background-image: url('data:image/svg+xml;utf8,<svg width="16" height="6" viewBox="0 0 8 6" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2.69964 5.24006L0.812969 3.3534C0.619635 3.16006 0.619635 2.84007 0.812969 2.64673C1.0063 2.4534 1.3263 2.4534 1.51964 2.64673L3.05297 4.18007L6.47964 0.753398C6.67297 0.560065 6.99297 0.560065 7.1863 0.753398C7.37964 0.946732 7.37964 1.26673 7.1863 1.46006L3.4063 5.24006C3.31297 5.3334 3.1863 5.38673 3.05297 5.38673C2.91964 5.38673 2.79297 5.3334 2.69964 5.24006Z" fill="%23161212"/></svg>');
431 background-repeat: no-repeat;
432 background-size: contain;
433 background-position: center;
434 }
435 }
436 & .form-check-label{
437 font-size: 10px;
438 font-weight: 400;
439 line-height: 20px;
440 text-align: left;
441 vertical-align: text-bottom;
442 & a{
443 color: #E11F2A;
444 text-decoration: underline;
445 }
446 }
447 & .charters__button--custom, .clean__data--custom{
448 font-size: 16px;
449 font-weight: 400;
450 padding: 8px;
451 width: 100%;
452 border-radius: 4px;
453 border:none;
454 }
455
456 & .charters__button--custom{
457 color: #FFFFFF;
458 line-height: 11.48px;
459 background: #002592;
460 padding: 15px 8px;
461 }
462 & .clean__data--custom{
463 background: #FAFAFA;
464 border: 1px solid #5F2167;
465 color: #5F2167;
466 }
467 & .input-group__date{
468 border-left: 0;
469 background: #fff;
470 }
471
472 & .form-control{
473 height: 45px;
474 }
475 & input.disabled--input__custom{
476 background: #ECEFF6;
477 border: 1px solid #E3E7F2;
478 font-weight: 700;
479 }
480
481 }
482
483 }
484
485
486
487
488 /* estilos del modal */
489 .lightbox { display: none; position: fixed; z-index: 9999; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.9); align-items: center; justify-content: center; flex-direction: column; }
490 .lightbox.open { display: flex; }
491 .lightbox-img { max-width: 90%; max-height: 80%; margin-bottom: 20px; }
492 .lightbox .close { position: absolute; bottom: 20px; right: 50%; font-size: 40px; color: #000; cursor: pointer; background: #fff; border-radius: 10px; }
493 #lightboxModal .nav { display: flex; justify-content: space-between; flex-flow: row wrap; width: 90%; position: absolute; }
494 #lightboxModal .nav span { font-size: 40px; color: white; cursor: pointer; }
495 .slick-dotted.slick-slider { overflow: hidden; }
496 .slick-dots { bottom: 15px !important; }
497</style>
498<script>
499 $(document).ready(function() {
500 $("#mensaje").hide();
501
502
503 $('.clean__data--custom').click(function() {
504 document.getElementById('chartersForm').reset();
505 });
506 });
507
508 function hasValue(value)
509{
510 for (i=0; i < value.length; i++)
511 {
512 if (value.charAt(i) != " ")
513 return true
514 }
515 return false
516}
517
518function validarFormCharters(form){
519
520 const validations = [
521 () => validateInput(form.txtName),
522 () => validateInput(form.txtLastName),
523 () => validateEmail(form.txtEmail),
524 () => validateEmail(form.txtEmailConfirm) ? validateEmailConfirmation(form.txtEmailConfirm, form.txtEmail) : true,
525 () => validateInput(form.txtPhone),
526 () => validateSelect(form.selCountry),
527 () => validateSelect(form.selCountry2),
528 () => validateSelect(form.txtCount),
529 () => validateInput(form.txtComment),
530 ];
531
532
533 const results = validations.map(validation => validation());
534 var abc = results.every(result => result);
535 if(abc){
536 event.preventDefault();
537 verifica();
538 }
539 else{
540 event.preventDefault();
541 return false;
542 }
543
544 //return results.every(result => result);
545}
546
547function validateDatepicker(inputElement) {
548 const errorMessage = inputElement.nextElementSibling.nextElementSibling;
549 const emptyMessage = inputElement.getAttribute('data-error-empty');
550 const invalidMessage = inputElement.getAttribute('data-error-invalid');
551 const value = inputElement.value.trim();
552 const dateRegex = /^\d{2}-\d{2}-\d{4}$/;
553
554 if (!value) {
555 errorMessage.textContent = emptyMessage;
556 errorMessage.style.display = 'block';
557 inputElement.classList.add('is-invalid');
558 return false;
559 } else if (!dateRegex.test(value)) {
560 errorMessage.textContent = invalidMessage;
561 errorMessage.style.display = 'block';
562 inputElement.classList.add('is-invalid');
563 return false;
564 } else {
565 errorMessage.style.display = 'none';
566 inputElement.classList.remove('is-invalid');
567 return true;
568 }
569}
570
571function validateSelect(selectElement) {
572 const errorMessage = selectElement.nextElementSibling;
573 const customMessage = selectElement.getAttribute('data-error');
574
575 if (selectElement.value === '0'){
576 errorMessage.textContent = customMessage;
577 errorMessage.style.display = 'block';
578 selectElement.classList.add('is-invalid');
579 return false;
580 } else {
581 errorMessage.style.display = 'none';
582 selectElement.classList.remove('is-invalid');
583 return true;
584 }
585}
586
587function validateEmail(inputElement) {
588 const errorMessage = inputElement.nextElementSibling
589 const value = inputElement.value.trim();
590 const emptyMessage = inputElement.getAttribute('data-error-empty');
591 const invalidMessage = inputElement.getAttribute('data-error-invalid');
592 const emailRegex = /^[^@\s]+@[^@\.\s]+(\.[^@\.\s]+)+$/;
593
594 if (inputElement.value.trim() === '') {
595 errorMessage.textContent = emptyMessage;
596 errorMessage.style.display = 'block';
597 inputElement.classList.add('is-invalid');
598 return false;
599 } else if (!emailRegex.test(value)) {
600 errorMessage.textContent = invalidMessage;
601 errorMessage.style.display = 'block';
602 inputElement.classList.add('is-invalid');
603 return false;
604 } else {
605 errorMessage.style.display = 'none';
606 inputElement.classList.remove('is-invalid');
607 return true;
608 }
609}
610
611function validateEmailConfirmation(inputElement, originalEmailElement) {
612 const errorMessage = inputElement.nextElementSibling;
613 const value = inputElement.value.trim();
614 const emptyMessage = inputElement.getAttribute('data-error-empty');
615 const mismatchMessage = inputElement.getAttribute('data-error-mismatch');
616
617 if (value !== originalEmailElement.value.trim()) {
618 errorMessage.textContent = mismatchMessage; // Mensaje de no coincidencia
619 errorMessage.style.display = 'block';
620 inputElement.classList.add('is-invalid');
621 return false;
622 }else {
623 errorMessage.style.display = 'none';
624 inputElement.classList.remove('is-invalid');
625 return true;
626 }
627}
628function validateInput(inputElement) {
629 const errorMessage = inputElement.nextElementSibling;
630 const customMessage = inputElement.getAttribute('data-error');
631 if (inputElement.value.trim() === '') {
632 errorMessage.textContent = customMessage;
633 errorMessage.style.display = 'block';
634 inputElement.classList.add('is-invalid');
635 return false;
636 } else {
637 errorMessage.style.display = 'none';
638 inputElement.classList.remove('is-invalid');
639 return true;
640 }
641}
642
643function verifica(){
644$("#chartersForm").hide();
645
646var settings = {
647 "url": "https://api.hsforms.com/submissions/v3/integration/submit/8212255/a1ce1868-69e2-4fb7-aa26-0f4799644adf",
648 "method": "POST",
649 "timeout": 0,
650 "headers": {
651 "Content-Type": "application/json"
652 },
653 "data": JSON.stringify({
654 "submittedAt": new Date().getTime(),
655 "fields": [
656 {
657 "name": "email",
658 "value": $("#txtEmail").val()
659 },
660 {
661 "name": "firstname",
662 "value": $("#txtName").val()
663 },
664 {
665 "name": "lastname",
666 "value": $("#txtLastName").val()
667 },
668 {
669 "name": "pais_de_procedencia",
670 "value": $("#selCountry").val()
671 },
672 {
673 "name": "pais",
674 "value": $("#selCountry2").val()
675 },
676 {
677 "name": "no__de_telefono",
678 "value": $("#txtPhone").val()
679 },
680 {
681 "name": "nodehuespedes",
682 "value": $("#txtCount").val()
683 },
684 {
685 "name": "comentario_feedback",
686 "value": $("#txtComment").val()
687 }
688 ],
689 "context": {
690 "pageUri": "ticabus.com",
691 "pageName": "Home Ticabus"
692 },
693 "legalConsentOptions": {
694 "consent": {
695 "consentToProcess": true,
696 "text": "Acepto los terminos y condiciones"
697 }
698 }
699 }),
700 };
701
702 $.ajax(settings).done(function (response) {
703 $("#mensaje").show();
704
705 });
706
707}
708
709</script>
710
711
712<script>
713 /* slider y modal */
714$(window).on('load resize orientationchange', function() {
715
716 $('#sliderMobile').each(function(){
717 var $carousel = $(this);
718
719 if ($(window).width() > 768) {
720 if ($carousel.hasClass('slick-initialized')) {
721 $carousel.slick('unslick');
722 }
723 }
724 else{
725
726 if (!$carousel.hasClass('slick-initialized')) {
727 $carousel.slick({
728 slidesToShow: 1,
729 slidesToScroll: 1,
730 mobileFirst: true,
731 arrows: true,
732 dots: true
733 });
734 }
735 }
736 });
737});
738
739
740$(function () {
741 const $links = $('#sliderMobile a')
742 const $modal = $('#lightboxModal')
743 const $img = $('.lightbox-img')
744 const $close = $('.close')
745 const $next = $('.next')
746 const $prev = $('.prev')
747
748 let currentIndex = 0
749
750 const openModal = (index) => {
751 const href = $links.eq(index).attr('href')
752 $img.attr('src', href)
753 $modal.addClass('open')
754 currentIndex = index
755 }
756
757 $links.on('click', function (e) {
758 e.preventDefault()
759 openModal($links.index(this))
760 })
761
762$close.on('click', () => $modal.removeClass('open'))
763
764 $next.on('click', () => {
765 currentIndex = (currentIndex + 1) % $links.length
766 openModal(currentIndex)
767 })
768
769 $prev.on('click', () => {
770 currentIndex = (currentIndex - 1 + $links.length) % $links.length
771 openModal(currentIndex)
772 })
773
774 $(document).on('keydown', (e) => {
775 if (!$modal.hasClass('open')) return
776 if (e.key === 'Escape') $modal.removeClass('open')
777 if (e.key === 'ArrowRight') $next.click()
778 if (e.key === 'ArrowLeft') $prev.click()
779 })
780})
781
782</script>