如何启发式地发现JavaScript输入自动完成键*事件

huangapple go评论67阅读模式
英文:

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 如何启发式地发现JavaScript输入自动完成键*事件 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)?

    &lt;!DOCTYPE html&gt;
    &lt;html&gt;
    &lt;head&gt;
    &lt;script type=&quot;application/javascript&quot;&gt;
    	&#39;use strict&#39;;
        
    		document.addEventListener(&quot;DOMContentLoaded&quot;, isDOMIsGood);
    
    		function isDOMIsGood() 
            {
    			// Handle autocomplete
    			document.body.addEventListener(&#39;keyup&#39;,
    				(e) =&gt; {
    					
            			if (e.target.tagName.toUpperCase()	!= &quot;INPUT&quot; 		|| 
                        	e.target.type.toUpperCase() 	!= &quot;TEXT&quot; 		||
                            getComputedStyle(e.target).textTransform.toUpperCase() 
    														!= &quot;CAPITALIZE&quot;	||
    						(
    						&quot;transform&quot; in e.target.dataset					&amp;&amp;
    						e.target.dataset.transform.toLowerCase()
    														== &quot;standard&quot;	
    						))												
                        	return true;
    						
    					if (&quot;key&quot; in e) // not autocomplete
    						return true;
    
    					e.target.value = e.target.value.toLowerCase();
    					
    					return true;
    				}
    			);
    			// Handle normal keyboard input			
    			document.body.addEventListener(&#39;keydown&#39;,
                	(e) =&gt; {
                    
                    	const WORD_DELIMS = &quot;.,&amp; -:&quot;;  // Needs work
                        
            			if (e.target.tagName.toUpperCase()	!= &quot;INPUT&quot; 		|| 
                        	e.target.type.toUpperCase() 	!= &quot;TEXT&quot;)
    						return true;
    						
    					if (!(&quot;key&quot; in e)) // autocomplete
    						return true;
    						
                        if (e.key.length 					&gt;  1 			|| 
                            e.altKey 										|| 
                            e.ctrlKey 										|| 
                            e.isComposing 									|| 
                            e.metaKey 										||
                        	e.target.value.length 			==  0 			|| 
                        	e.target.selectionStart			==  0 			|| 
                            e.key 							&gt;  &quot;Z&quot; 			|| 
                            e.key 							&lt;  &quot;A&quot;		 	||
    						(
    						&quot;transform&quot; in e.target.dataset					&amp;&amp;
    						e.target.dataset.transform.toLowerCase()
    														== &quot;standard&quot;	
    						)												||
                            getComputedStyle(e.target).textTransform.toUpperCase() 
    														!= &quot;CAPITALIZE&quot;	||
                            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(&quot;paste&quot;, 
                	(e) =&gt; {
                    	const WORD_DELIMS = &quot;.,&amp; -:&quot;;   // Needs work
                        
            			if (e.target.tagName.toUpperCase()	!= &quot;INPUT&quot; 		|| 
                        	e.target.type.toUpperCase() 	!= &quot;TEXT&quot; 		||
                            getComputedStyle(e.target).textTransform.toUpperCase() 
    														!= &quot;CAPITALIZE&quot;	||
    						(
    						&quot;transform&quot; in e.target.dataset					&amp;&amp;
    						e.target.dataset.transform.toLowerCase()
    														== &quot;standard&quot;	
    						))												
                        	return true;
    
                        let paste = (e.clipboardData || window.clipboardData).getData(&#39;text&#39;);
                        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(&quot;properRules&quot;).addEventListener(&quot;click&quot;, 
    				(e) =&gt; {
    					
    					if (e.target.tagName.toLowerCase() == &quot;input&quot; &amp;&amp; 
    						e.target.type.toLowerCase()    == &quot;radio&quot; &amp;&amp;
    						e.target.name == &quot;properCase&quot;)
    					{
    						var enhanced = document.getElementById(&quot;enhanced&quot;);
    						enhanced.dataset.transform = e.target.value;
    						
    						if (enhanced.dataset.transform == &quot;none&quot;)
    							enhanced.style.textTransform = &quot;none&quot;;
    						else
    							enhanced.style.textTransform = &quot;capitalize&quot;;
    					}	
    					
    					return true;
    				}
    			); 
            }
    &lt;/script&gt;
    &lt;style type=&quot;text/css&quot;&gt;
    input[type=radio]:checked {
    	accent-color: lightblue;;
    }
    &lt;/style&gt;
    &lt;/head&gt;
    &lt;body&gt;
    &lt;h1&gt;Supplementing CSS Text-Transform: Capitalize&lt;/h1&gt;
    &lt;h2&gt;How to enforce &quot;Proper Case&quot; on HTML input?&lt;/h2&gt;
    
    &lt;p&gt;CSS Text-Transform will upcase each word if all lower case but not downcase multiple consecutive caps&lt;/p&gt;
    &lt;div id=&quot;outer&quot;&gt;
    	&lt;div&gt;
    		&lt;label for=&quot;enhanced&quot;&gt;Enhanced Capitalize:&lt;/label&gt;
    		&lt;input id=&quot;enhanced&quot; type=&quot;text&quot; style=&quot;text-transform: capitalize; background-color: lightblue;&quot;
    			autocomplete=&quot;new-password&quot; autofocus spellcheck=&quot;false&quot; &gt;
    		&lt;br&gt;&lt;br&gt;
    	&lt;/div&gt;
    	&lt;div id=&quot;properRules&quot;&gt;
    	  &lt;p&gt;&quot;Proper Case&quot; enforcement level:&lt;/p&gt;
    	  &lt;input type=&quot;radio&quot; id=&quot;pc1&quot; name=&quot;properCase&quot; value=&quot;strict&quot; checked=checked &gt;
    	  &lt;label for=&quot;pc1&quot;&gt;Strict&lt;/label&gt;&lt;br&gt;
    	  &lt;input type=&quot;radio&quot; id=&quot;pc2&quot; name=&quot;properCase&quot; value=&quot;standard&quot;&gt;
    	  &lt;label for=&quot;pc2&quot;&gt;Relaxed&lt;/label&gt;&lt;br&gt;
    	  &lt;input type=&quot;radio&quot; id=&quot;pc3&quot; name=&quot;properCase&quot; value=&quot;none&quot;&gt;
    	  &lt;label for=&quot;pc3&quot;&gt;None&lt;/label&gt;&lt;br&gt;
    	&lt;/div&gt;
    &lt;/div&gt;
    &lt;/body&gt;
    &lt;/html&gt;

答案1

得分: 0

这是如何在不更改HTML的情况下执行的。但我建议更好的方法是为用户提供一个输入框,让他们输入或粘贴文本,然后根据单选按钮的选择来转换该文本。

HTML

&lt;h1&gt;Supplementing CSS Text-Transform: Capitalize&lt;/h1&gt;
&lt;h2&gt;How to enforce &quot;Proper Case&quot; on HTML input?&lt;/h2&gt;

&lt;p&gt;CSS Text-Transform will upcase each word if all lower case but not downcase multiple consecutive caps&lt;/p&gt;
&lt;div id=&quot;outer&quot;&gt;
  &lt;div&gt;
    &lt;label for=&quot;enhanced&quot;&gt;Enhanced Capitalize:&lt;/label&gt;
    &lt;input id=&quot;enhanced&quot; type=&quot;text&quot; style=&quot;background-color: lightblue;&quot; autocomplete=&quot;new-password&quot; autofocus spellcheck=&quot;false&quot;&gt;
    &lt;br&gt;&lt;br&gt;
  &lt;/div&gt;
  &lt;div id=&quot;properRules&quot;&gt;
    &lt;p&gt;&quot;Proper Case&quot; enforcement level:&lt;/p&gt;
    &lt;input type=&quot;radio&quot; id=&quot;pc1&quot; name=&quot;properCase&quot; value=&quot;strict&quot; checked=checked&gt;
    &lt;label for=&quot;pc1&quot;&gt;Strict&lt;/label&gt;&lt;br&gt;
    &lt;input type=&quot;radio&quot; id=&quot;pc2&quot; name=&quot;properCase&quot; value=&quot;standard&quot;&gt;
    &lt;label for=&quot;pc2&quot;&gt;Relaxed&lt;/label&gt;&lt;br&gt;
    &lt;input type=&quot;radio&quot; id=&quot;pc3&quot; name=&quot;properCase&quot; value=&quot;none&quot;&gt;
    &lt;label for=&quot;pc3&quot;&gt;None&lt;/label&gt;&lt;br&gt;
  &lt;/div&gt;
&lt;/div&gt;

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

&lt;h1&gt;Supplementing CSS Text-Transform: Capitalize&lt;/h1&gt;
&lt;h2&gt;How to enforce &quot;Proper Case&quot; on HTML input?&lt;/h2&gt;

&lt;p&gt;CSS Text-Transform will upcase each word if all lower case but not downcase multiple consecutive caps&lt;/p&gt;
&lt;div id=&quot;outer&quot;&gt;
  &lt;div&gt;
    &lt;label for=&quot;enhanced&quot;&gt;Enhanced Capitalize:&lt;/label&gt;
    &lt;input id=&quot;enhanced&quot; type=&quot;text&quot; style=&quot;background-color: lightblue;&quot; autocomplete=&quot;new-password&quot; autofocus spellcheck=&quot;false&quot;&gt;
    &lt;br&gt;&lt;br&gt;
  &lt;/div&gt;
  &lt;div id=&quot;properRules&quot;&gt;
    &lt;p&gt;&quot;Proper Case&quot; enforcement level:&lt;/p&gt;
    &lt;input type=&quot;radio&quot; id=&quot;pc1&quot; name=&quot;properCase&quot; value=&quot;strict&quot; checked=checked&gt;
    &lt;label for=&quot;pc1&quot;&gt;Strict&lt;/label&gt;&lt;br&gt;
    &lt;input type=&quot;radio&quot; id=&quot;pc2&quot; name=&quot;properCase&quot; value=&quot;standard&quot;&gt;
    &lt;label for=&quot;pc2&quot;&gt;Relaxed&lt;/label&gt;&lt;br&gt;
    &lt;input type=&quot;radio&quot; id=&quot;pc3&quot; name=&quot;properCase&quot; value=&quot;none&quot;&gt;
    &lt;label for=&quot;pc3&quot;&gt;None&lt;/label&gt;&lt;br&gt;
  &lt;/div&gt;
&lt;/div&gt;

CSS

input[type=radio]:checked {
  accent-color: lightblue;
}

.capitalize {
  text-transform: capitalize;
}

JS

const textInput = document.getElementById(&quot;enhanced&quot;);
const radioStrict = document.getElementById(&quot;pc1&quot;);
const radioRelaxed = document.getElementById(&quot;pc2&quot;);
const radioNone = document.getElementById(&quot;pc3&quot;);

textInput.addEventListener(&#39;input&#39;, () =&gt; {
  if (radioStrict.checked) {
    textInput.value = textInput.value.toLowerCase();
    textInput.classList.add(&#39;capitalize&#39;);
    return true;
  }

  if (radioRelaxed.checked) {
    textInput.classList.add(&#39;capitalize&#39;);
    return true;
  }

  if (radioNone.checked) {
    textInput.classList.remove(&#39;capitalize&#39;);
    return true;
  }
});

radioStrict.addEventListener(&#39;input&#39;, () =&gt; {
  textInput.value = textInput.value.toLowerCase();
  textInput.classList.add(&#39;capitalize&#39;);
});

radioRelaxed.addEventListener(&#39;input&#39;, () =&gt; {
  textInput.classList.add(&#39;capitalize&#39;);
});

radioNone.addEventListener(&#39;input&#39;, () =&gt; {
  textInput.classList.remove(&#39;capitalize&#39;);
});

huangapple
  • 本文由 发表于 2023年7月20日 15:44:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76727690.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定