(function (global) { 'use strict'; var DISPLAY_NAME_KEY = 'roomLobbyDisplayName'; var PLAYER_NAME_KEY = 'playerName'; var MAX_LEN = 24; function sanitizeDisplayName(raw) { var s = String(raw == null ? '' : raw).trim(); if (!s) return ''; try { s = s.normalize('NFKC'); } catch (e) { /* ignore */ } s = s.replace(/[\x00-\x1f\x7f]/g, ''); if (s.length > MAX_LEN) s = s.slice(0, MAX_LEN); return s; } function readDisplayName() { try { return ( localStorage.getItem(DISPLAY_NAME_KEY) || localStorage.getItem(PLAYER_NAME_KEY) || 'MONE' ).trim() || 'MONE'; } catch (e) { return 'MONE'; } } function syncDisplayNameDom(displayName) { var text = String(displayName || '').trim(); if (!text) return; var upper = text.toUpperCase(); var ids = [ 'lobby-profile-name', 'room-lobby-profile-overlay-name', 'room-lobby-profile-name' ]; ids.forEach(function (id) { var el = document.getElementById(id); if (el) el.textContent = upper; }); try { document.querySelectorAll('[data-jd-display-name]').forEach(function (el) { el.textContent = upper; }); } catch (e2) { /* ignore */ } } function replaceNickQueryParam(displayName) { try { var u = new URL(global.location.href); if (!u.searchParams.has('nick')) return; u.searchParams.set('nick', displayName); global.history.replaceState({}, '', u.pathname + u.search + u.hash); } catch (e) { /* ignore */ } } /** * @param {string} nextName * @param {{ socket?: object, silent?: boolean }} [options] * @returns {{ ok: boolean, displayName?: string, error?: string }} */ function applyDisplayNameChange(nextName, options) { var safe = sanitizeDisplayName(nextName); if (!safe) return { ok: false, error: 'empty' }; var opts = options || {}; try { localStorage.setItem(DISPLAY_NAME_KEY, safe); localStorage.setItem(PLAYER_NAME_KEY, safe); } catch (e) { /* ignore */ } syncDisplayNameDom(safe); replaceNickQueryParam(safe); try { global.dispatchEvent(new CustomEvent('jd-display-name-changed', { detail: { displayName: safe } })); } catch (e2) { /* ignore */ } var sock = opts.socket || global.__jdGameSocket || null; if (sock && typeof sock.emit === 'function' && sock.connected) { sock.emit('update-display-name', { nickname: safe }, function (res) { if (res && res.ok && res.nickname) { try { localStorage.setItem(DISPLAY_NAME_KEY, res.nickname); localStorage.setItem(PLAYER_NAME_KEY, res.nickname); } catch (e3) { /* ignore */ } syncDisplayNameDom(res.nickname); } }); } return { ok: true, displayName: safe }; } var editorReady = false; function ensureNameEditorDom() { if (editorReady && document.getElementById('jd-display-name-editor-overlay')) return; if (!document.getElementById('jd-display-name-editor-style')) { var st = document.createElement('style'); st.id = 'jd-display-name-editor-style'; st.textContent = '' + '.jd-dne-overlay{position:fixed;inset:0;z-index:10080;display:flex;align-items:center;justify-content:center;padding:16px;}' + '.jd-dne-overlay.is-hidden{display:none!important;}' + '.jd-dne-backdrop{position:absolute;inset:0;background:rgba(0,0,0,.72);}' + '.jd-dne-dialog{position:relative;z-index:1;width:min(420px,calc(100vw - 32px));padding:22px 20px 18px;border-radius:14px;' + 'background:linear-gradient(180deg,#0d2848 0%,#061528 100%);border:2px solid rgba(56,232,255,.85);box-shadow:0 0 28px rgba(56,232,255,.35);color:#eaf8ff;font-family:Kanit,Segoe UI,sans-serif;}' + '.jd-dne-title{margin:0 0 14px;font-size:1.25rem;font-weight:700;text-align:center;letter-spacing:.02em;}' + '.jd-dne-input{display:block;width:100%;box-sizing:border-box;padding:12px 14px;border-radius:10px;border:2px solid rgba(56,232,255,.55);' + 'background:rgba(0,20,40,.85);color:#fff;font-size:1.05rem;font-family:inherit;outline:none;}' + '.jd-dne-input:focus{border-color:#5ce9ff;box-shadow:0 0 0 3px rgba(92,233,255,.25);}' + '.jd-dne-hint{margin:8px 0 0;font-size:.82rem;opacity:.75;text-align:center;}' + '.jd-dne-error{margin:8px 0 0;font-size:.85rem;color:#ff8a8a;text-align:center;min-height:1.1em;}' + '.jd-dne-actions{display:flex;gap:10px;margin-top:18px;justify-content:center;}' + '.jd-dne-btn{min-width:110px;padding:10px 16px;border-radius:10px;border:2px solid transparent;font-size:1rem;font-weight:600;font-family:inherit;cursor:pointer;}' + '.jd-dne-btn--cancel{background:rgba(255,255,255,.08);border-color:rgba(255,255,255,.25);color:#e2e8f0;}' + '.jd-dne-btn--confirm{background:linear-gradient(180deg,#2ee6ff,#0ea5c9);border-color:#7df4ff;color:#042033;}'; document.head.appendChild(st); } if (!document.getElementById('jd-display-name-editor-overlay')) { var wrap = document.createElement('div'); wrap.id = 'jd-display-name-editor-overlay'; wrap.className = 'jd-dne-overlay is-hidden'; wrap.setAttribute('aria-hidden', 'true'); wrap.innerHTML = '' + '' + ''; document.body.appendChild(wrap); } editorReady = true; } /** * เปิดกล่องแก้ชื่อ (ใช้แทน window.prompt — ทำงานใน Cursor browser / mobile) * @param {{ initialValue?: string, title?: string }} [options] * @returns {Promise} ชื่อใหม่ หรือ null ถ้ายกเลิก */ function openDisplayNameEditor(options) { ensureNameEditorDom(); var opts = options || {}; var overlay = document.getElementById('jd-display-name-editor-overlay'); var input = document.getElementById('jd-dne-input'); var errEl = document.getElementById('jd-dne-error'); var btnOk = document.getElementById('jd-dne-confirm'); var btnCancel = document.getElementById('jd-dne-cancel'); var backdrop = document.getElementById('jd-dne-backdrop'); var titleEl = document.getElementById('jd-dne-title'); if (!overlay || !input || !btnOk || !btnCancel) { return Promise.resolve(null); } return new Promise(function (resolve) { var settled = false; function finish(value) { if (settled) return; settled = true; overlay.classList.add('is-hidden'); overlay.setAttribute('aria-hidden', 'true'); document.removeEventListener('keydown', onDocKey, true); resolve(value); } function onDocKey(e) { if (overlay.classList.contains('is-hidden')) return; if (e.key === 'Escape') { e.preventDefault(); e.stopPropagation(); finish(null); } } function submit() { if (errEl) errEl.textContent = ''; var safe = sanitizeDisplayName(input.value); if (!safe) { if (errEl) errEl.textContent = 'กรุณากรอกชื่อผู้เล่น'; input.focus(); return; } finish(safe); } if (titleEl && opts.title) titleEl.textContent = opts.title; input.value = opts.initialValue != null ? String(opts.initialValue) : readDisplayName(); if (errEl) errEl.textContent = ''; overlay.classList.remove('is-hidden'); overlay.setAttribute('aria-hidden', 'false'); document.addEventListener('keydown', onDocKey, true); btnOk.onclick = function (e) { e.preventDefault(); submit(); }; btnCancel.onclick = function (e) { e.preventDefault(); finish(null); }; backdrop.onclick = function () { finish(null); }; input.onkeydown = function (e) { if (e.key === 'Enter') { e.preventDefault(); submit(); } }; requestAnimationFrame(function () { input.focus(); input.select(); }); }); } /** * เปิด editor แล้ว apply ชื่อ (socket sync ถ้ามี) * @param {{ socket?: object }} [options] * @returns {Promise<{ ok: boolean, displayName?: string, cancelled?: boolean }>} */ function promptAndApplyDisplayName(options) { var opts = options || {}; return openDisplayNameEditor({ initialValue: readDisplayName() }).then(function (draft) { if (draft == null) return { ok: false, cancelled: true }; return applyDisplayNameChange(draft, opts); }); } global.jdDisplayName = { key: DISPLAY_NAME_KEY, read: readDisplayName, sanitize: sanitizeDisplayName, syncDom: syncDisplayNameDom, apply: applyDisplayNameChange, openEditor: openDisplayNameEditor, promptAndApply: promptAndApplyDisplayName }; global.jdApplyDisplayNameChange = applyDisplayNameChange; global.jdReadDisplayName = readDisplayName; global.jdOpenDisplayNameEditor = openDisplayNameEditor; global.jdPromptAndApplyDisplayName = promptAndApplyDisplayName; })(typeof window !== 'undefined' ? window : this);