From eda4fff0c50e196c429d0333659678f90f6e4ff2 Mon Sep 17 00:00:00 2001 From: Youzini-afk <13153778771cx@gmail.com> Date: Fri, 17 Apr 2026 22:56:37 +0800 Subject: [PATCH] fix: harden ena planner mobile button actions --- ena-planner/ena-planner.html | 102 ++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 37 deletions(-) diff --git a/ena-planner/ena-planner.html b/ena-planner/ena-planner.html index 9ef87e5..e42e37a 100644 --- a/ena-planner/ena-planner.html +++ b/ena-planner/ena-planner.html @@ -27,7 +27,7 @@
就绪
保存
- +
@@ -125,7 +125,7 @@
- +
@@ -140,8 +140,8 @@
- - + +
@@ -205,15 +205,15 @@
- - - + + +
@@ -222,8 +222,8 @@
- - + +
@@ -278,9 +278,9 @@
诊断工具
- - - + + +

         
@@ -301,9 +301,9 @@
- - - + + +
暂无日志
@@ -517,29 +517,38 @@ right.className = 'prompt-head-right'; const upBtn = document.createElement('button'); + upBtn.type = 'button'; upBtn.className = 'btn btn-sm'; upBtn.textContent = '↑'; upBtn.disabled = idx === 0; - upBtn.addEventListener('click', () => { + upBtn.addEventListener('click', ev => { + ev.preventDefault(); + ev.stopPropagation(); if (idx === 0) return; [cfg.promptBlocks[idx - 1], cfg.promptBlocks[idx]] = [cfg.promptBlocks[idx], cfg.promptBlocks[idx - 1]]; renderPromptList(); scheduleSave(); }); const downBtn = document.createElement('button'); + downBtn.type = 'button'; downBtn.className = 'btn btn-sm'; downBtn.textContent = '↓'; downBtn.disabled = idx === total - 1; - downBtn.addEventListener('click', () => { + downBtn.addEventListener('click', ev => { + ev.preventDefault(); + ev.stopPropagation(); if (idx >= total - 1) return; [cfg.promptBlocks[idx], cfg.promptBlocks[idx + 1]] = [cfg.promptBlocks[idx + 1], cfg.promptBlocks[idx]]; renderPromptList(); scheduleSave(); }); const delBtn = document.createElement('button'); + delBtn.type = 'button'; delBtn.className = 'btn btn-sm btn-del'; delBtn.textContent = '删除'; - delBtn.addEventListener('click', () => { + delBtn.addEventListener('click', ev => { + ev.preventDefault(); + ev.stopPropagation(); cfg.promptBlocks.splice(idx, 1); renderPromptList(); scheduleSave(); }); @@ -757,21 +766,40 @@ /* ── Event bindings ── */ function bindEvents() { + document.addEventListener('submit', ev => { + ev.preventDefault(); + ev.stopPropagation(); + }); + + document.querySelectorAll('button').forEach(btn => { + if (!btn.getAttribute('type')) btn.setAttribute('type', 'button'); + }); + + const bindButtonAction = (id, handler) => { + const element = $(id); + if (!element) return; + element.addEventListener('click', ev => { + ev.preventDefault(); + ev.stopPropagation(); + handler(ev); + }); + }; + $$('.nav-item, .mobile-nav-item').forEach(item => { item.addEventListener('click', () => activateTab(item.dataset.view)); }); - $('ep_close').addEventListener('click', () => post('xb-ena:close')); + bindButtonAction('ep_close', () => post('xb-ena:close')); $('ep_enabled').addEventListener('change', () => setBadge(toBool($('ep_enabled').value, true))); - $('ep_run_test').addEventListener('click', () => { + bindButtonAction('ep_run_test', () => { const text = $('ep_test_input').value.trim() || '(测试输入)我想让你帮我规划下一步剧情。'; post('xb-ena:run-test', { text }); setLocalStatus('ep_test_status', '测试中…', 'loading'); }); - $('ep_toggle_key').addEventListener('click', () => { + bindButtonAction('ep_toggle_key', () => { const input = $('ep_api_key'); const btn = $('ep_toggle_key'); if (input.type === 'password') { @@ -783,11 +811,11 @@ $('ep_prefix_mode').addEventListener('change', updatePrefixModeUI); - $('ep_fetch_models').addEventListener('click', () => { + bindButtonAction('ep_fetch_models', () => { post('xb-ena:fetch-models'); setLocalStatus('ep_api_status', '拉取中…', 'loading'); }); - $('ep_test_conn').addEventListener('click', () => { + bindButtonAction('ep_test_conn', () => { post('xb-ena:fetch-models'); setLocalStatus('ep_api_status', '测试中…', 'loading'); }); @@ -801,13 +829,13 @@ $('ep_keep_tags').value = normalized.join(', '); }); - $('ep_add_prompt').addEventListener('click', () => { + bindButtonAction('ep_add_prompt', () => { cfg.promptBlocks = cfg.promptBlocks || []; cfg.promptBlocks.push({ id: genId(), role: 'system', name: '新块', content: '' }); renderPromptList(); scheduleSave(); }); - $('ep_reset_prompt').addEventListener('click', () => { + bindButtonAction('ep_reset_prompt', () => { if (!confirm('确定恢复默认提示词块?当前提示词块将被覆盖。')) return; if (pendingSave) return; const requestId = `ena_reset_${Date.now()}`; @@ -825,7 +853,7 @@ renderPromptList(); scheduleSave(); }); - $('ep_tpl_save').addEventListener('click', () => { + bindButtonAction('ep_tpl_save', () => { const name = $('ep_tpl_select').value; if (!name) { setSaveIndicator('error', '请先选择或创建模板'); return; } cfg.promptTemplates = cfg.promptTemplates || {}; @@ -834,7 +862,7 @@ renderTemplateSelect(name); scheduleSave(); }); - $('ep_tpl_saveas').addEventListener('click', () => { + bindButtonAction('ep_tpl_saveas', () => { const name = prompt('新模板名称'); if (!name) return; cfg.promptTemplates = cfg.promptTemplates || {}; @@ -843,7 +871,7 @@ renderTemplateSelect(name); scheduleSave(); }); - $('ep_tpl_delete').addEventListener('click', () => { + bindButtonAction('ep_tpl_delete', () => { const name = $('ep_tpl_select').value; if (!name) return; const backup = structuredClone(cfg.promptTemplates[name]); @@ -853,7 +881,7 @@ showUndoBar(name, backup); }); - $('ep_tpl_undo_btn').addEventListener('click', () => { + bindButtonAction('ep_tpl_undo_btn', () => { if (!undoState) return; cfg.promptTemplates = cfg.promptTemplates || {}; cfg.promptTemplates[undoState.name] = undoState.blocks; @@ -862,28 +890,28 @@ clearUndo(); scheduleSave(); }); - $('ep_debug_worldbook').addEventListener('click', () => { + bindButtonAction('ep_debug_worldbook', () => { $('ep_debug_output').classList.add('visible'); $('ep_debug_output').textContent = '诊断中…'; post('xb-ena:debug-worldbook'); }); - $('ep_debug_char').addEventListener('click', () => { + bindButtonAction('ep_debug_char', () => { $('ep_debug_output').classList.add('visible'); $('ep_debug_output').textContent = '诊断中…'; post('xb-ena:debug-char'); }); - $('ep_test_planner').addEventListener('click', () => { + bindButtonAction('ep_test_planner', () => { post('xb-ena:run-test', { text: '(测试输入)请规划下一步剧情走向。' }); $('ep_debug_output').classList.add('visible'); $('ep_debug_output').textContent = '规划测试中…'; }); - $('ep_open_logs').addEventListener('click', () => post('xb-ena:logs-request')); - $('ep_log_clear').addEventListener('click', () => { + bindButtonAction('ep_open_logs', () => post('xb-ena:logs-request')); + bindButtonAction('ep_log_clear', () => { if (!confirm('确定清空所有日志?')) return; post('xb-ena:logs-clear'); }); - $('ep_log_export').addEventListener('click', () => { + bindButtonAction('ep_log_export', () => { const blob = new Blob([JSON.stringify(logs || [], null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a');