(function ($) {
'use strict';
// ---------- Modal helpers: BS5 (native) or jQuery fallback ----------
function modalGet(id) {
var el = document.getElementById(id);
if (!el) return null;
if (window.bootstrap && bootstrap.Modal) return bootstrap.Modal.getOrCreateInstance(el);
if (typeof $(el).modal === 'function') {
return { show:()=>$(el).modal('show'), hide:()=>$(el).modal('hide'), toggle:()=>$(el).modal('toggle') };
}
return null;
}
function modalShow(id){ var m=modalGet(id); m&&m.show&&m.show(); }
function modalHide(id){ var m=modalGet(id); m&&m.hide&&m.hide(); }
function modalToggle(id){ var m=modalGet(id); m&&m.toggle&&m.toggle(); }
$(function () {
// Footer year (null-safe)
var $navLink = $('.mm-navbars-bottom .mm-navbar a');
if ($navLink && $navLink.length) $navLink.text('© ' + new Date().getFullYear() + ' Travel Destinations');
// Favorites count UI helper
function updateProfileFavoritesCount(n){
if (n == null) return;
var num = Number(n); if (isNaN(num)) return;
$('.profile-setting-box .favorites-count').attr('data-count', String(num)).text(num);
}
// Reviews: expand / read more
$(document).on('click', '.review', function (e) {
e.preventDefault(); e.stopPropagation();
var $review = $(this), reviewId = $review.data('review-id');
if (reviewId == null) return;
$review.find('#review-read-more-link').hide();
$review.find('#review-part2').show();
$('.reviewFeedback[data-review-id="' + reviewId + '"]').show();
});
// Reviews: thumbs up / down (class-based to reduce reflow)
$(document).on('click', 'a.addReviewFeedback', function (e) {
e.preventDefault(); e.stopPropagation();
var $this = $(this), reviewId = $this.data('review-id'), feedback = String($this.data('feedback'));
if (reviewId == null || (feedback !== '1' && feedback !== '0')) return;
var yesSel = '.addReviewFeedback[data-review-id="' + reviewId + '"][data-feedback="1"]';
var noSel = '.addReviewFeedback[data-review-id="' + reviewId + '"][data-feedback="0"]';
function setLocalState(val){
$(yesSel + ',' + noSel).removeClass('fb-on fb-off').addClass('fb-off');
if (val === '1') $(yesSel).removeClass('fb-off').addClass('fb-on');
if (val === '0') $(noSel ).removeClass('fb-off').addClass('fb-on');
}
setLocalState(feedback);
$.ajax({
type: 'GET',
url: 'https://cancunmexico.guide/functions.cfc?method=add_review_feedback',
data: { review_id: reviewId, feedback: feedback },
success: function (resp) {
var data; try { data = (typeof resp === 'object') ? resp : JSON.parse(resp); } catch { return; }
if (data.success === 1) setLocalState(String(data.feedback));
else if (data.error === 'login_required') modalToggle('sign-in');
}
});
});
// Favorites
$(document).on('click', 'a.addToFavorites', function (e) {
e.preventDefault(); e.stopPropagation();
var $this = $(this), type = $this.data('type'), id = $this.data('id');
if (!type || id == null) return;
$.ajax({
type: 'GET',
url: 'https://cancunmexico.guide/functions.cfc?method=add_to_favorites',
data: { type: type, id: id },
success: function (resp) {
var data; try { data = (typeof resp === 'object') ? resp : JSON.parse(resp); } catch { return; }
if (data.success === 1) {
$('.inFavorites[data-id="' + id + '"]').show();
$('.addToFavorites[data-id="' + id + '"]').hide().closest('.loc_open').hide();
updateProfileFavoritesCount(data.favorites_count);
} else if (data.error === 'not_logged_in') {
modalToggle('sign-in');
}
}
});
});
// Forgot Password (step 1)
$(document).on('click', '#submitResetPW', function (e) {
e.preventDefault();
var $form = $('#forgotPasswordForm'), formEl = $form[0]; if (!formEl) return;
if (!formEl.checkValidity()) { $form.addClass('was-validated'); return; }
$.ajax({
type: 'GET',
url: 'https://cancunmexico.guide/functions.cfc?method=reset_password1',
data: $form.serialize(),
success: function (resp) {
var data; try { data = (typeof resp === 'object') ? resp : JSON.parse(resp); } catch { return; }
if (data.success === 1) {
$('#access-code-group,#new-password-group,#new-confirm-password-group').show();
$('#message1').hide();
$('#submitResetPWCode').show(); $('#submitResetPW').hide();
} else if (data.error === 'blank_email') {
// basic inline feedback
var $g = $form.find('#forgot_email').closest('.form-group');
$g.addClass('has-error').append('
' + (data.message || 'Email required.') + '
');
}
}
});
$form.addClass('was-validated');
});
// Forgot Password (step 2)
$(document).on('click', '#submitResetPWCode', function (e) {
e.preventDefault();
var $form = $('#forgotPasswordForm'), formEl = $form[0]; if (!formEl) return;
if (!formEl.checkValidity()) { $form.addClass('was-validated'); return; }
$.ajax({
type: 'GET',
url: 'https://cancunmexico.guide/functions.cfc?method=reset_password2',
data: $form.serialize(),
success: function (resp) {
var data; try { data = (typeof resp === 'object') ? resp : JSON.parse(resp); } catch { return; }
$form.find('.form-group').removeClass('has-error'); $form.find('.help-block').remove();
if (data.success === 2) {
modalToggle('forgot-password'); modalToggle('sign-in');
} else {
if (data.error === 'blank_email') {
$('#forgot_email').closest('.form-group').addClass('has-error')
.append('' + data.message + '
');
}
if (data.error === 'invalid_access_code') {
$('#access-code-group').addClass('has-error')
.append('' + data.message + '
');
}
if (data.error === 'password_length') {
$('#new-password-group').addClass('has-error')
.append('' + data.message + '
');
}
if (data.error === 'blank_confirmation_password') {
$('#new-confirm-password-group').addClass('has-error')
.append('' + data.message + '
');
}
if (data.error === 'passwords_no_match') {
$('#new-password-group,#new-confirm-password-group').addClass('has-error')
.append('' + data.message + '
');
}
}
}
});
$form.addClass('was-validated');
});
// Login (AJAX)
$(document).on('click', '#submitLogin', function (e) {
e.preventDefault();
var $form = $('#signinForm'), formEl = $form[0]; if (!formEl) return;
if (!formEl.checkValidity()) { $form.addClass('was-validated'); return; }
$.ajax({
type: 'POST',
url: 'https://cancunmexico.guide/functions.cfc?method=check_login',
data: $form.serialize(),
success: function (resp) {
var data; try { data = (typeof resp === 'object') ? resp : JSON.parse(resp); } catch { return; }
if (data.success === 1) {
$('#reviewedBy,#submitReviewBtn1').show();
$('#submitReviewBtn2,#menu-sign-in').hide();
$('#userName').val(data.user_first_name + ' ' + data.user_last_name.substring(0, 1) + '.');
modalToggle('sign-in');
$('#menu-profile-setting .name').text(data.user_first_name + ' ' + data.user_last_name);
$('#menu-profile-setting .mail').text(data.user_email).show();
$('#menu-profile-setting .visitor').hide();
$('#menu-profile-setting .member').show();
$('#menu-profile-setting').show();
$('#menu-profile-setting .sign-in-section').hide();
$('#menu-profile-setting .sign-out-section').show();
$('#menu-profile-setting .profile-thumb-small img').attr('src', "https://cancunmexico.guide/img/profile_green.jpg");
} else {
$form.find('.form-group').removeClass('has-error'); $form.find('.help-block').remove();
if (data.error === 'blank_email') {
$('#login_email').closest('.form-group').addClass('has-error')
.append('' + data.message + '
');
}
if (data.error === 'blank_password' || data.error === 'invalid_login') {
$('#login_password').closest('.form-group').addClass('has-error')
.append('' + data.message + '
');
}
}
}
});
$form.addClass('was-validated');
});
// Register (AJAX)
$(document).on('click', '#submitRegisterUser', function (e) {
e.preventDefault();
var formEl = document.getElementById('signupForm'); if (!formEl) return;
if (!formEl.checkValidity()) { $(formEl).addClass('was-validated'); return; }
var data = new FormData(formEl);
$.ajax({
type: 'POST',
url: 'https://cancunmexico.guide/register.cfm',
data: data,
contentType: false,
processData: false,
success: function (resp) {
var data; try { data = (typeof resp === 'object') ? resp : JSON.parse(resp); } catch { return; }
if (data.success === 1) {
modalToggle('sign-up'); modalToggle('sign-in');
} else {
var $f = $('#signupForm');
$f.find('.form-group').removeClass('has-error'); $f.find('.help-block').remove();
if (data.error === 'blank_first_name') {
$('#signup_first_name').closest('.form-group').addClass('has-error')
.append('' + data.message + '
');
}
if (data.error === 'blank_last_name') {
$('#signup_last_name').closest('.form-group').addClass('has-error')
.append('' + data.message + '
');
}
if (data.error === 'blank_email' || data.error === 'email_exists') {
$('#signup_email').closest('.form-group').addClass('has-error')
.append('' + data.message + '
');
}
if (['password_length', 'invalid_login'].includes(data.error)) {
$('#signup_password').closest('.form-group').addClass('has-error')
.append('' + data.message + '
');
}
if (['blank_confirmation_password', 'passwords_no_match'].includes(data.error)) {
$('#signup_confirm_password').closest('.form-group').addClass('has-error')
.append('' + data.message + '
');
}
}
}
});
$(formEl).addClass('was-validated');
});
// Rating label
$(document).on('click', 'input[type=radio][name=rating]', function () {
var labels = { 5:'Excellent', 4:'Good', 3:'Average', 2:'Poor', 1:'Terrible' };
$('#ratingName').html('Overall rating: "' + (labels[this.value] || '') + '"');
});
// Image modal: open + set src
$(document).on('click', '.pop', function () {
var src = $(this).find('img').attr('popsrc') || '';
$('.imagepreview').attr('src', src);
modalShow('imagemodal');
});
// Image modal: focus-safe behavior (fixes aria-hidden warning)
(function () {
var lastOpener = null;
var imgModalEl = document.getElementById('imagemodal');
document.addEventListener('click', function (e) {
var pop = e.target.closest && e.target.closest('.pop');
if (!pop) return;
lastOpener = pop;
setTimeout(function () {
var img = document.querySelector('#imagemodal .imagepreview');
if (img) { img.setAttribute('tabindex', '-1'); try { img.blur(); } catch(e){} }
}, 0);
}, { passive: true });
// clicking the image closes the modal
var preview = document.querySelector('#imagemodal .imagepreview');
if (preview) {
preview.addEventListener('click', function () {
var inst = (window.bootstrap && bootstrap.Modal) ? bootstrap.Modal.getOrCreateInstance(imgModalEl) : null;
if (inst && inst.hide) inst.hide();
}, { passive: true });
}
imgModalEl?.addEventListener('hide.bs.modal', function () {
if (imgModalEl.contains(document.activeElement)) { try { document.activeElement.blur(); } catch(e){} }
}, { passive: true });
imgModalEl?.addEventListener('hidden.bs.modal', function () {
try { (lastOpener || document.body).focus({ preventScroll:true }); } catch(e){}
}, { passive: true });
})();
}); // DOM ready
})(jQuery);