update 4page

This commit is contained in:
2026-07-02 18:15:06 +08:00
parent 4d30803b60
commit 296db4a164
53 changed files with 5271 additions and 60 deletions
+30
View File
@@ -0,0 +1,30 @@
/**
* Loads adl-register.section.html into a container.
*/
(function () {
var MODULE_URL = '/pages/modules/adl-register.section.html';
function loadAdlRegisterModule() {
var container = document.getElementById('adl-register-container');
if (!container) return;
fetch(MODULE_URL, { credentials: 'same-origin' })
.then(function (res) {
if (!res.ok) throw new Error('Failed to load ' + MODULE_URL);
return res.text();
})
.then(function (html) {
container.innerHTML = html;
document.dispatchEvent(new CustomEvent('aifo:adl-register-ready'));
})
.catch(function (err) {
console.error('[adl-register-module.js]', err);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', loadAdlRegisterModule);
} else {
loadAdlRegisterModule();
}
})();
+238
View File
@@ -0,0 +1,238 @@
/**
* ADL register form interactions (static port of aifo theme adl-register.js).
*
* Configure API endpoints before load:
* window.ADL_REGISTER = { ajaxUrl: '...', successUrl: '/pages/user_signup_success.html' };
*/
(function () {
var countries = [
{ name: 'Australia', flag: '🇦🇺', dial: '+61' },
{ name: 'China', flag: '🇨🇳', dial: '+86' },
{ name: 'United States', flag: '🇺🇸', dial: '+1' },
{ name: 'United Kingdom', flag: '🇬🇧', dial: '+44' },
{ name: 'Singapore', flag: '🇸🇬', dial: '+65' },
{ name: 'Malaysia', flag: '🇲🇾', dial: '+60' },
{ name: 'New Zealand', flag: '🇳🇿', dial: '+64' },
{ name: 'Japan', flag: '🇯🇵', dial: '+81' },
{ name: 'Korea', flag: '🇰🇷', dial: '+82' },
{ name: 'Hong Kong', flag: '🇭🇰', dial: '+852' },
{ name: 'Taiwan', flag: '🇹🇼', dial: '+886' },
{ name: 'Thailand', flag: '🇹🇭', dial: '+66' },
{ name: 'Vietnam', flag: '🇻🇳', dial: '+84' },
{ name: 'Philippines', flag: '🇵🇭', dial: '+63' },
{ name: 'India', flag: '🇮🇳', dial: '+91' },
{ name: 'Germany', flag: '🇩🇪', dial: '+49' }
];
function initAdlRegister() {
var form = document.getElementById('adl-register-form');
if (!form || form.dataset.adlInit === '1') return;
form.dataset.adlInit = '1';
var cfg = window.ADL_REGISTER || {};
var ajaxUrl = cfg.ajaxUrl || '';
var successUrl = cfg.successUrl || '/pages/user_signup_success.html';
var errEl = document.getElementById('adl-register-error');
function showErr(msg) {
if (!errEl) return;
errEl.textContent = msg || 'Something went wrong.';
errEl.classList.add('show');
}
function clearErr() {
if (!errEl) return;
errEl.textContent = '';
errEl.classList.remove('show');
}
form.querySelectorAll('.adl-eye-toggle').forEach(function (btn) {
btn.addEventListener('click', function () {
var target = form.querySelector(btn.getAttribute('data-target'));
if (!target) return;
var isPwd = target.type === 'password';
target.type = isPwd ? 'text' : 'password';
btn.setAttribute('aria-label', isPwd ? 'Hide password' : 'Show password');
btn.classList.toggle('is-visible', isPwd);
});
});
var menu = document.getElementById('adl-country-menu');
var list = document.getElementById('adl-country-list');
var countrySelect = document.getElementById('adl-country-select');
var countrySearch = document.getElementById('adl-country-search');
function renderCountries(items) {
if (!list) return;
list.innerHTML = '';
items.forEach(function (c) {
var item = document.createElement('div');
item.className = 'adl-country-item';
item.setAttribute('data-dial', c.dial);
item.setAttribute('data-flag', c.flag);
item.innerHTML = '<span>' + c.flag + '</span><span>' + c.name + ' (' + c.dial + ')</span>';
list.appendChild(item);
});
}
renderCountries(countries);
if (countrySelect && menu) {
countrySelect.addEventListener('click', function () {
var open = menu.classList.toggle('open');
countrySelect.setAttribute('aria-expanded', open ? 'true' : 'false');
});
}
if (countrySearch) {
countrySearch.addEventListener('input', function () {
var q = countrySearch.value.toLowerCase();
renderCountries(
countries.filter(function (c) {
return c.name.toLowerCase().indexOf(q) !== -1 || c.dial.indexOf(q) !== -1;
})
);
});
}
if (list) {
list.addEventListener('click', function (e) {
var item = e.target.closest('.adl-country-item');
if (!item) return;
var flagEl = document.getElementById('adl-country-flag');
var codeEl = document.getElementById('adl-country-code');
var inputEl = document.getElementById('adl-country-code-input');
if (flagEl) flagEl.textContent = item.getAttribute('data-flag');
if (codeEl) codeEl.textContent = item.getAttribute('data-dial');
if (inputEl) inputEl.value = item.getAttribute('data-dial');
if (menu) menu.classList.remove('open');
if (countrySelect) countrySelect.setAttribute('aria-expanded', 'false');
});
}
document.addEventListener('click', function (e) {
if (!e.target.closest('.adl-phone-wrapper') && menu) {
menu.classList.remove('open');
if (countrySelect) countrySelect.setAttribute('aria-expanded', 'false');
}
});
var sendCodeBtn = document.getElementById('adl-send-code');
if (sendCodeBtn) {
sendCodeBtn.addEventListener('click', function () {
clearErr();
var email = document.getElementById('adl-email');
var username = document.getElementById('adl-username');
if (!email || !username || !email.value.trim() || !username.value.trim()) {
showErr('Please enter username and email first.');
return;
}
if (!ajaxUrl) {
showErr('Email code API is not configured for this static preview.');
return;
}
sendCodeBtn.disabled = true;
sendCodeBtn.textContent = 'Sending...';
var body = new URLSearchParams();
body.set('action', 'send_email_code');
body.set('email', email.value.trim());
body.set('username', username.value.trim());
fetch(ajaxUrl, { method: 'POST', body: body, credentials: 'same-origin' })
.then(function (res) { return res.json(); })
.then(function () {
var sec = 60;
sendCodeBtn.textContent = 'Resend (' + sec + 's)';
var timer = setInterval(function () {
sec -= 1;
sendCodeBtn.textContent = 'Resend (' + sec + 's)';
if (sec <= 0) {
clearInterval(timer);
sendCodeBtn.disabled = false;
sendCodeBtn.textContent = 'Get Code';
}
}, 1000);
})
.catch(function () {
showErr('Failed to send code. Please try again.');
sendCodeBtn.disabled = false;
sendCodeBtn.textContent = 'Get Code';
});
});
}
form.addEventListener('submit', function (e) {
e.preventDefault();
clearErr();
var agree = document.getElementById('adl-agree-privacy');
if (!agree || !agree.checked) {
showErr('Please agree to the terms to continue.');
return;
}
var submitBtn = document.getElementById('adl-register-submit');
if (!submitBtn || submitBtn.disabled) return;
var password = document.getElementById('adl-password');
var passRe = /^(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*(),.?":{}|<>]).{12,}$/;
if (!password || !passRe.test(password.value)) {
showErr('Password must be at least 12 characters long and include at least one uppercase letter, one number, and one special character.');
return;
}
if (!ajaxUrl) {
showErr('Registration API is not configured for this static preview.');
return;
}
submitBtn.disabled = true;
submitBtn.textContent = 'Submitting...';
var countryCode = document.getElementById('adl-country-code-input');
var phone = document.getElementById('adl-phone');
var phoneFull = ((countryCode && countryCode.value) || '') + ' ' + ((phone && phone.value.trim()) || '');
var body = new URLSearchParams();
body.set('action', 'aifo_register');
body.set('username', document.getElementById('adl-username').value.trim());
body.set('email', document.getElementById('adl-email').value.trim());
body.set('password', password.value);
body.set('confirm', document.getElementById('adl-confirm-password').value);
body.set('input_code', document.getElementById('adl-email-code').value.trim());
body.set('phone', phoneFull.trim());
body.set('agree_privacy', '1');
body.set(
'agree_subscribe',
document.getElementById('adl-agree-subscribe').checked ? '1' : '0'
);
fetch(ajaxUrl, { method: 'POST', body: body, credentials: 'same-origin' })
.then(function (res) { return res.json(); })
.then(function (res) {
if (res && res.success) {
var emailVal = document.getElementById('adl-email').value.trim();
window.location.href = successUrl + '?email=' + encodeURIComponent(emailVal);
return;
}
showErr(res && res.data && res.data.message ? res.data.message : 'Registration failed.');
submitBtn.disabled = false;
submitBtn.textContent = 'Sign up';
})
.catch(function () {
showErr('Registration request failed. Please try again.');
submitBtn.disabled = false;
submitBtn.textContent = 'Sign up';
});
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initAdlRegister);
} else {
initAdlRegister();
}
document.addEventListener('aifo:adl-register-ready', initAdlRegister);
})();
+62
View File
@@ -0,0 +1,62 @@
/**
* Loads challenge-floor.section.html into #challenge-floor-module, then boots render scripts.
*/
(function () {
var MODULE_URL = '/pages/modules/challenge-floor.section.html';
var PROGRAM_DATA_URL = '/assets/js/challenge-floor-program-data.js';
var RENDER_URL = '/assets/js/challenge-floor-render.js';
function loadScript(src) {
return new Promise(function (resolve, reject) {
if (document.querySelector('script[src="' + src + '"]')) {
resolve();
return;
}
var script = document.createElement('script');
script.src = src;
script.onload = resolve;
script.onerror = function () {
reject(new Error('Failed to load ' + src));
};
document.body.appendChild(script);
});
}
function bootChallengeFloor() {
window.CHALLENGE_FLOOR_BOOT = window.CHALLENGE_FLOOR_BOOT || {};
if (!window.CHALLENGE_FLOOR_BOOT.assetBase) {
window.CHALLENGE_FLOOR_BOOT.assetBase = '../assets/images/challenge/';
}
return loadScript(PROGRAM_DATA_URL).then(function () {
return loadScript(RENDER_URL);
});
}
function loadChallengeFloorModule() {
var container = document.getElementById('challenge-floor-module');
if (!container) return;
fetch(MODULE_URL, { credentials: 'same-origin' })
.then(function (res) {
if (!res.ok) throw new Error('Failed to load ' + MODULE_URL);
return res.text();
})
.then(function (html) {
container.innerHTML = html;
return bootChallengeFloor();
})
.then(function () {
document.dispatchEvent(new CustomEvent('aifo:challenge-floor-ready'));
})
.catch(function (err) {
console.error('[challenge-floor-module.js]', err);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', loadChallengeFloorModule);
} else {
loadChallengeFloorModule();
}
})();
+46
View File
@@ -0,0 +1,46 @@
/**
* Loads home-hero-carousel.section.html into #home-hero-carousel-module
*/
(function () {
var MODULE_URL = '/pages/modules/home-hero-carousel.section.html';
function loadHomeHeroCarouselModule() {
var container = document.getElementById('home-hero-carousel-module');
if (!container) return;
fetch(MODULE_URL, { credentials: 'same-origin' })
.then(function (res) {
if (!res.ok) throw new Error('Failed to load ' + MODULE_URL);
return res.text();
})
.then(function (html) {
container.innerHTML = html;
var ensureScript = function () {
if (window.AifoHomeHeroCarouselInit) {
var root = container.querySelector('[data-home-hero-carousel]');
if (root) window.AifoHomeHeroCarouselInit(root);
return;
}
var script = document.createElement('script');
script.src = '/js/home-hero-carousel.js';
script.onload = function () {
var root = container.querySelector('[data-home-hero-carousel]');
if (root && window.AifoHomeHeroCarouselInit) {
window.AifoHomeHeroCarouselInit(root);
}
};
document.body.appendChild(script);
};
ensureScript();
})
.catch(function (err) {
console.error('[home-hero-carousel-module.js]', err);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', loadHomeHeroCarouselModule);
} else {
loadHomeHeroCarouselModule();
}
})();
+153
View File
@@ -0,0 +1,153 @@
/**
* Home hero carousel — autoplay + dot navigation + mobile swipe
*/
(function () {
var AUTOPLAY_MS = 5000;
var SWIPE_THRESHOLD = 48;
var MOBILE_MQ = '(max-width: 991.98px)';
function initHomeHeroCarousel(root) {
if (root.getAttribute('data-carousel-ready') === 'true') return;
root.setAttribute('data-carousel-ready', 'true');
var slides = root.querySelectorAll('[data-home-hero-slide]');
var dots = root.querySelectorAll('[data-home-hero-dot]');
var viewport = root.querySelector('.home-hero-carousel__viewport');
if (!slides.length) return;
var index = 0;
var timer = null;
var touchStartX = 0;
var touchStartY = 0;
var touchTracking = false;
function setSlide(nextIndex) {
index = (nextIndex + slides.length) % slides.length;
slides.forEach(function (slide, i) {
var active = i === index;
slide.classList.toggle('is-active', active);
slide.setAttribute('aria-hidden', active ? 'false' : 'true');
});
dots.forEach(function (dot, i) {
var active = i === index;
dot.classList.toggle('is-active', active);
dot.setAttribute('aria-selected', active ? 'true' : 'false');
});
}
function startAutoplay() {
stopAutoplay();
timer = window.setInterval(function () {
setSlide(index + 1);
}, AUTOPLAY_MS);
}
function stopAutoplay() {
if (timer) {
window.clearInterval(timer);
timer = null;
}
}
function isMobileSwipeEnabled() {
return window.matchMedia(MOBILE_MQ).matches;
}
function bindTouchSwipe() {
if (!viewport || viewport.getAttribute('data-swipe-ready') === 'true') return;
viewport.setAttribute('data-swipe-ready', 'true');
viewport.addEventListener(
'touchstart',
function (e) {
if (!isMobileSwipeEnabled() || !e.touches.length) return;
touchStartX = e.touches[0].clientX;
touchStartY = e.touches[0].clientY;
touchTracking = true;
stopAutoplay();
},
{ passive: true }
);
viewport.addEventListener(
'touchend',
function (e) {
if (!touchTracking) return;
touchTracking = false;
if (!isMobileSwipeEnabled()) {
startAutoplay();
return;
}
var touch = e.changedTouches[0];
if (!touch) {
startAutoplay();
return;
}
var dx = touch.clientX - touchStartX;
var dy = touch.clientY - touchStartY;
if (Math.abs(dx) < SWIPE_THRESHOLD || Math.abs(dx) <= Math.abs(dy)) {
startAutoplay();
return;
}
if (dx < 0) {
setSlide(index + 1);
} else {
setSlide(index - 1);
}
startAutoplay();
},
{ passive: true }
);
viewport.addEventListener(
'touchcancel',
function () {
touchTracking = false;
startAutoplay();
},
{ passive: true }
);
}
dots.forEach(function (dot) {
dot.addEventListener('click', function () {
var target = Number(dot.getAttribute('data-home-hero-dot'));
if (Number.isNaN(target)) return;
setSlide(target);
startAutoplay();
});
});
root.addEventListener('mouseenter', stopAutoplay);
root.addEventListener('mouseleave', startAutoplay);
root.addEventListener('focusin', stopAutoplay);
root.addEventListener('focusout', function (e) {
if (!root.contains(e.relatedTarget)) startAutoplay();
});
bindTouchSwipe();
setSlide(0);
startAutoplay();
}
function boot() {
document.querySelectorAll('[data-home-hero-carousel]').forEach(initHomeHeroCarousel);
}
window.AifoHomeHeroCarouselInit = initHomeHeroCarousel;
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', boot);
} else {
boot();
}
document.addEventListener('aifo:home-hero-carousel-reload', boot);
})();
+64
View File
@@ -0,0 +1,64 @@
/**
* Loads Leading V2 header/footer modules (separate from layout.js nav/footer).
*/
(function () {
var HEADER_URL = "/components/leading-v2-header.html";
var FOOTER_URL = "/components/leading-v2-footer.html";
function fetchText(url) {
return fetch(url, { credentials: "same-origin" }).then(function (res) {
if (!res.ok) throw new Error("Failed to load " + url + " (" + res.status + ")");
return res.text();
});
}
function injectHtml(containerId, html) {
var el = document.getElementById(containerId);
if (!el) return null;
el.innerHTML = html;
return el;
}
function updateCopyrightYear(root) {
var year = String(new Date().getFullYear());
root.querySelectorAll("[data-lv2-year]").forEach(function (el) {
el.textContent = year;
});
}
function initLayoutV2() {
var headerContainer = document.getElementById("header-v2-container");
var footerContainer = document.getElementById("footer-v2-container");
if (!headerContainer && !footerContainer) return;
var tasks = [];
tasks.push(headerContainer ? fetchText(HEADER_URL) : Promise.resolve(null));
tasks.push(footerContainer ? fetchText(FOOTER_URL) : Promise.resolve(null));
Promise.all(tasks)
.then(function (parts) {
var headerHtml = parts[0];
var footerHtml = parts[1];
if (headerHtml) {
injectHtml("header-v2-container", headerHtml);
}
if (footerHtml) {
var footerRoot = injectHtml("footer-v2-container", footerHtml);
if (footerRoot) updateCopyrightYear(footerRoot);
}
document.dispatchEvent(new CustomEvent("aifo:layout-v2-ready"));
})
.catch(function (err) {
console.error("[layout-v2.js]", err);
});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initLayoutV2);
} else {
initLayoutV2();
}
})();
+34
View File
@@ -0,0 +1,34 @@
/**
* Partnership page — FAQ accordion.
*/
(function () {
function initFaq(root) {
if (!root) return;
root.querySelectorAll(".faq-header").forEach(function (header) {
header.addEventListener("click", function () {
var item = header.closest(".faq-item");
if (!item) return;
var isActive = item.classList.contains("active");
root.querySelectorAll(".faq-item").forEach(function (el) {
el.classList.remove("active");
});
if (!isActive) {
item.classList.add("active");
}
});
});
}
function init() {
initFaq(document.querySelector("#partnership-page .partnership-faq"));
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();
+30
View File
@@ -0,0 +1,30 @@
/**
* Loads promo-compare.section.html into #promo-compare-module.
*/
(function () {
var MODULE_URL = '/pages/modules/promo-compare.section.html';
function loadPromoCompareModule() {
var container = document.getElementById('promo-compare-module');
if (!container) return;
fetch(MODULE_URL, { credentials: 'same-origin' })
.then(function (res) {
if (!res.ok) throw new Error('Failed to load ' + MODULE_URL);
return res.text();
})
.then(function (html) {
container.innerHTML = html;
document.dispatchEvent(new CustomEvent('aifo:promo-compare-ready'));
})
.catch(function (err) {
console.error('[promo-compare-module.js]', err);
});
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', loadPromoCompareModule);
} else {
loadPromoCompareModule();
}
})();