简体   繁体   中英

HTML Texeare caret control using left, right, down, up, home and end virtual buttons

I am trying to put navigation control buttons on the HTML textarea box.So far the Tab works fine. The Backapace works fine. So do the End, Home, and Space buttons. The LEFT and RIGHT buttons keep jumping TWO characters with every click on the button.I have been banging my head for two days trying to find a solution before I decided to post the question. This is the link for the JSFiddle:[] ( https://jsfiddle.net/ChemistryOfMath/uuchyfg0/8/ ) https://jsfiddle.net/ChemistryOfMath/uuchyfg0/8/
The HTML code is as follows:

 <html> <head> <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.2.js"></script> <title>Test Caret</title> <style type="text/css"> #txtarea { display: block; padding: 5px; width: 200px; height: 100px; font: 1em, Verdana, Sans-Serif; background: #fff; border: 1px solid #486787; margin-left: 40px; } #kbdFrame { float: left; } ul li { white-space: nowrap; overflow: hidden; list-style-type: none; display: inline-block; border: 1px solid #111db3; margin: 2px; color: #000; border-radius: 5px; box-sizing: border-box; text-align: center; overflow: hidden; cursor: pointer; font-family: arial, sans-serif; font-size: 15px; width: 45px; height: 45px; line-height: 45px; } #left, #up, #right, #down { color: red; } </style> <script type="text/javascript"> $(document).ready(function() { var e = document.getElementById('txtarea'); e.focus(); var character; /**===FUNCTIONs=======================*/ BACKSPACE = function() { character = ""; var pos = e.selectionStart; if (e.selectionStart == e.selectionEnd) { e.value = e.value.substr(0, e.selectionStart - 1) + character + e.value.substr(e.selectionEnd, e.value.length); e.selectionStart = pos - 1; e.selectionEnd = pos - 1; } else { // replace selected text e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); e.selectionStart = pos; e.selectionEnd = pos; } } TAB = function() { var pos = e.selectionEnd character = "\\t" e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); e.selectionStart = pos + 1; e.selectionEnd = pos + 1; } LEFT = function() { //character = "" e.selectionStart = e.selectionEnd -= 1; } RIGHT = function() { //character = "" e.selectionStart = e.selectionEnd += 1; } DOWN = function() { //character = "" //e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); var pos = e.selectionEnd, prevLine = e.value.lastIndexOf('\\n', pos), nextLine = e.value.indexOf('\\n', pos + 1); if (nextLine === -1) return; pos = pos - prevLine; e.selectionStart = e.selectionEnd = nextLine + pos; } UP = function() { //character = "" //e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); var pos = e.selectionEnd, prevLine = e.value.lastIndexOf('\\n', pos), TwoBLine = e.value.lastIndexOf('\\n', prevLine - 1); if (prevLine === -1) return; pos = pos - prevLine; e.selectionStart = e.selectionEnd = TwoBLine + pos; } HOME = function() { //character = "" //e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); e.selectionEnd = e.selectionStart = e.value.lastIndexOf( '\\n', e.selectionEnd - 1 ) + 1; } END = function() { //character = "" //e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); var pos = e.selectionEnd, i = e.value.indexOf('\\n', pos); if (i === -1) i = e.value.length; e.selectionStart = e.selectionEnd = i; } SPACE = function() { var x = e.selectionStart character = " " character = e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); e.selectionStart = pos + 1; e.selectionEnd = pos + 1; } /**===Buttons=======================*/ $(".keyboard").click(function(evt) { $("#txtarea").focus(); var mykeyID = evt.target.id; var character = $(evt.target).text(); switch (mykeyID) { case "tab": //$("#txtarea").focus(); TAB(); break; case "space": SPACE(); break; case "bkSp": BACKSPACE(); break; case "left": LEFT(); //$("#txtarea").focus(); break; case "right": RIGHT(); //$("#txtarea").focus(); break; case "down": DOWN(); //$("#txtarea").focus(); break; case "up": UP(); //$("#txtarea").focus(); break; case "home": HOME(); //$("#txtarea").focus(); break; case "end": END(); //$("#txtarea").focus(); break; default: character = e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); //e.selectionStart = 0; //e.selectionEnd = 0; $("#txtarea").val(character); break; } }); }); </script> </head> <body> <textarea type="text" name="txtarea" id="txtarea">Testing the right and left buttons. Please help.</textarea> <div class="" id="kbdFrame"> <ul class="keyboard" id=""> <ul id="rOne"> <li class="key" id="tab">Tab</li> <li class="key" id="up">Up</li> <li class="key" id="bkSp">&larr;</li> </ul> <ul class="keyboard" id="rSix"> <li class="key" id="left">Left</li> <li class="key" id="home">Home</li> <li class="key" id="right">Right</li> </ul> <ul class="keyboard kbdR7" id="rSeven"> <li class="key" id="space">Space</li> <li class="key" id="down">Down</li> <li class="key" id="end">End</li> </ul> </ul> </div> </body> </html> 

The (".keyboard").click() is triggered 2 times. Why ? Because the buttons are in a ul with keyboard class who itself is in a ul with a keyboard class.

<ul class="keyboard" id="">

  [...]

  <ul class="keyboard" id="rSix">
    <li class="key" id="left">Left</li>
    <li class="key" id="home">Home</li>
    <li class="key" id="right">Right</li>
  </ul>

  [...]

</ul>

So the trigger is executed 2 times. Remove the first keyboard class : JSFiddle

Your problem is the event delegation. For details you may take a look to event-delegation

This problem is up to event handling:

$(".keyboard").click(function(evt) {

and the html source:

<ul class="keyboard" id="">

and inside another:

<ul class="keyboard" id="rSix">

This means: whenever you click on ".keyboard", the following handler:

$(".keyboard").click(function(evt) {

receives two events, one for each of the following two elements (in sequence):

<ul class="keyboard" id="rSix">

and immeditaly after from this other:

<ul class="keyboard" id="">

A possible solution to avoid this problem is to stop the event bubling calling the following line of code:

evt.stopPropagation();

as first line in your click handler.

Another solution is to use a different event delegation:

$(".keyboard li").click(function(evt) {

In the following snippet the correct code:

 $(function () { var e = document.getElementById('txtarea'); e.focus(); var character; /**===FUNCTIONs=======================*/ BACKSPACE = function() { character = ""; var pos = e.selectionStart; if (e.selectionStart == e.selectionEnd) { e.value = e.value.substr(0, e.selectionStart - 1) + character + e.value.substr(e.selectionEnd, e.value.length); e.selectionStart = pos - 1; e.selectionEnd = pos - 1; } else { // replace selected text e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); e.selectionStart = pos; e.selectionEnd = pos; } } TAB = function() { var pos = e.selectionEnd character = "\\t" e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); e.selectionStart = pos + 1; e.selectionEnd = pos + 1; } LEFT = function() { //character = "" e.selectionStart = e.selectionEnd -= 1; } RIGHT = function() { //character = "" e.selectionStart = e.selectionEnd += 1; } DOWN = function() { //character = "" //e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); var pos = e.selectionEnd, prevLine = e.value.lastIndexOf('\\n', pos), nextLine = e.value.indexOf('\\n', pos + 1); if (nextLine === -1) return; pos = pos - prevLine; e.selectionStart = e.selectionEnd = nextLine + pos; } UP = function() { //character = "" //e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); var pos = e.selectionEnd, prevLine = e.value.lastIndexOf('\\n', pos), TwoBLine = e.value.lastIndexOf('\\n', prevLine - 1); if (prevLine === -1) return; pos = pos - prevLine; e.selectionStart = e.selectionEnd = TwoBLine + pos; } HOME = function() { //character = "" //e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); e.selectionEnd = e.selectionStart = e.value.lastIndexOf( '\\n', e.selectionEnd - 1 ) + 1; } END = function() { //character = "" //e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); var pos = e.selectionEnd, i = e.value.indexOf('\\n', pos); if (i === -1) i = e.value.length; e.selectionStart = e.selectionEnd = i; } SPACE = function() { var x = e.selectionStart character = " " character = e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); e.selectionStart = pos + 1; e.selectionEnd = pos + 1; } /**===Buttons=======================*/ $(".keyboard").click(function(evt) { // FIX evt.stopPropagation(); $("#txtarea").focus(); var mykeyID = evt.target.id; var character = $(evt.target).text(); switch (mykeyID) { case "tab": //$("#txtarea").focus(); TAB(); break; case "space": SPACE(); break; case "bkSp": BACKSPACE(); break; case "left": LEFT(); //$("#txtarea").focus(); break; case "right": RIGHT(); //$("#txtarea").focus(); break; case "down": DOWN(); //$("#txtarea").focus(); break; case "up": UP(); //$("#txtarea").focus(); break; case "home": HOME(); //$("#txtarea").focus(); break; case "end": END(); //$("#txtarea").focus(); break; default: character = e.value = e.value.substr(0, e.selectionStart) + character + e.value.substr(e.selectionEnd, e.value.length); //e.selectionStart = 0; //e.selectionEnd = 0; $("#txtarea").val(character); break; } }); }); 
 #txtarea { display: block; padding: 5px; width: 200px; height: 100px; font: 1em, Verdana, Sans-Serif; background: #fff; border: 1px solid #486787; margin-left: 40px; } #kbdFrame { float: left; } ul li { white-space: nowrap; overflow: hidden; list-style-type: none; display: inline-block; border: 1px solid #111db3; margin: 2px; color: #000; border-radius: 5px; box-sizing: border-box; text-align: center; overflow: hidden; cursor: pointer; font-family: arial, sans-serif; font-size: 15px; width: 45px; height: 45px; line-height: 45px; } #left, #up, #right, #down { color: red; } 
 <script src="https://code.jquery.com/jquery-1.12.1.min.js"></script> <textarea type="text" name="txtarea" id="txtarea">Tab works fine. The backapace works fine. So do the end, home and space buttons. the LEFT and RIGHT buttons keep jumping TWO characters. Please help.</textarea> <div class="" id="kbdFrame"> <ul class="keyboard" id=""> <ul id="rOne"> <li class="key" id="tab">Tab</li> <li class="key" id="up">Up</li> <li class="key" id="bkSp">&larr;</li> </ul> <ul class="keyboard" id="rSix"> <li class="key" id="left">Left</li> <li class="key" id="home">Home</li> <li class="key" id="right">Right</li> </ul> <ul class="keyboard kbdR7" id="rSeven"> <li class="key" id="space">Space</li> <li class="key" id="down">Down</li> <li class="key" id="end">End</li> </ul> </ul> </div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM