英文:
How to heuristically discover Javascript input autocomplete key* events
问题
以下是您提供的HTML和JavaScript代码的翻译部分:
最近,我有一个需求,需要在HTML输入字段中强制执行Proper-Case。CSS的Text-Transform: Capitalize几乎满足了需求,但不能转换多个大写字母为小写。所以我编写了下面的JavaScript代码。
令人惊讶的是,您会发现自动完成输入(用户点击自动完成选项之一)会导致没有任何"key"属性的keyup和keydown事件:-( 正如您在代码中看到的,我不得不在事件中搜索"key",如果不存在我就假定它是自动完成。
是否有更好/有文档记录的方法?毕竟,自动完成更像是"粘贴"事件吗?有人有关于规范的指导吗?
<!DOCTYPE html>
<html>
<head>
<script type="application/javascript">
'use strict';
document.addEventListener("DOMContentLoaded", isDOMIsGood);
function isDOMIsGood()
{
// 处理自动完成
document.body.addEventListener('keyup',
(e) => {
if (e.target.tagName.toUpperCase() != "INPUT" ||
e.target.type.toUpperCase() != "TEXT" ||
getComputedStyle(e.target).textTransform.toUpperCase()
!= "CAPITALIZE" ||
(
"transform" in e.target.dataset &&
e.target.dataset.transform.toLowerCase()
== "standard"
))
return true;
if ("key" in e) // 非自动完成
return true;
e.target.value = e.target.value.toLowerCase();
return true;
}
);
// 处理普通键盘输入
document.body.addEventListener('keydown',
(e) => {
const WORD_DELIMS = ".,& -:"; // 需要改进
if (e.target.tagName.toUpperCase() != "INPUT" ||
e.target.type.toUpperCase() != "TEXT")
return true;
if (!("key" in e)) // 自动完成
return true;
if (e.key.length > 1 ||
e.altKey ||
e.ctrlKey ||
e.isComposing ||
e.metaKey ||
e.target.value.length == 0 ||
e.target.selectionStart == 0 ||
e.key > "Z" ||
e.key < "A" ||
(
"transform" in e.target.dataset &&
e.target.dataset.transform.toLowerCase()
== "standard"
) ||
getComputedStyle(e.target).textTransform.toUpperCase()
!= "CAPITALIZE" ||
WORD_DELIMS.indexOf(e.target.value.substr(e.target.selectionStart - 1, 1)) != -1)
return true;
let cursorPos = e.target.selectionStart;
e.target.value = e.target.value.substring(0, cursorPos) +
String.fromCharCode(e.key.charCodeAt(0) + 32) +
e.target.value.substring(cursorPos);
e.target.selectionStart = ++cursorPos;
e.target.selectionEnd = cursorPos;
e.preventDefault();
e.stopPropagation();
return false;
}
);
// 处理粘贴
document.body.addEventListener("paste",
(e) => {
const WORD_DELIMS = ".,& -:"; // 需要改进
if (e.target.tagName.toUpperCase() != "INPUT" ||
e.target.type.toUpperCase() != "TEXT" ||
getComputedStyle(e.target).textTransform.toUpperCase()
!= "CAPITALIZE" ||
(
"transform" in e.target.dataset &&
e.target.dataset.transform.toLowerCase()
== "standard"
))
return true;
let paste = (e.clipboardData || window.clipboardData).getData('text');
if (paste.length == 0)
return true;
e.target.value = (e.target.value.substring(0, e.target.selectionStart) +
paste + e.target.value.substring(e.target.selectionStart)).toLowerCase();
e.preventDefault();
e.stopPropagation();
return true;
}
);
// 允许用户、配置文件等设置执行级别
document.getElementById("properRules").addEventListener("click",
(e) => {
if (e.target.tagName.toLowerCase() == "input" &&
e.target.type.toLowerCase() == "radio" &&
e.target.name == "properCase")
{
var enhanced = document.getElementById("enhanced");
enhanced.dataset.transform = e.target.value;
if (enhanced.dataset.transform == "none")
enhanced.style.textTransform = "none";
else
enhanced.style.textTransform = "capitalize";
}
return true;
}
);
}
</script>
<style type="text/css">
input[type=radio]:checked {
accent-color: lightblue;;
}
</style>
</head>
<body>
<h1>补充CSS Text-Transform: Capitalize</h1>
<h2>如何在HTML输入字段上强制执行"Proper Case"?</h2>
<p>CSS Text-Transform会将每个单词转换为大写,但不会将多个连续的大写字母转换为小写</p>
<div id="outer">
<div>
<label for="enhanced">增强型大写:</label>
<input id="enhanced" type="text" style="text-transform: capitalize; background-color: lightblue;"
autocomplete="new-password" autofocus spellcheck="false" >
<br><br>
</div>
<div id="properRules">
<p>"Proper Case" 执行级别:</p>
<input type="radio" id="pc1" name="properCase" value="strict" checked=checked >
<label for="pc1">严格</label><br>
<input type="radio" id="pc2" name="properCase" value="standard">
<label for="pc2">标准</label><br>
<input type="radio" id="pc3" name="properCase" value="none">
<label for="pc3">无</label><br>
</div>
</div>
</body>
</html>
英文:
I recently had a requirement to enforce Proper-Case in a HTML input field. CSS Text-Transform: Capitalize was 90% there but didn't down-case multiple caps. So I wrote the Javascript below.
To my surprise you'll see that autocomplete input (user clicking one of the autocomplete options) results in keyup and keydown events that are bereft of any "key" properties As you can also see in the code, I'm having to search for "key" in the event and if it's not there I assume it's an autocomplete.
Is there a better/documented way? Surely an autocomplete is more of a "Paste" event? Does someone have pointers to a specification(s)?
<!DOCTYPE html>
<html>
<head>
<script type="application/javascript">
'use strict';
document.addEventListener("DOMContentLoaded", isDOMIsGood);
function isDOMIsGood()
{
// Handle autocomplete
document.body.addEventListener('keyup',
(e) => {
if (e.target.tagName.toUpperCase() != "INPUT" ||
e.target.type.toUpperCase() != "TEXT" ||
getComputedStyle(e.target).textTransform.toUpperCase()
!= "CAPITALIZE" ||
(
"transform" in e.target.dataset &&
e.target.dataset.transform.toLowerCase()
== "standard"
))
return true;
if ("key" in e) // not autocomplete
return true;
e.target.value = e.target.value.toLowerCase();
return true;
}
);
// Handle normal keyboard input
document.body.addEventListener('keydown',
(e) => {
const WORD_DELIMS = ".,& -:"; // Needs work
if (e.target.tagName.toUpperCase() != "INPUT" ||
e.target.type.toUpperCase() != "TEXT")
return true;
if (!("key" in e)) // autocomplete
return true;
if (e.key.length > 1 ||
e.altKey ||
e.ctrlKey ||
e.isComposing ||
e.metaKey ||
e.target.value.length == 0 ||
e.target.selectionStart == 0 ||
e.key > "Z" ||
e.key < "A" ||
(
"transform" in e.target.dataset &&
e.target.dataset.transform.toLowerCase()
== "standard"
) ||
getComputedStyle(e.target).textTransform.toUpperCase()
!= "CAPITALIZE" ||
WORD_DELIMS.indexOf(e.target.value.substr(e.target.selectionStart - 1, 1)) != -1)
return true;
let cursorPos = e.target.selectionStart;
e.target.value = e.target.value.substring(0, cursorPos) +
String.fromCharCode(e.key.charCodeAt(0) + 32) +
e.target.value.substring(cursorPos);
e.target.selectionStart = ++cursorPos;
e.target.selectionEnd = cursorPos;
e.preventDefault();
e.stopPropagation();
return false;
}
);
// Handle paste
document.body.addEventListener("paste",
(e) => {
const WORD_DELIMS = ".,& -:"; // Needs work
if (e.target.tagName.toUpperCase() != "INPUT" ||
e.target.type.toUpperCase() != "TEXT" ||
getComputedStyle(e.target).textTransform.toUpperCase()
!= "CAPITALIZE" ||
(
"transform" in e.target.dataset &&
e.target.dataset.transform.toLowerCase()
== "standard"
))
return true;
let paste = (e.clipboardData || window.clipboardData).getData('text');
if (paste.length == 0)
return true;
e.target.value = (e.target.value.substring(0, e.target.selectionStart) +
paste + e.target.value.substring(e.target.selectionStart)).toLowerCase();
e.preventDefault();
e.stopPropagation();
return true;
}
);
// Allow the user, config file, etc set the enforcement level
document.getElementById("properRules").addEventListener("click",
(e) => {
if (e.target.tagName.toLowerCase() == "input" &&
e.target.type.toLowerCase() == "radio" &&
e.target.name == "properCase")
{
var enhanced = document.getElementById("enhanced");
enhanced.dataset.transform = e.target.value;
if (enhanced.dataset.transform == "none")
enhanced.style.textTransform = "none";
else
enhanced.style.textTransform = "capitalize";
}
return true;
}
);
}
</script>
<style type="text/css">
input[type=radio]:checked {
accent-color: lightblue;;
}
</style>
</head>
<body>
<h1>Supplementing CSS Text-Transform: Capitalize</h1>
<h2>How to enforce "Proper Case" on HTML input?</h2>
<p>CSS Text-Transform will upcase each word if all lower case but not downcase multiple consecutive caps</p>
<div id="outer">
<div>
<label for="enhanced">Enhanced Capitalize:</label>
<input id="enhanced" type="text" style="text-transform: capitalize; background-color: lightblue;"
autocomplete="new-password" autofocus spellcheck="false" >
<br><br>
</div>
<div id="properRules">
<p>"Proper Case" enforcement level:</p>
<input type="radio" id="pc1" name="properCase" value="strict" checked=checked >
<label for="pc1">Strict</label><br>
<input type="radio" id="pc2" name="properCase" value="standard">
<label for="pc2">Relaxed</label><br>
<input type="radio" id="pc3" name="properCase" value="none">
<label for="pc3">None</label><br>
</div>
</div>
</body>
</html>
答案1
得分: 0
这是如何在不更改HTML的情况下执行的。但我建议更好的方法是为用户提供一个输入框,让他们输入或粘贴文本,然后根据单选按钮的选择来转换该文本。
HTML
<h1>Supplementing CSS Text-Transform: Capitalize</h1>
<h2>How to enforce "Proper Case" on HTML input?</h2>
<p>CSS Text-Transform will upcase each word if all lower case but not downcase multiple consecutive caps</p>
<div id="outer">
<div>
<label for="enhanced">Enhanced Capitalize:</label>
<input id="enhanced" type="text" style="background-color: lightblue;" autocomplete="new-password" autofocus spellcheck="false">
<br><br>
</div>
<div id="properRules">
<p>"Proper Case" enforcement level:</p>
<input type="radio" id="pc1" name="properCase" value="strict" checked=checked>
<label for="pc1">Strict</label><br>
<input type="radio" id="pc2" name="properCase" value="standard">
<label for="pc2">Relaxed</label><br>
<input type="radio" id="pc3" name="properCase" value="none">
<label for="pc3">None</label><br>
</div>
</div>
CSS
input[type=radio]:checked {
accent-color: lightblue;
}
.capitalize {
text-transform: capitalize;
}
JS
const textInput = document.getElementById("enhanced");
const radioStrict = document.getElementById("pc1");
const radioRelaxed = document.getElementById("pc2");
const radioNone = document.getElementById("pc3");
textInput.addEventListener('input', () => {
if (radioStrict.checked) {
textInput.value = textInput.value.toLowerCase();
textInput.classList.add('capitalize');
return true;
}
if (radioRelaxed.checked) {
textInput.classList.add('capitalize');
return true;
}
if (radioNone.checked) {
textInput.classList.remove('capitalize');
return true;
}
});
radioStrict.addEventListener('input', () => {
textInput.value = textInput.value.toLowerCase();
textInput.classList.add('capitalize');
});
radioRelaxed.addEventListener('input', () => {
textInput.classList.add('capitalize');
});
radioNone.addEventListener('input', () => {
textInput.classList.remove('capitalize');
});
英文:
Here is how you can do it without changing the html. But I would suggest a better way would be to have an input for the user to enter or paste their text and an output where you transform that text based on a radio button selection.
<br>
<br>
HTML
<h1>Supplementing CSS Text-Transform: Capitalize</h1>
<h2>How to enforce "Proper Case" on HTML input?</h2>
<p>CSS Text-Transform will upcase each word if all lower case but not downcase multiple consecutive caps</p>
<div id="outer">
<div>
<label for="enhanced">Enhanced Capitalize:</label>
<input id="enhanced" type="text" style="background-color: lightblue;" autocomplete="new-password" autofocus spellcheck="false">
<br><br>
</div>
<div id="properRules">
<p>"Proper Case" enforcement level:</p>
<input type="radio" id="pc1" name="properCase" value="strict" checked=checked>
<label for="pc1">Strict</label><br>
<input type="radio" id="pc2" name="properCase" value="standard">
<label for="pc2">Relaxed</label><br>
<input type="radio" id="pc3" name="properCase" value="none">
<label for="pc3">None</label><br>
</div>
</div>
CSS
input[type=radio]:checked {
accent-color: lightblue;
}
.capitalize {
text-transform: capitalize;
}
JS
const textInput = document.getElementById("enhanced");
const radioStrict = document.getElementById("pc1");
const radioRelaxed = document.getElementById("pc2");
const radioNone = document.getElementById("pc3");
textInput.addEventListener('input', () => {
if (radioStrict.checked) {
textInput.value = textInput.value.toLowerCase();
textInput.classList.add('capitalize');
return true;
}
if (radioRelaxed.checked) {
textInput.classList.add('capitalize');
return true;
}
if (radioNone.checked) {
textInput.classList.remove('capitalize');
return true;
}
});
radioStrict.addEventListener('input', () => {
textInput.value = textInput.value.toLowerCase();
textInput.classList.add('capitalize');
});
radioRelaxed.addEventListener('input', () => {
textInput.classList.add('capitalize');
});
radioNone.addEventListener('input', () => {
textInput.classList.remove('capitalize');
});
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论