/** * CyberSim OS - Immersive Workstation Login & Network Selection Screen (Phase 2.5) * * Immersive fictional workstation lockscreen, runtime language switching, * learner first & last name validation, and dynamic workplace network selection. */ import { i18n } from './i18n.js'; import { branding } from './branding.js'; export class LoginScreen { constructor({ containerElement, onConnect }) { this.container = containerElement; this.onConnect = onConnect; this.selectedScenarioId = null; this.scenarios = []; this.unsubscribeI18n = null; } /** * Escape HTML to ensure learner input is never rendered as executable markup. */ static escapeHtml(str) { if (typeof str !== 'string') return ''; return str .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } /** * Initialize and render the login screen. */ async render() { this.scenarios = branding.getScenariosCatalog(); if (this.scenarios.length > 0 && !this.selectedScenarioId) { this.selectedScenarioId = this.scenarios[0].id; } this._drawUI(); // Listen to language changes to re-render login UI dynamically if (this.unsubscribeI18n) this.unsubscribeI18n(); this.unsubscribeI18n = i18n.onChange(() => { this._drawUI(); }); } _drawUI() { if (!this.container) return; const org = branding.getOrganization(); const enabledLocales = i18n.getEnabledLocales(); const currentLocale = i18n.getLocale(); // Preserve entered first and last name if switching language const existingFirstInput = this.container.querySelector('#login-firstname-input'); const existingFirstName = existingFirstInput ? existingFirstInput.value : ''; const existingLastInput = this.container.querySelector('#login-lastname-input'); const existingLastName = existingLastInput ? existingLastInput.value : ''; this.container.innerHTML = `
${i18n.t('login.instructions')}