Add standalone mobile IME test page
This commit is contained in:
1 parent
778cf39471
commit
cf84dda5ec
1 file changed
+265
@@ -0,0 +1,265 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||
<title>IME Test</title>
|
||||
<style>
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: #f8fafc;
|
||||
color: #0f172a;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
}
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
min-height: 100dvh;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
padding: max(16px, env(safe-area-inset-top)) 16px max(16px, env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
color: #475569;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
label {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea,
|
||||
[contenteditable] {
|
||||
width: 100%;
|
||||
border: 1px solid #cbd5e1;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
color: #0f172a;
|
||||
font: inherit;
|
||||
font-size: 18px;
|
||||
line-height: 1.6;
|
||||
outline: none;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 150px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
[contenteditable] {
|
||||
min-height: 110px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
button {
|
||||
border: 1px solid #94a3b8;
|
||||
border-radius: 999px;
|
||||
background: #fff;
|
||||
color: #0f172a;
|
||||
font: inherit;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
padding: 9px 13px;
|
||||
}
|
||||
|
||||
button.primary {
|
||||
border-color: #10b981;
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
}
|
||||
|
||||
pre {
|
||||
min-height: 180px;
|
||||
max-height: 38dvh;
|
||||
overflow: auto;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
background: #fff;
|
||||
color: #0f172a;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>IME Test</h1>
|
||||
<p>这是一个不加载 React、不加载编辑器的原生输入测试页。依次点下面三个输入区,用豆包输入法按键,然后点“复制日志”。</p>
|
||||
|
||||
<label>
|
||||
Input
|
||||
<input id="plain-input" autocomplete="on" autocorrect="on" inputmode="text" placeholder="点这里输入" />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Textarea
|
||||
<textarea id="plain-textarea" autocomplete="on" autocorrect="on" inputmode="text" placeholder="点这里输入"></textarea>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
Contenteditable
|
||||
<div id="plain-contenteditable" contenteditable="true" role="textbox" aria-multiline="true"></div>
|
||||
</label>
|
||||
|
||||
<div class="buttons">
|
||||
<button class="primary" id="focus-input" type="button">聚焦 Input</button>
|
||||
<button class="primary" id="focus-textarea" type="button">聚焦 Textarea</button>
|
||||
<button class="primary" id="focus-contenteditable" type="button">聚焦 Contenteditable</button>
|
||||
<button id="prompt-input" type="button">Prompt</button>
|
||||
<button id="read-clipboard" type="button">读剪贴板</button>
|
||||
<button id="copy-log" type="button">复制日志</button>
|
||||
<button id="clear-log" type="button">清空日志</button>
|
||||
</div>
|
||||
|
||||
<pre id="log"></pre>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
const input = document.getElementById("plain-input");
|
||||
const textarea = document.getElementById("plain-textarea");
|
||||
const contenteditable = document.getElementById("plain-contenteditable");
|
||||
const logNode = document.getElementById("log");
|
||||
const events = [];
|
||||
|
||||
const activeLabel = () => {
|
||||
const element = document.activeElement;
|
||||
if (!element) return "none";
|
||||
const id = element.id ? `#${element.id}` : "";
|
||||
return `${element.tagName.toLowerCase()}${id}`;
|
||||
};
|
||||
|
||||
const valueOf = (element) => {
|
||||
if (!element) return "";
|
||||
return "value" in element ? element.value : element.innerText;
|
||||
};
|
||||
|
||||
const writeLog = (eventName, event) => {
|
||||
const target = event?.target;
|
||||
const time = new Date().toLocaleTimeString("zh-CN", { hour12: false });
|
||||
const inputType = event && "inputType" in event ? ` type=${event.inputType}` : "";
|
||||
const data = event && "data" in event && event.data ? ` data=${JSON.stringify(event.data)}` : "";
|
||||
const key = event && "key" in event ? ` key=${event.key}` : "";
|
||||
const composing = event && "isComposing" in event ? ` composing=${event.isComposing}` : "";
|
||||
events.unshift(
|
||||
`${time} ${eventName} active=${activeLabel()} target=${target?.id || target?.tagName || "none"} len=${valueOf(target).length}${inputType}${data}${key}${composing}`
|
||||
);
|
||||
events.length = Math.min(events.length, 80);
|
||||
renderLog();
|
||||
};
|
||||
|
||||
const renderLog = () => {
|
||||
const header = [
|
||||
`url=${location.href}`,
|
||||
`userAgent=${navigator.userAgent}`,
|
||||
`active=${activeLabel()}`,
|
||||
`inputLen=${input.value.length}`,
|
||||
`textareaLen=${textarea.value.length}`,
|
||||
`contenteditableLen=${contenteditable.innerText.length}`,
|
||||
"",
|
||||
];
|
||||
logNode.textContent = header.concat(events).join("\n");
|
||||
};
|
||||
|
||||
for (const element of [input, textarea, contenteditable]) {
|
||||
for (const eventName of [
|
||||
"focus",
|
||||
"blur",
|
||||
"click",
|
||||
"keydown",
|
||||
"keyup",
|
||||
"beforeinput",
|
||||
"input",
|
||||
"compositionstart",
|
||||
"compositionupdate",
|
||||
"compositionend",
|
||||
"paste",
|
||||
]) {
|
||||
element.addEventListener(eventName, (event) => writeLog(eventName, event));
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("focus-input").addEventListener("click", () => {
|
||||
input.focus();
|
||||
writeLog("button-focus-input");
|
||||
});
|
||||
|
||||
document.getElementById("focus-textarea").addEventListener("click", () => {
|
||||
textarea.focus();
|
||||
writeLog("button-focus-textarea");
|
||||
});
|
||||
|
||||
document.getElementById("focus-contenteditable").addEventListener("click", () => {
|
||||
contenteditable.focus();
|
||||
writeLog("button-focus-contenteditable");
|
||||
});
|
||||
|
||||
document.getElementById("prompt-input").addEventListener("click", () => {
|
||||
const text = window.prompt("Prompt input");
|
||||
writeLog(text ? "prompt-ok" : "prompt-empty");
|
||||
if (text) {
|
||||
textarea.value += `${textarea.value ? "\\n" : ""}${text}`;
|
||||
textarea.dispatchEvent(new InputEvent("input", { bubbles: true, inputType: "insertText", data: text }));
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById("read-clipboard").addEventListener("click", async () => {
|
||||
try {
|
||||
const text = await navigator.clipboard.readText();
|
||||
writeLog(text ? "clipboard-ok" : "clipboard-empty");
|
||||
if (text) {
|
||||
textarea.value += `${textarea.value ? "\\n" : ""}${text}`;
|
||||
textarea.dispatchEvent(new InputEvent("input", { bubbles: true, inputType: "insertFromPaste", data: text }));
|
||||
}
|
||||
} catch (error) {
|
||||
writeLog(`clipboard-error-${error.name || "unknown"}`);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById("copy-log").addEventListener("click", async () => {
|
||||
renderLog();
|
||||
try {
|
||||
await navigator.clipboard.writeText(logNode.textContent);
|
||||
} catch {
|
||||
window.prompt("Copy log", logNode.textContent);
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById("clear-log").addEventListener("click", () => {
|
||||
events.length = 0;
|
||||
input.value = "";
|
||||
textarea.value = "";
|
||||
contenteditable.innerText = "";
|
||||
renderLog();
|
||||
});
|
||||
|
||||
writeLog("page-ready");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user