Skip to content

Commit abd43b9

Browse files
authored
Add files via upload
1 parent d6bf316 commit abd43b9

1 file changed

Lines changed: 66 additions & 53 deletions

File tree

3code_mobile.html

Lines changed: 66 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+TC:wght@400;700&display=swap" rel="stylesheet">
1010
<style>
1111
/* ----------------------------------------------------- */
12-
/* 手機優化樣式,參考 keyboard.css 和 index-0.html 樣式 */
12+
/* 手機優化樣式 */
1313
/* ----------------------------------------------------- */
1414

1515
:root {
@@ -28,7 +28,7 @@
2828
margin: 0;
2929
padding: 0;
3030
box-sizing: border-box;
31-
-webkit-tap-highlight-color: transparent;
31+
-webkit-tap-highlight-color: transparent; /* 移除點擊高亮 */
3232
outline: none;
3333
}
3434

@@ -99,7 +99,7 @@
9999
cursor: text;
100100
}
101101

102-
/* 候選字與輸入區容器 */
102+
/* 候選字與輸入區 */
103103
#input-area {
104104
width: 100%;
105105
background-color: var(--container-bg);
@@ -110,7 +110,6 @@
110110
border: 1px solid var(--border-color);
111111
}
112112

113-
/* 編碼輸入顯示 */
114113
#main-input {
115114
width: 100%;
116115
padding: 8px;
@@ -125,20 +124,21 @@
125124
overflow-x: auto;
126125
}
127126

128-
/* 候選字橫向滾動容器 */
127+
/* === 候選字區域:修改為橫向滑動 === */
129128
#candidate-display {
130-
display: flex;
129+
display: flex; /* 確保內容在同一行 */
131130
align-items: center;
132131
padding: 8px;
133-
gap: 12px;
134-
white-space: nowrap; /* 確保所有候選字在一行 */
132+
gap: 12px; /* 增加間距 */
133+
white-space: nowrap; /* 內容不換行 */
135134
overflow-x: scroll; /* 允許橫向滾動 */
136-
-webkit-overflow-scrolling: touch; /* 提升 iOS 上的滾動體驗 */
135+
-webkit-overflow-scrolling: touch; /* 改善 iOS 上的滑動體驗 */
137136
min-height: 40px;
138137
}
139138

139+
/* 隱藏滾動條 */
140140
#candidate-display::-webkit-scrollbar {
141-
display: none; /* 隱藏滾動條 */
141+
display: none;
142142
}
143143

144144
#candidate-display span {
@@ -148,8 +148,9 @@
148148
transition: all 0.2s;
149149
user-select: none;
150150
white-space: nowrap;
151-
font-size: 1.2rem; /* 略微放大字體 */
152-
flex-shrink: 0; /* 防止候選字被壓縮 */
151+
font-size: 1.2rem; /* 稍大一點的字體 */
152+
flex-shrink: 0; /* 確保文字不被壓縮 */
153+
text-align: center;
153154
}
154155

155156
#candidate-display span:active, #candidate-display span:hover {
@@ -190,7 +191,7 @@
190191

191192
.key {
192193
flex-grow: 1;
193-
flex-basis: 0;
194+
flex-basis: 0;
194195
padding: 0;
195196
border-radius: 6px;
196197
background-color: var(--key-bg);
@@ -199,7 +200,7 @@
199200
user-select: none;
200201
transition: background-color 0.1s;
201202
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.2);
202-
line-height: 50px;
203+
line-height: 50px;
203204
min-height: 50px;
204205
font-size: 1.2rem;
205206
font-weight: bold;
@@ -213,7 +214,7 @@
213214
}
214215

215216
.key.space-key {
216-
flex: 2; /* 兩倍寬 */
217+
flex: 2;
217218
background-color: #c5cae9;
218219
}
219220

@@ -246,24 +247,24 @@
246247
</div>
247248

248249
<script>
249-
// --- 資料處理與解析 (從 index-0.html 擷取核心部分) ---
250+
// --- 資料處理與解析 ---
250251
let currentCodemap = {};
252+
let currentReverseCodemap = {};
251253

252254
const keyname_map_upper = {
253-
'a': '', 'b': '', 'c': '', 'd': '', 'e': '', 'f': '', 'g': '',
254-
'h': '', 'i': '', 'j': '', 'k': '', 'l': '', 'm': '', 'n': 'P',
255-
'o': '', 'p': '', 'q': '', 'r': '', 's': '', 't': '', 'u': '',
256-
'v': '', 'w': 'O', 'x': 'X', 'y': 'Y', 'z': 'Z',
257-
// 符號對應
258-
"'": "〃", ';': ';', ',': ',', '.': '.', '/': '/', ' ': '空白', 'enter': '換行', 'backspace': '刪除', 'shift': '中/英',
255+
'a': '', 'b': '', 'c': '', 'd': '', 'e': '', 'f': '', 'g': '',
256+
'h': '', 'i': '', 'j': '', 'k': '', 'l': '', 'm': '', 'n': '',
257+
'o': '', 'p': '', 'q': '', 'r': '', 's': '', 't': '', 'u': '',
258+
'v': '', 'w': '', 'x': '', 'y': '', 'z': '',
259+
// 符號對應 (按鍵顯示)
260+
"'": "〃", ';': ';', ',': ',', '.': '.', '/': '/', ' ': '空白鍵', 'enter': 'Enter', 'backspace': '刪除鍵', 'shift': '中/英',
259261
};
260262
const keyname_map_lower = {
261263
'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd', 'e': 'e', 'f': 'f', 'g': 'g',
262264
'h': 'h', 'i': 'i', 'j': 'j', 'k': 'k', 'l': 'l', 'm': 'm', 'n': 'n',
263265
'o': 'o', 'p': 'p', 'q': 'q', 'r': 'r', 's': 's', 't': 't', 'u': 'u',
264266
'v': 'v', 'w': 'w', 'x': 'x', 'y': 'y', 'z': 'z',
265-
// 符號對應
266-
"'": "'", ';': ';', ',': ',', '.': '.', '/': '/', ' ': ' ', 'enter': 'Enter', 'backspace': 'Back', 'shift': 'Shift',
267+
"'": "'", ';': ';', ',': ',', '.': '.', '/': '/', ' ': ' ', 'enter': 'Enter', 'backspace': '刪除鍵', 'shift': '中/英',
267268
};
268269

269270
// DOM 元素
@@ -278,29 +279,35 @@
278279
const MAX_CODE_LENGTH = 3;
279280
let currentCode = '';
280281
let currentCandidates = [];
282+
// let currentPage = 0; // 已移除分頁邏輯
283+
// const candidatesPerPage = 10; // 已移除分頁邏輯
281284
let isEnglishMode = false;
282285

283-
// 函式:格式化碼表資料為物件 (從 index-0.html 擷取)
284286
function parseCinData(data) {
285287
const newCodemap = {};
288+
const newReverseCodemap = {};
286289
const lines = data.trim().split('\n');
287290
lines.forEach(line => {
288291
const parts = line.split('\t');
289292
if (parts.length >= 2 && !line.startsWith('#')) {
290-
const code = parts[0].trim().toLowerCase(); // 確保編碼小寫
293+
const code = parts[0].trim();
291294
const char = parts[1].trim();
292295
if (code && char) {
293296
if (!newCodemap[code]) {
294297
newCodemap[code] = [];
295298
}
296299
newCodemap[code].push(char);
300+
301+
if (!newReverseCodemap[char]) {
302+
newReverseCodemap[char] = [];
303+
}
304+
newReverseCodemap[char].push(code);
297305
}
298306
}
299307
});
300-
return newCodemap;
308+
return { newCodemap, newReverseCodemap };
301309
}
302310

303-
// 函式:載入次常用字碼表 (僅載入 3codes2.txt)
304311
async function loadSecondaryCodemap() {
305312
const fileName = './3codes2.txt';
306313
try {
@@ -309,19 +316,25 @@
309316
throw new Error('Network response was not ok');
310317
}
311318
const text = await response.text();
312-
currentCodemap = parseCinData(text);
319+
const { newCodemap, newReverseCodemap } = parseCinData(text);
320+
currentCodemap = newCodemap;
321+
currentReverseCodemap = newReverseCodemap;
313322
updateModeDisplay();
314323
mainInput.textContent = '編碼表載入成功';
315324
} catch (error) {
316325
console.error(`載入 ${fileName} 時發生錯誤:`, error);
317-
mainInput.textContent = `錯誤:無法載入編碼檔 ${fileName}請確認檔案存在且與此 HTML 位於相同目錄下。`;
326+
mainInput.textContent = `錯誤:無法載入編碼檔 ${fileName}請確認檔案存在。`;
318327
}
319328
resetInputState();
320329
}
321330

322331
// --- 處理中文模式輸入的核心函數 ---
323332
function handleChineseInput(code) {
324-
333+
// 忽略數字鍵
334+
if (code.match(/^[1-90]$/)) {
335+
return;
336+
}
337+
325338
if (code === 'backspace') {
326339
if (currentCode.length > 0) {
327340
currentCode = currentCode.slice(0, -1);
@@ -332,9 +345,8 @@
332345
return;
333346
}
334347
if (code === 'enter') {
335-
// 如果有候選字,選第一個上字
336348
if (currentCandidates.length > 0) {
337-
selectCandidate(0);
349+
selectCandidate(0); // 選第一個候選字上字
338350
} else {
339351
textOutput.textContent += '\n'; // 換行
340352
}
@@ -343,15 +355,15 @@
343355

344356
if (code === ' ') {
345357
if (currentCandidates.length > 0) {
346-
selectCandidate(0);
358+
selectCandidate(0); // 選第一個候選字上字
347359
} else {
348360
textOutput.textContent += ' '; // 輸出全形空格
349361
}
350362
return;
351363
}
352364

353365
const inputChar = code.toLowerCase();
354-
// 接受所有 26 字母和 5 符號的輸入: a-z, ; ' , . /
366+
// 接受所有 26 字母和 5 符號的輸入
355367
if (inputChar.match(/^[a-z;'./,<>]$/)) {
356368
if (currentCode.length === MAX_CODE_LENGTH) {
357369
if (currentCandidates.length > 0) {
@@ -391,7 +403,7 @@
391403

392404
// --- 核心狀態更新與顯示函數 (中文模式專用) ---
393405
function updateStateAndDisplay() {
394-
mainInput.textContent = `輸入編碼: ${formatCode(currentCode)}`;
406+
mainInput.textContent = formatCode(currentCode);
395407
currentCandidates = currentCodemap[currentCode] || [];
396408

397409
if (currentCode.length === MAX_CODE_LENGTH) {
@@ -400,7 +412,7 @@
400412
resetInputState();
401413
return;
402414
} else if (currentCandidates.length === 0) {
403-
// 沒有候選字,清空輸入
415+
// 如果沒有候選字,清空輸入,不做任何輸出
404416
resetInputState();
405417
return;
406418
}
@@ -409,7 +421,7 @@
409421
showCandidates();
410422
}
411423

412-
// --- 顯示候選字為可滑動列表 (更新) ---
424+
// --- 顯示候選字為**滑動列表 (已移除編號和分頁)** ---
413425
function showCandidates() {
414426
candidateDisplay.innerHTML = '';
415427

@@ -421,19 +433,24 @@
421433
return;
422434
}
423435

424-
// 顯示所有候選字並支援點擊
436+
// 顯示所有候選字
425437
currentCandidates.forEach((candidate, index) => {
426438
const span = document.createElement('span');
427-
// 移除數字標記,直接顯示漢字
428-
span.textContent = candidate;
429-
span.onclick = () => selectCandidate(index);
439+
// 不顯示編號
440+
span.textContent = candidate;
441+
// 直接使用陣列索引
442+
span.onclick = () => selectCandidate(index);
430443
candidateDisplay.appendChild(span);
431444
});
445+
446+
// 確保候選字滾動到最左邊
447+
candidateDisplay.scrollLeft = 0;
432448
}
433449

434-
// --- 選擇候選字並清空輸入 ---
450+
// --- 選擇候選字並清空輸入 (已移除分頁邏輯) ---
435451
function selectCandidate(index) {
436-
const selectedCandidate = currentCandidates[index];
452+
// 使用絕對索引
453+
const selectedCandidate = currentCandidates[index];
437454
if (selectedCandidate) {
438455
textOutput.textContent += selectedCandidate;
439456
resetInputState();
@@ -444,15 +461,15 @@
444461
function resetInputState() {
445462
currentCode = '';
446463
currentCandidates = [];
447-
mainInput.textContent = isEnglishMode ? '英文模式' : '編碼顯示在此';
464+
mainInput.textContent = '編碼顯示在此';
448465
showCandidates();
449466
}
450467

451468
// --- 格式化編碼顯示 ---
452469
function formatCode(code) {
453470
let displayString = '';
454471
for (const char of code) {
455-
// 顯示基礎字根/符號
472+
// 使用大寫字母/全形符號顯示編碼
456473
displayString += keyname_map_upper[char] || char.toUpperCase();
457474
}
458475
return displayString;
@@ -464,7 +481,6 @@
464481
document.querySelectorAll('.key[data-code]').forEach(keyElement => {
465482
const code = keyElement.dataset.code;
466483
if (map[code]) {
467-
// 功能鍵使用原始標籤,字符鍵使用大小寫/字根
468484
keyElement.textContent = map[code];
469485
}
470486
});
@@ -477,12 +493,11 @@
477493

478494
// --- 動態生成手機優化鍵盤 ---
479495
function generateMobileKeyboard() {
480-
// 佈局包含 26 字母和 5 個特殊符號: ; ' , . /
481496
const layout_mobile = [
482497
['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
483498
['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';'],
484-
['Shift', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', "'"],
485-
['Space', 'Back', 'Enter'] // 移除 123
499+
['Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', "'"],
500+
['Shift', 'Space', 'Back', 'Enter']
486501
];
487502

488503
keyboardContainer.innerHTML = '';
@@ -545,7 +560,6 @@
545560
return;
546561
}
547562

548-
// 嘗試使用現代瀏覽器的 Clipboard API
549563
if (navigator.clipboard) {
550564
navigator.clipboard.writeText(textToCopy).then(() => {
551565
alert('文字已成功複製到剪貼簿!');
@@ -554,7 +568,6 @@
554568
alert('複製失敗,可能需要 HTTPS 或手動選取。');
555569
});
556570
} else {
557-
// 後備方案
558571
const tempInput = document.createElement('textarea');
559572
tempInput.value = textToCopy;
560573
document.body.appendChild(tempInput);
@@ -582,7 +595,7 @@
582595
// 頁面啟動
583596
document.addEventListener('DOMContentLoaded', () => {
584597
generateMobileKeyboard();
585-
loadSecondaryCodemap(); // 啟動時載入次常用字碼表
598+
loadSecondaryCodemap();
586599

587600
copyButton.addEventListener('click', copyTextToClipboard);
588601
clearButton.addEventListener('click', clearOutput);

0 commit comments

Comments
 (0)