4d30803b60
Add static site, shared layout, and Node dev server with standard .gitignore. Co-authored-by: Cursor <cursoragent@cursor.com>
928 lines
32 KiB
JavaScript
928 lines
32 KiB
JavaScript
"use strict";
|
||
|
||
(function($){
|
||
|
||
$(window).on("load", function() {
|
||
|
||
}),
|
||
|
||
$(window).on('load resize', function() {
|
||
|
||
// Background image holder - Static hero with fullscreen autosize
|
||
if ($('.spotlight').length) {
|
||
$('.spotlight').each(function() {
|
||
|
||
var $this = $(this);
|
||
var holderHeight;
|
||
|
||
if ($this.data('spotlight') == 'fullscreen') {
|
||
if ($this.data('spotlight-offset')) {
|
||
var offsetHeight = $('body').find($this.data('spotlight-offset')).height();
|
||
holderHeight = $(window).height() - offsetHeight;
|
||
}
|
||
else {
|
||
holderHeight = $(window).height();
|
||
}
|
||
|
||
|
||
if ($(window).width() > 991) {
|
||
$this.find('.spotlight-holder').css({
|
||
'height': holderHeight + 'px'
|
||
});
|
||
}
|
||
else {
|
||
$this.find('.spotlight-holder').css({
|
||
'height': 'auto'
|
||
});
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}),
|
||
|
||
$(document).ready(function() {
|
||
|
||
// Plugins init
|
||
$(".scrollbar-inner")[0] && $(".scrollbar-inner").scrollbar().scrollLock();
|
||
$('[data-stick-in-parent="true"]')[0] && $('[data-stick-in-parent="true"]').stick_in_parent();
|
||
$('.selectpicker')[0] && $('.selectpicker').selectpicker();
|
||
$('.textarea-autosize')[0] && autosize($('.textarea-autosize'));
|
||
$('[data-toggle="tooltip"]').tooltip();
|
||
$('[data-toggle="popover"]').each(function() {
|
||
var popoverClass = '';
|
||
if($(this).data('color')) {
|
||
popoverClass = 'popover-'+$(this).data('color');
|
||
}
|
||
$(this).popover({
|
||
trigger: 'focus',
|
||
template: '<div class="popover '+ popoverClass +'" role="tooltip"><div class="arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'
|
||
})
|
||
});
|
||
|
||
|
||
// Floating label
|
||
$('.form-control').on('focus blur', function(e) {
|
||
$(this).parents('.form-group').toggleClass('focused', (e.type === 'focus' || this.value.length > 0));
|
||
}).trigger('blur');
|
||
|
||
|
||
// Custom input file
|
||
$('.custom-input-file').each(function() {
|
||
var $input = $(this),
|
||
$label = $input.next('label'),
|
||
labelVal = $label.html();
|
||
|
||
$input.on('change', function(e) {
|
||
var fileName = '';
|
||
|
||
if (this.files && this.files.length > 1)
|
||
fileName = (this.getAttribute('data-multiple-caption') || '').replace('{count}', this.files.length);
|
||
else if (e.target.value)
|
||
fileName = e.target.value.split('\\').pop();
|
||
|
||
if (fileName)
|
||
$label.find('span').html(fileName);
|
||
else
|
||
$label.html(labelVal);
|
||
});
|
||
|
||
|
||
// Firefox bug fix
|
||
$input.on('focus', function() {
|
||
$input.addClass('has-focus');
|
||
})
|
||
.on('blur', function() {
|
||
$input.removeClass('has-focus');
|
||
});
|
||
});
|
||
|
||
|
||
// NoUI Slider
|
||
if ($(".input-slider-container")[0]) {
|
||
$('.input-slider-container').each(function() {
|
||
|
||
var slider = $(this).find('.input-slider');
|
||
var sliderId = slider.attr('id');
|
||
var minValue = slider.data('range-value-min');
|
||
var maxValue = slider.data('range-value-max');
|
||
|
||
var sliderValue = $(this).find('.range-slider-value');
|
||
var sliderValueId = sliderValue.attr('id');
|
||
var startValue = sliderValue.data('range-value-low');
|
||
|
||
var c = document.getElementById(sliderId),
|
||
d = document.getElementById(sliderValueId);
|
||
|
||
noUiSlider.create(c, {
|
||
start: [parseInt(startValue)],
|
||
connect: [true, false],
|
||
//step: 1000,
|
||
range: {
|
||
'min': [parseInt(minValue)],
|
||
'max': [parseInt(maxValue)]
|
||
}
|
||
});
|
||
|
||
c.noUiSlider.on('update', function(a, b) {
|
||
d.textContent = a[b];
|
||
});
|
||
})
|
||
|
||
}
|
||
|
||
if ($("#input-slider-range")[0]) {
|
||
var c = document.getElementById("input-slider-range"),
|
||
d = document.getElementById("input-slider-range-value-low"),
|
||
e = document.getElementById("input-slider-range-value-high"),
|
||
f = [d, e];
|
||
|
||
noUiSlider.create(c, {
|
||
start: [parseInt(d.getAttribute('data-range-value-low')), parseInt(e.getAttribute('data-range-value-high'))],
|
||
connect: !0,
|
||
range: {
|
||
min: parseInt(c.getAttribute('data-range-value-min')),
|
||
max: parseInt(c.getAttribute('data-range-value-max'))
|
||
}
|
||
}), c.noUiSlider.on("update", function(a, b) {
|
||
f[b].textContent = a[b]
|
||
})
|
||
}
|
||
|
||
// Scroll to anchor with animation
|
||
$('.scroll-me, .toc-entry a').on('click', function(event) {
|
||
var hash = $(this).attr('href');
|
||
var offset = $(this).data('scroll-to-offset') ? $(this).data('scroll-to-offset') : 0;
|
||
|
||
// Animate scroll to the selected section
|
||
$('html, body').stop(true, true).animate({
|
||
scrollTop: $(hash).offset().top - offset
|
||
}, 600);
|
||
|
||
event.preventDefault();
|
||
});
|
||
|
||
}),
|
||
|
||
$(document).ready(function() {
|
||
$("body").on("click", "[data-action]", function(e) {
|
||
|
||
e.preventDefault();
|
||
|
||
var $this = $(this);
|
||
var action = $this.data('action');
|
||
var target = '';
|
||
|
||
switch (action) {
|
||
case "offcanvas-open":
|
||
target = $this.data("target"), $(target).addClass("open"), $("body").append('<div class="body-backdrop" data-action="offcanvas-close" data-target=' + target + " />");
|
||
break;
|
||
case "offcanvas-close":
|
||
target = $this.data("target"), $(target).removeClass("open"), $("body").find(".body-backdrop").remove();
|
||
break;
|
||
|
||
case 'aside-open':
|
||
target = $this.data('target');
|
||
$this.data('action', 'aside-close');
|
||
$this.addClass('toggled');
|
||
$(target).addClass('toggled');
|
||
$('.content').append('<div class="body-backdrop" data-action="aside-close" data-target='+target+' />');
|
||
break;
|
||
|
||
|
||
case 'aside-close':
|
||
target = $this.data('target');
|
||
$this.data('action', 'aside-open');
|
||
$('[data-action="aside-open"], '+target).removeClass('toggled');
|
||
$('.content, .header').find('.body-backdrop').remove();
|
||
break;
|
||
}
|
||
})
|
||
});
|
||
|
||
|
||
// nav
|
||
|
||
// Check if top code bar is visible
|
||
function isTopCodeBarVisible() {
|
||
const $topCodeBar = $('.top-code-bar');
|
||
|
||
// If element doesn't exist
|
||
if (!$topCodeBar.length) {
|
||
return false;
|
||
}
|
||
|
||
// Use jQuery method to check if visible
|
||
return $topCodeBar.is(':visible') && $topCodeBar.css('visibility') !== 'hidden' && $topCodeBar.height() > 0;
|
||
}
|
||
|
||
function isMobileNavViewport() {
|
||
if (window.matchMedia("(max-width: 991.98px)").matches) {
|
||
return true;
|
||
}
|
||
if (window.matchMedia("(min-width: 992px)").matches) {
|
||
return false;
|
||
}
|
||
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i
|
||
.test(navigator.userAgent);
|
||
}
|
||
|
||
function initDesktopFixedNav() {
|
||
if (isMobileNavViewport()) return;
|
||
|
||
const $nav = $('#nav');
|
||
if (!$nav.length) return;
|
||
|
||
const threshold = 35;
|
||
const defaultTop = isTopCodeBarVisible() ? '35px' : '0';
|
||
const fixedTop = '0';
|
||
|
||
$nav.css({
|
||
'position': 'fixed',
|
||
'top': defaultTop,
|
||
'left': '0',
|
||
'width': '100%',
|
||
'z-index': '1500',
|
||
'background-color': 'rgba(0, 0, 0, 0.4)',
|
||
'box-shadow': '0 2px 10px rgba(0,0,0,0.1)',
|
||
'transition': 'none'
|
||
});
|
||
|
||
function updateNavPosition() {
|
||
const isdefaultTop = isTopCodeBarVisible();
|
||
if (!isdefaultTop) {
|
||
$nav.css('top', fixedTop);
|
||
return;
|
||
}
|
||
const scrollTop = $(window).scrollTop();
|
||
$nav.css('top', scrollTop > threshold ? fixedTop : defaultTop);
|
||
}
|
||
|
||
$(window).off('scroll.aifoNav resize.aifoNav');
|
||
$(window).on('scroll.aifoNav resize.aifoNav', updateNavPosition);
|
||
updateNavPosition();
|
||
}
|
||
|
||
$(document).ready(initDesktopFixedNav);
|
||
document.addEventListener('aifo:layout-ready', initDesktopFixedNav);
|
||
|
||
// Seaction-2
|
||
$(function() {
|
||
// Check if jQuery UI is loaded (for easing functions)
|
||
const hasJQueryUI = typeof $.easing !== 'undefined';
|
||
|
||
const $section2 = $('#section-2');
|
||
|
||
// Counter data
|
||
const counters = [
|
||
{ index: 0, start: 1000, end: 50000, suffix: '+' },
|
||
{ index: 1, start: 1, end: 20, suffix: 'M+' },
|
||
{ index: 2, start: 1000, end: 70000, suffix: '+' }
|
||
];
|
||
|
||
// Listen to elements entering viewport
|
||
const observer = new IntersectionObserver(function(entries) {
|
||
entries.forEach(function(entry) {
|
||
if (entry.isIntersecting) {
|
||
// Add fade-in class (if not already)
|
||
if (!$section2.hasClass('fade-in')) {
|
||
$section2.addClass('fade-in');
|
||
}
|
||
|
||
triggerCounters();
|
||
// Listen to animation end
|
||
// $section2.one('animationend webkitAnimationEnd oanimationend MSAnimationEnd', function() {
|
||
|
||
// });
|
||
|
||
observer.unobserve(entry.target);
|
||
}
|
||
});
|
||
}, { threshold: 0.2 });
|
||
|
||
// Check if element exists
|
||
if ($section2.length) {
|
||
observer.observe($section2[0]);
|
||
}
|
||
|
||
function triggerCounters() {
|
||
setTimeout(function() {
|
||
counters.forEach(function(counter) {
|
||
const $counter = $('#section-2 .counter').eq(counter.index);
|
||
|
||
if ($counter.length) {
|
||
animateValue(
|
||
$counter,
|
||
counter.start,
|
||
counter.end,
|
||
counter.suffix,
|
||
2000,
|
||
hasJQueryUI ? 'easeOutElastic' : 'easeOutCubic'
|
||
);
|
||
}
|
||
});
|
||
}, 600);
|
||
|
||
}
|
||
|
||
|
||
|
||
// Animation function
|
||
function animateValue($element, start, end, suffix, duration, easing) {
|
||
let startTimestamp = null;
|
||
|
||
// Easing function
|
||
function getEasing(progress) {
|
||
switch(easing) {
|
||
case 'easeOutCubic':
|
||
return 1 - Math.pow(1 - progress, 3);
|
||
case 'easeOutElastic':
|
||
const c4 = (2 * Math.PI) / 3;
|
||
return progress === 0 ? 0 :
|
||
progress === 1 ? 1 :
|
||
Math.pow(2, -10 * progress) * Math.sin((progress * 10 - 0.75) * c4) + 1;
|
||
default:
|
||
return progress;
|
||
}
|
||
}
|
||
|
||
// Format number
|
||
function formatNumber(num) {
|
||
return num.toLocaleString('en-US');
|
||
}
|
||
|
||
// Animation step
|
||
function step(timestamp) {
|
||
if (!startTimestamp) startTimestamp = timestamp;
|
||
|
||
const elapsed = timestamp - startTimestamp;
|
||
const progress = Math.min(elapsed / duration, 1);
|
||
const easedProgress = getEasing(progress);
|
||
|
||
const current = Math.floor(start + (end - start) * easedProgress);
|
||
|
||
// Update display
|
||
if (suffix === 'M+') {
|
||
$element.text('$'+current + suffix);
|
||
} else {
|
||
$element.text(formatNumber(current) + suffix);
|
||
}
|
||
|
||
if (progress < 1) {
|
||
requestAnimationFrame(step);
|
||
}
|
||
}
|
||
|
||
requestAnimationFrame(step);
|
||
}
|
||
});
|
||
|
||
|
||
/* =========================
|
||
Intersection fade-in (pixel-precise)
|
||
and lazy loaders for floor loading
|
||
========================= */
|
||
|
||
const io = new IntersectionObserver((entries, obs) => {
|
||
entries.forEach(e=>{
|
||
if(e.isIntersecting){
|
||
$(e.target).addClass('show');
|
||
obs.unobserve(e.target);
|
||
}
|
||
});
|
||
},{threshold:0.12});
|
||
|
||
$(function(){
|
||
$('.fade-in').each(function(){ io.observe(this); });
|
||
});
|
||
|
||
|
||
|
||
|
||
// ============================================
|
||
// challenge
|
||
// ============================================
|
||
|
||
const appState = {
|
||
programType: '1step',
|
||
instantMode: 'pro',
|
||
accountSize: '10k',
|
||
expandedParam: null
|
||
};
|
||
|
||
const programData = {
|
||
'1step': {
|
||
defaultSize: '10k',
|
||
availableSizes: ['10k', '25k', '50k', '100k', '200k'],
|
||
data: {
|
||
'10k': { fee: '$89', daily: '3%', max: '5%', target: '8%', split: '70%~95%', payout: '14 days', news: 'Allowed' },
|
||
'25k': { fee: '$179', daily: '3%', max: '5%', target: '8%', split: '70%~95%', payout: '14 days', news: 'Allowed' },
|
||
'50k': { fee: '$359', daily: '3%', max: '5%', target: '8%', split: '70%~95%', payout: '14 days', news: 'Allowed' },
|
||
'100k': { fee: '$579', daily: '3%', max: '5%', target: '8%', split: '70%~95%', payout: '14 days', news: 'Allowed' },
|
||
'200k': { fee: '$1,239', daily: '3%', max: '5%', target: '8%', split: '70%~95%', payout: '14 days', news: 'Allowed' }
|
||
}
|
||
},
|
||
'2step': {
|
||
defaultSize: '10k',
|
||
availableSizes: ['10k', '25k', '50k', '100k', '200k'],
|
||
data: {
|
||
'10k': { fee: '$109', daily: ' 3%', max: '8%', target: 'Phase 1 <span class="text-orange"> 5%</span><br> Phase 2 <span class="text-orange"> 8%</span>', split: '70%~95%', payout: '14 days', news: 'Allowed' },
|
||
'25k': { fee: '$219', daily: ' 3%', max: '8%', target: 'Phase 1 <span class="text-orange"> 5%</span><br> Phase 2 <span class="text-orange"> 8%</span>', split: '70%~95%', payout: '14 days', news: 'Allowed' },
|
||
'50k': { fee: '$359', daily: ' 3%', max: '8%', target: 'Phase 1 <span class="text-orange"> 5%</span><br> Phase 2 <span class="text-orange"> 8%</span>', split: '70%~95%', payout: '14 days', news: 'Allowed' },
|
||
'100k': { fee: '$589', daily: ' 3%', max: '8%', target: 'Phase 1 <span class="text-orange"> 5%</span><br> Phase 2 <span class="text-orange"> 8%</span>', split: '70%~95%', payout: '14 days', news: 'Allowed' },
|
||
'200k': { fee: '$1,249', daily: ' 3%', max: '8%', target: 'Phase 1 <span class="text-orange"> 5%</span><br> Phase 2 <span class="text-orange"> 8%</span>', split: '70%~95%', payout: '14 days', news: 'Allowed' }
|
||
}
|
||
},
|
||
'3step': {
|
||
defaultSize: '10k',
|
||
availableSizes: ['10k', '25k', '50k', '100k', '200k'],
|
||
data: {
|
||
'10k': { fee: '$69', daily: ' 3%', max: '5%', target: 'Phase 1 <span class="text-orange"> 3%</span><br>Phase 2 <span class="text-orange"> 3%</span><br>Phase 3 <span class="text-orange"> 5%</span>', split: '70%~95%', payout: '14 days', news: 'Allow' },
|
||
'25k': { fee: '$149', daily: ' 3%', max: '5%', target: 'Phase 1 <span class="text-orange"> 3%</span><br>Phase 2 <span class="text-orange"> 3%</span><br>Phase 3 <span class="text-orange"> 5%</span>', split: '70%~95%', payout: '14 days', news: 'Allow' },
|
||
'50k': { fee: '$299', daily: ' 3%', max: '5%', target: 'Phase 1 <span class="text-orange"> 3%</span><br>Phase 2 <span class="text-orange"> 3%</span><br>Phase 3 <span class="text-orange"> 5%</span>', split: '70%~95%', payout: '14 days', news: 'Allow' },
|
||
'100k': { fee: '$459', daily: ' 3%', max: '5%', target: 'Phase 1 <span class="text-orange"> 3%</span><br>Phase 2 <span class="text-orange"> 3%</span><br>Phase 3 <span class="text-orange"> 5%</span>', split: '70%~95%', payout: '14 days', news: 'Allow' },
|
||
'200k': { fee: '$909', daily: ' 3%', max: '5%', target: 'Phase 1 <span class="text-orange"> 3%</span><br>Phase 2 <span class="text-orange"> 3%</span><br>Phase 3 <span class="text-orange"> 5%</span>', split: '70%~95%', payout: '14 days', news: 'Allow' }
|
||
}
|
||
},
|
||
'instant': {
|
||
pro: {
|
||
defaultSize: '10k',
|
||
availableSizes: ['10k', '25k', '50k'],
|
||
data: {
|
||
'10k': { fee: '$1091', daily: '2%', max: '5%', target: '4%', split: '70%~95%', payout: 'payout on demand', news: 'Allow' },
|
||
'25k': { fee: '$219', daily: '2%', max: '5%', target: '4%', split: '70%~95%', payout: 'payout on demand', news: 'Allow' },
|
||
'50k': { fee: '$399', daily: '2%', max: '5%', target: '4%', split: '70%~95%', payout: 'payout on demand', news: 'Allow' },
|
||
}
|
||
},
|
||
aifo: {
|
||
defaultSize: '100k',
|
||
availableSizes: ['100k', '200k'],
|
||
data: {
|
||
'100k': { fee: '$749', daily: '2%', max: '4%', target: '4%', split: '70%~95%', payout: 'payout on demand', news: 'Allow' },
|
||
'200k': { fee: '$1,199', daily: '2%', max: '4%', target: '4%', split: '70%~95%', payout: 'payout on demand', news: 'Allow' }
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
const parameterDescriptions = {
|
||
'Challenge Fee': 'One-time fee to participate in the challenge program',
|
||
'Daily Drawdown': 'Maximum percentage loss allowed in a single trading day based on the previous day’s closing balance or equity.',
|
||
'Max Drawdown': 'The Maximum Loss Limit is the maximum allowable loss calculated based on the highest equity value your account reaches during the evaluation or trading phase.',
|
||
'Profit Target': 'The percentage gain required to successfully complete each phase of the challenge.',
|
||
'withdrawable profit': 'The Profit Target refers to the required percentage of withdrawable profit that the account must achieve before a payout can be requested.',
|
||
'Profit split': 'Percentage of profits you keep. The firm keeps the remainder.',
|
||
'Payout period': 'Minimum time required before you can request a withdrawal of profits.',
|
||
'News Trading': ''
|
||
};
|
||
|
||
// const parameterNames = ['Challenge Fee', 'Daily Drawdown', 'Max Drawdown', 'Profit Target', 'Profit split', 'Payout period', 'News Trading'];
|
||
const parameterNames = ['Challenge Fee', 'Daily Drawdown', 'Max Drawdown', 'Profit Target', 'Profit split', 'Payout period'];
|
||
const parameterNames_instant = ['Challenge Fee', 'Daily Drawdown', 'Max Drawdown', 'withdrawable profit', 'Profit split', 'Payout period'];
|
||
|
||
// ============================================
|
||
// 工具函数
|
||
// ============================================
|
||
|
||
function getIconSVG(paramName) {
|
||
const icons = {
|
||
'Challenge Fee': '<img src="./assets/images/backgrounds/svg/Component 26.svg" alt="Funded Trading" class="chall-icon">',
|
||
'Daily Drawdown': '<img src="./assets/images/backgrounds/svg/Component 27.svg" alt="Funded Trading" class="chall-icon">',
|
||
'Max Drawdown': '<img src="./assets/images/backgrounds/svg/Component 28.svg" alt="Funded Trading" class="chall-icon">',
|
||
'Profit Target': '<img src="./assets/images/backgrounds/svg/Component 29.svg" alt="Funded Trading" class="chall-icon">',
|
||
'withdrawable profit': '<img src="./assets/images/backgrounds/svg/Component 29.svg" alt="Funded Trading" class="chall-icon">',
|
||
'Profit split': '<img src="./assets/images/backgrounds/svg/Component 30.svg" alt="Funded Trading" class="chall-icon">',
|
||
'Payout period': '<img src="./assets/images/backgrounds/svg/Component 31.svg" alt="Funded Trading" class="chall-icon">',
|
||
'News Trading': '<img src="./assets/images/backgrounds/svg/Component 32.svg" alt="Funded Trading" class="chall-icon">'
|
||
};
|
||
return icons[paramName] || '';
|
||
}
|
||
|
||
function getCurrentProgramConfig() {
|
||
if (appState.programType === 'instant') {
|
||
return programData.instant[appState.instantMode];
|
||
}
|
||
return programData[appState.programType];
|
||
}
|
||
|
||
function getDataForSize(size) {
|
||
const config = getCurrentProgramConfig();
|
||
return config.data[size];
|
||
}
|
||
|
||
function formatAccountSize(size) {
|
||
const formats = {
|
||
'10k': '$10K',
|
||
'25k': '$25K',
|
||
'50k': '$50K',
|
||
'100k': '$100K',
|
||
'200k': '$200K'
|
||
};
|
||
return formats[size] || size;
|
||
}
|
||
|
||
function getParamKey(paramName) {
|
||
const keyMap = {
|
||
'Challenge Fee': 'fee',
|
||
'Daily Drawdown': 'daily',
|
||
'Max Drawdown': 'max',
|
||
'Profit Target': 'target',
|
||
'withdrawable profit':'target',
|
||
'Profit split': 'split',
|
||
'Payout period': 'payout',
|
||
'News Trading': 'news'
|
||
};
|
||
return keyMap[paramName];
|
||
}
|
||
|
||
// ============================================
|
||
// 桌面版渲染
|
||
// ============================================
|
||
|
||
function renderDesktopTable(type) {
|
||
const config = getCurrentProgramConfig();
|
||
const sizes = config.availableSizes;
|
||
|
||
let html = '';
|
||
|
||
var param = parameterNames;
|
||
if(type=="aifo" || type=="pro" || type=="instant"){
|
||
param = parameterNames_instant;
|
||
}
|
||
|
||
param.forEach(paramName => {
|
||
const paramKey = getParamKey(paramName);
|
||
const rowId = paramName.replace(/\s+/g, '-').toLowerCase();
|
||
|
||
// 参数行
|
||
html += `<tr class="param-data-row" data-param="${paramName}">`;
|
||
html += `<td>
|
||
<div class="param-name-cell">
|
||
<div class="param-icon">${getIconSVG(paramName)}</div>
|
||
<div class="param-name">${paramName}</div>
|
||
<div class="expand-btn ${appState.expandedParam === paramName ? 'expanded' : ''}">
|
||
<img src="./assets/images/backgrounds/arraw-icon.png" alt="Funded Trading" class="arraw-icon-table">
|
||
</div>
|
||
</div>
|
||
</td>`;
|
||
|
||
// 各账户大小的数值
|
||
sizes.forEach(size => {
|
||
const data = getDataForSize(size);
|
||
html += `<td>${data[paramKey]}</td>`;
|
||
});
|
||
|
||
html += `</tr>`;
|
||
|
||
// 展开说明行
|
||
html += `<tr class="challenge-row-expand ${appState.expandedParam === paramName ? 'show' : ''}" data-expand="${paramName}">`;
|
||
html += `<td colspan="6">${parameterDescriptions[paramName]}</td>`;
|
||
html += `</tr>`;
|
||
});
|
||
|
||
$('#desktopTableBody').html(html);
|
||
}
|
||
|
||
// ============================================
|
||
// 移动版渲染
|
||
// ============================================
|
||
|
||
function renderMobileAccountSizes() {
|
||
const config = getCurrentProgramConfig();
|
||
const sizes = config.availableSizes;
|
||
|
||
const buttons = sizes.map(size => {
|
||
const label = formatAccountSize(size);
|
||
const activeClass = size === appState.accountSize ? 'active' : '';
|
||
return `<button class="mobile-size-btn ${activeClass}" data-size="${size}">${label}</button>`;
|
||
}).join('');
|
||
|
||
$('#mobileAccountSizes').html(buttons);
|
||
|
||
if (!sizes.includes(appState.accountSize)) {
|
||
appState.accountSize = config.defaultSize;
|
||
}
|
||
}
|
||
|
||
function renderMobileParams(type) {
|
||
const data = getDataForSize(appState.accountSize);
|
||
|
||
let html = '';
|
||
|
||
var param = parameterNames;
|
||
if(type=="aifo" || type=="pro" || type=="instant"){
|
||
param = parameterNames_instant;
|
||
}
|
||
|
||
param.forEach(paramName => {
|
||
const paramKey = getParamKey(paramName);
|
||
|
||
html += `<div>
|
||
<div class="mobile-param-row" data-param="${paramName}">
|
||
<div class="mobile-param-left">
|
||
<div class="param-icon">${getIconSVG(paramName)}</div>
|
||
<div class="param-name">${paramName}</div>
|
||
<div class="expand-btn ${appState.expandedParam === paramName ? 'expanded' : ''}">
|
||
<img src="./assets/images/backgrounds/arraw-icon.png" alt="Funded Trading" class="arraw-icon-table">
|
||
|
||
</div>
|
||
</div>
|
||
<div class="mobile-param-value">${data[paramKey]}</div>
|
||
</div>
|
||
<div class="mobile-param-description ${appState.expandedParam === paramName ? 'show' : ''}" data-desc="${paramName}">
|
||
${parameterDescriptions[paramName]}
|
||
</div>
|
||
</div>`;
|
||
});
|
||
|
||
$('#mobileParamsList').html(html);
|
||
}
|
||
|
||
function updateMobileAmount() {
|
||
$('#mobileAmount').text(formatAccountSize(appState.accountSize));
|
||
}
|
||
|
||
// ============================================
|
||
// 状态切换
|
||
// ============================================
|
||
|
||
function changeProgramType(newType) {
|
||
appState.programType = newType;
|
||
const config = getCurrentProgramConfig();
|
||
appState.accountSize = config.defaultSize;
|
||
appState.expandedParam = null;
|
||
|
||
renderDesktopTable(newType);
|
||
renderMobileAccountSizes();
|
||
renderMobileParams(newType);
|
||
updateMobileAmount();
|
||
}
|
||
|
||
function changeInstantMode(newMode) {
|
||
appState.instantMode = newMode;
|
||
const config = getCurrentProgramConfig();
|
||
|
||
if (!config.availableSizes.includes(appState.accountSize)) {
|
||
appState.accountSize = config.defaultSize;
|
||
}
|
||
|
||
appState.expandedParam = null;
|
||
|
||
renderDesktopTable(newMode);
|
||
renderMobileAccountSizes();
|
||
renderMobileParams(newMode);
|
||
updateMobileAmount();
|
||
}
|
||
|
||
function changeMobileAccountSize(newSize) {
|
||
appState.accountSize = newSize;
|
||
appState.expandedParam = null;
|
||
|
||
updateMobileAmount();
|
||
$('#mobileParamsList').fadeOut(150, function() {
|
||
|
||
const tabs = document.querySelectorAll('.challenge-tab');
|
||
var type = "step";
|
||
tabs.forEach(tab => {
|
||
if (tab.classList.contains('active')) {
|
||
const program = tab.dataset.program;
|
||
if(program == "instant"){
|
||
type = "instant";
|
||
}
|
||
}
|
||
});
|
||
renderMobileParams(type);
|
||
|
||
|
||
$(this).fadeIn(150);
|
||
});
|
||
}
|
||
|
||
// ============================================
|
||
// 事件监听
|
||
// ============================================
|
||
|
||
$(document).on('click', '.challenge-tab', function() {
|
||
$('.challenge-tab').removeClass('active');
|
||
$(this).addClass('active');
|
||
|
||
const newProgram = $(this).data('program');
|
||
const addons = document.querySelector('.challenge-addons');
|
||
|
||
if (newProgram === 'instant') {
|
||
$('#instantSubTabs').addClass('show');
|
||
document.querySelectorAll('.ch-pro')
|
||
.forEach(el => el.classList.remove('d-none'));
|
||
|
||
document.querySelectorAll('.ch-aifo')
|
||
.forEach(el => el.classList.add('d-none'));
|
||
|
||
if (addons) {
|
||
addons.classList.add('is-hidden');
|
||
}
|
||
|
||
} else {
|
||
|
||
|
||
document.querySelectorAll('.ch-pro')
|
||
.forEach(el => el.classList.remove('d-none'));
|
||
|
||
document.querySelectorAll('.ch-aifo')
|
||
.forEach(el => el.classList.remove('d-none'));
|
||
|
||
$('#instantSubTabs').removeClass('show');
|
||
if (addons) {
|
||
addons.classList.remove('is-hidden');
|
||
}
|
||
}
|
||
|
||
changeProgramType(newProgram);
|
||
});
|
||
|
||
$(document).on('click', '.instant-tab', function() {
|
||
$('.instant-tab').removeClass('active');
|
||
$(this).addClass('active');
|
||
|
||
const newMode = $(this).data('instant-type');
|
||
|
||
if (newMode === "pro") {
|
||
document.querySelectorAll('.ch-pro')
|
||
.forEach(el => el.classList.remove('d-none'));
|
||
|
||
document.querySelectorAll('.ch-aifo')
|
||
.forEach(el => el.classList.add('d-none'));
|
||
} else {
|
||
document.querySelectorAll('.ch-pro')
|
||
.forEach(el => el.classList.add('d-none'));
|
||
|
||
document.querySelectorAll('.ch-aifo')
|
||
.forEach(el => el.classList.remove('d-none'));
|
||
}
|
||
|
||
changeInstantMode(newMode);
|
||
});
|
||
|
||
$(document).on('click', '.mobile-size-btn', function() {
|
||
$('.mobile-size-btn').removeClass('active');
|
||
$(this).addClass('active');
|
||
|
||
const newSize = $(this).data('size');
|
||
changeMobileAccountSize(newSize);
|
||
});
|
||
|
||
$(document).on('click', '.param-data-row', function() {
|
||
const paramName = $(this).data('param');
|
||
if(paramName=="News Trading"){
|
||
return;
|
||
}
|
||
|
||
if (appState.expandedParam === paramName) {
|
||
appState.expandedParam = null;
|
||
} else {
|
||
appState.expandedParam = paramName;
|
||
}
|
||
|
||
$('.challenge-row-expand').removeClass('show');
|
||
$('.param-data-row .expand-btn').removeClass('expanded');
|
||
|
||
if (appState.expandedParam) {
|
||
$(`.challenge-row-expand[data-expand="${appState.expandedParam}"]`).addClass('show');
|
||
$(this).find('.expand-btn').addClass('expanded');
|
||
}
|
||
});
|
||
|
||
$(document).on('click', '.mobile-param-row', function() {
|
||
const paramName = $(this).data('param');
|
||
|
||
if (appState.expandedParam === paramName) {
|
||
appState.expandedParam = null;
|
||
} else {
|
||
appState.expandedParam = paramName;
|
||
}
|
||
|
||
$('.mobile-param-description').removeClass('show');
|
||
$('.mobile-param-row .expand-btn').removeClass('expanded');
|
||
|
||
if (appState.expandedParam) {
|
||
$(`.mobile-param-description[data-desc="${appState.expandedParam}"]`).addClass('show');
|
||
$(this).find('.expand-btn').addClass('expanded');
|
||
}
|
||
});
|
||
|
||
$(document).on('click', '.start-challenge-btn', function() {
|
||
const size = $(this).data('size');
|
||
console.log('Start Challenge:', {
|
||
programType: appState.programType,
|
||
instantMode: appState.instantMode,
|
||
accountSize: size
|
||
});
|
||
});
|
||
|
||
$(document).on('click', '.mobile-start-btn', function() {
|
||
console.log('Start Challenge:', {
|
||
programType: appState.programType,
|
||
instantMode: appState.instantMode,
|
||
accountSize: appState.accountSize
|
||
});
|
||
});
|
||
|
||
// ============================================
|
||
// 初始化
|
||
// ============================================
|
||
|
||
$(document).ready(function() {
|
||
renderDesktopTable();
|
||
renderMobileAccountSizes();
|
||
renderMobileParams();
|
||
updateMobileAmount();
|
||
});
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
})(jQuery);
|
||
|
||
|
||
/* ===========================================================
|
||
Reusable Carousel Class
|
||
=========================================================== */
|
||
class Carousel {
|
||
constructor(opts) {
|
||
this.container = document.querySelector(opts.container);
|
||
this.track = this.container.querySelector(".carousel-track");
|
||
this.items = [...this.track.children];
|
||
this.prevBtn = document.getElementById(opts.prev);
|
||
this.nextBtn = document.getElementById(opts.next);
|
||
this.dotsContainer = document.querySelector(opts.dots);
|
||
|
||
this.index = 0;
|
||
this.pageWidth = this.items[0].offsetWidth + 40; // including margin
|
||
|
||
this.setupDots();
|
||
this.update();
|
||
this.bindEvents();
|
||
}
|
||
|
||
setupDots() {
|
||
this.dotsContainer.innerHTML = "";
|
||
this.items.forEach((_, i) => {
|
||
const dot = document.createElement("div");
|
||
dot.className = "dot";
|
||
dot.addEventListener("click", () => this.goTo(i));
|
||
this.dotsContainer.appendChild(dot);
|
||
});
|
||
}
|
||
|
||
bindEvents() {
|
||
this.prevBtn.addEventListener("click", () => this.prev());
|
||
this.nextBtn.addEventListener("click", () => this.next());
|
||
window.addEventListener("resize", () => {
|
||
this.pageWidth = this.items[0].offsetWidth + 40;
|
||
this.update();
|
||
});
|
||
}
|
||
|
||
prev() {
|
||
this.index = Math.max(0, this.index - 1);
|
||
this.update();
|
||
}
|
||
|
||
next() {
|
||
this.index = Math.min(this.items.length - 1, this.index + 1);
|
||
this.update();
|
||
}
|
||
|
||
goTo(i) {
|
||
this.index = i;
|
||
this.update();
|
||
}
|
||
|
||
update() {
|
||
const centerOffset = (window.innerWidth / 2) - (this.pageWidth / 2);
|
||
let x = this.index * this.pageWidth * -1 + centerOffset;
|
||
|
||
if (this.index === 0) x = 0;
|
||
if (this.index === this.items.length - 1) {
|
||
x = (this.items.length - 1) * this.pageWidth * -1 + (window.innerWidth - this.pageWidth);
|
||
}
|
||
|
||
this.track.style.transform = `translateX(${x}px)`;
|
||
|
||
[...this.dotsContainer.children].forEach((dot, i) => {
|
||
dot.classList.toggle("active", i === this.index);
|
||
});
|
||
}
|
||
}
|
||
|
||
function showInfoAlert(){
|
||
alert("New features are about to be launched");
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|