1// assets/js/main.js 2 3// 1. Import Core Modules 4import Terminal from './modules/Terminal.js'; 5import PostType from './modules/PostType.js'; 6 7// 2. Import Terminal Applications 8import ContactApp from './modules/apps/ContactApp.js'; 9import AboutApp from './modules/apps/AboutApp.js'; 10import NetworkScanApp from './modules/apps/NetworkScanApp.js'; 11 12/** 13 * Utility function to pause execution for a given time. 14 * @param {number} ms - The number of milliseconds to sleep. 15 * @returns {Promise} 16 */ 17export const sleep = (ms) => new Promise(r => setTimeout(r, ms)); 18 19/** 20 * Main application entry point. 21 * Initializes the terminal, registers apps, and handles boot sequence. 22 */ 23async function initializeTerminal() { 24 // Check if the terminal container exists before proceeding. 25 if (!document.getElementById('terminal')) { 26 console.error("Terminal container not found. Initialization failed."); 27 return; 28 } 29 30 // Instantiate the main Terminal system 31 const sys = new Terminal(); 32 33 // --------------------------------------------------------- 34 // SECTION A: REGISTER APPLICATIONS 35 // --------------------------------------------------------- 36 37 const contactApp = new ContactApp(sys); 38 sys.registerApp(contactApp); 39 40 const aboutApp = new AboutApp(sys); 41 sys.registerApp(aboutApp); 42 43 const networkScanApp = new NetworkScanApp(sys); 44 sys.registerApp(networkScanApp); 45 46 47 // --------------------------------------------------------- 48 // SECTION B: REGISTER WORDPRESS POST TYPES 49 // --------------------------------------------------------- 50 if (window.terminalData && window.terminalData.post_type_configs) { 51 console.log("Terminal Data Configs:", window.terminalData.post_type_configs); 52 window.terminalData.post_type_configs.forEach(config => { 53 const renderFn = config.render_fn ? new Function('post', 'currentTranslations', config.render_fn) : null; 54 55 const postType = new PostType( 56 config.name, 57 config.slug, 58 config.cmd_config, 59 renderFn 60 ); 61 62 if (window.terminalData[config.js_object_key]) { 63 postType.setPosts(window.terminalData[config.js_object_key]); 64 } 65 66 postType.register(sys); 67 sys.registerPostType(postType); 68 }); 69 } 70 71 // --------------------------------------------------------- 72 // SECTION C: SYSTEM BOOT SEQUENCE 73 // --------------------------------------------------------- 74 75 if (window.terminalData.is_singular_post) { 76 await sys.openDeepLinkPost(window.terminalData.singular_post_id, window.terminalData.singular_post_type); 77 78 } else if (window.terminalData.is_404) { 79 await sys.display404Error(); 80 81 } else { 82 await sys.boot(true); 83 } 84 85 window.sys = sys; 86} 87 88// Wait for the DOM to be fully loaded before initializing 89document.addEventListener('DOMContentLoaded', initializeTerminal); 90 91// Global Slider Function 92window.moveSlide = function (sliderId, direction) { 93 const slider = document.getElementById(sliderId); 94 if (!slider) return; 95 96 const slides = slider.querySelectorAll('.slide'); 97 let activeIndex = -1; 98 99 slides.forEach((slide, index) => { 100 if (slide.classList.contains('active')) { 101 activeIndex = index; 102 slide.classList.remove('active'); 103 } 104 }); 105 106 let newIndex = activeIndex + direction; 107 if (newIndex >= slides.length) newIndex = 0; 108 if (newIndex < 0) newIndex = slides.length - 1; 109 110 slides[newIndex].classList.add('active'); 111 112 // Update counter 113 const counter = slider.querySelector('.slide-counter'); 114 if (counter) { 115 counter.innerText = `${newIndex + 1} / ${slides.length}`; 116 } 117}; 118 119// Auto-Slider Logic 120(function () { 121 const observer = new MutationObserver((mutations) => { 122 mutations.forEach((mutation) => { 123 if (mutation.addedNodes.length) { 124 mutation.addedNodes.forEach((node) => { 125 if (node.nodeType === 1 && node.querySelector('.portfolio-slider')) { 126 initAutoSliders(node); 127 } else if (node.classList && node.classList.contains('portfolio-slider')) { 128 initAutoSliders(node.parentElement); 129 } 130 }); 131 } 132 }); 133 }); 134
135 // Start observing the document body for added nodes 136 observer.observe(document.body, { childList: true, subtree: true }); 137 138 function initAutoSliders(container) { 139 const sliders = container.querySelectorAll('.portfolio-slider'); 140 sliders.forEach(slider => { 141 if (slider.dataset.autoInitialized) return; 142 slider.dataset.autoInitialized = "true"; 143 144 const slides = slider.querySelectorAll('.slide'); 145 if (slides.length <= 1) return; 146 147 const nextSlide = () => { 148 // Check if slider is still in DOM 149 if (!document.body.contains(slider)) return; 150 151 // Check if hovered (pause on hover) 152 if (slider.matches(':hover')) { 153 setTimeout(nextSlide, 1000); // Check again in 1s 154 return; 155 } 156 157 // Get current active slide duration 158 const activeSlide = slider.querySelector('.slide.active'); 159 let duration = 6000; // Default fallback 160 if (activeSlide && activeSlide.dataset.duration) { 161 duration = parseInt(activeSlide.dataset.duration, 10); 162 } 163 164 // Safety check: Ensure duration is at least 1 second to prevent rapid loops 165 if (isNaN(duration) || duration < 1000) { 166 duration = 6000; 167 } 168 169 setTimeout(() => { 170 window.moveSlide(slider.id, 1); 171 nextSlide(); // Recursive call 172 }, duration); 173 }; 174 175 // Start the loop 176 nextSlide(); 177 }); 178 } 179})();
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.