javascript - Get the offset position of the caret in a textarea in pixels -


this question has answer here:

in project i'm trying offset position of caret in textarea in pixels. can done?

before asking here, have gone through many links, tim down's, couldn't find solution works in ie8+, chrome , firefox. seems tim down working on this.

some other links have found have many issues not finding top offset of caret position.

i trying offset position of caret because want show auto-complete suggestion box inside textarea positioning based on offset position of caret.

ps: can't use contenteditable div because have written lots of code related textarea.

here's approach using rangyinputs, rangy , jquery.

it copies whole text inside textarea div of same size. have set css ensure in every browser, textarea , div wrap content in same way.

when textarea clicked, read out @ character index caret positioned, insert caret span @ same index inside div. doing ended having issue caret span jumping previous line if user clicked @ start of line. fix check if previous character space (which allow wrap occur), if true, wrap in span, , wrap next word (the 1 directly after caret position) in span. compare top values between these 2 span's, if differ, there wrapping going on, assume top , left value of #nextword span equivalent caret position.

this approach can still improved upon, i'm sure haven't thought of possibly go wrong, , if have, haven't bothered implementing fix of them don't have time @ moment, number of things need at:

  • it doesn't yet handle hard returns inserted enter (fixed)
  • positioning breaks when entering multiple spaces in row (fixed)
  • i think hyphens allow content wrap occur well..

currently works same way across browsers here on windows 8 latest versions of chrome, firefox, ie , safari. testing has not been rigorous though.

here's jsfiddle.

i hope you, @ least might give ideas build on.

some features:

  • i have included ul positioned in right spot, , fixed firefox issue textarea selection not re-set original spot after dom manipulations.

  • i have added ie7 - ie9 support , fixed multiple word selection issue pointed out in comments.

  • i have added support hard returns inserted enter , multiple spaces in row.

  • i have fixed issue default behaviour ctrl+shift+left arrow text selection method.

javascript

function gettextareaxandy() {      // don't if key pressed left arrow     if (e.which == 37) return;           // save selection start     var selection = $(this).getselection();     var index = selection.start;      // copy text div     $(this).blur();     $("div").text($(this).val());      // current character     $(this).setselection(index, index + 1);     currentcharacter = $(this).getselection().text;      // previous character     $(this).setselection(index - 1, index)     previouscharacter = $(this).getselection().text;      var start, endchar;     var end = 0;     var range = rangy.createrange();      // if current or previous character space or line break, find next word , wrap in span     var linebreak = previouscharacter.match(/(\r\n|\n|\r)/gm) == undefined ? false : true;      if (previouscharacter == ' ' || currentcharacter == ' ' || linebreak) {         = index + 1; // start @ end of current space                 while (endchar != ' ' && end < $(this).val().length) {             i++;             $(this).setselection(i, + 1)             var sel = $(this).getselection();             endchar = sel.text;             end = sel.start;         }          range.setstart($("div")[0].childnodes[0], index);         range.setend($("div")[0].childnodes[0], end);         var nextword = range.tohtml();         range.deletecontents();         var position = $("<span id='nextword'>" + nextword + "</span>")[0];         range.insertnode(position);         var nextwordtop = $("#nextword").position().top;     }      // insert `#caret` @ position of caret     range.setstart($("div")[0].childnodes[0], index);     var caret = $("<span id='caret'></span>")[0];     range.insertnode(caret);     var carettop = $("#caret").position().top;      // if preceding character space, wrap in span     if (previouscharacter == ' ') {         range.setstart($("div")[0].childnodes[0], index - 1);         range.setend($("div")[0].childnodes[0], index);         var prevchar = $("<span id='prevchar'></span>")[0];         range.insertnode(prevchar);         var prevchartop = $("#prevchar").position().top;     }      // set textarea selection selection start     $(this).focus();     $(this).setselection(index, selection.end);      // if top value of previous character span not equal top value of next word,     // there must have been wrapping going on, previous character space, wrapping     // have occured after space, safe assume left , top value of `#nextword`     // indicate caret position     if (prevchartop != undefined && prevchartop != nextwordtop) {         $("label").text('x: ' + $("#nextword").position().left + 'px, y: ' + $("#nextword").position().top);         $('ul').css('left', ($("#nextword").position().left) + 'px');         $('ul').css('top', ($("#nextword").position().top + 13) + 'px');     }     // if not, there no wrapping, can take left , top value `#caret`         else {         $("label").text('x: ' + $("#caret").position().left + 'px, y: ' + $("#caret").position().top);         $('ul').css('left', ($("#caret").position().left) + 'px');         $('ul').css('top', ($("#caret").position().top + 14) + 'px');     }      $('ul').css('display', 'block'); }  $("textarea").click(gettextareaxandy); $("textarea").keyup(gettextareaxandy); 

html

<div></div> <textarea>lorem ipsum dummy text of printing , typesetting industry. lorem ipsum has been industry's standard dummy text ever since 1500s, when unknown printer took galley of type , scrambled make type specimen book.</textarea> <label></label> <ul>     <li>why don't type this..</li> </ul> 

css

body {     font-family: verdana;     font-size: 12px;     line-height: 14px; } textarea, div {     font-family: verdana;     font-size: 12px;     line-height: 14px;     width: 300px;     display: block;     overflow: hidden;     border: 1px solid black;     padding: 0;     margin: 0;     resize: none;     min-height: 300px;     position: absolute;     -moz-box-sizing: border-box;     white-space: pre-wrap; } span {     display: inline-block;     height: 14px;     position: relative; } span#caret {     display: inline; } label {     display: block;     margin-left: 320px; } ul {     padding: 0px;     margin: 9px;     position: absolute;     z-index: 999;     border: 1px solid #000;     background-color: #fff;     list-style-type:none;     display: none; } @media screen , (-webkit-min-device-pixel-ratio:0) {     span {         white-space: pre-wrap;     } } div {     /* firefox wrapping fix */     -moz-padding-end: 1.5px;     -moz-padding-start: 1.5px;     /* ie8/ie9 wrapping fix */     padding-right: 5px\0/;     width: 295px\0/; } span#caret {     display: inline-block\0/; } 

Popular posts from this blog

How to calculate SNR of signals in MATLAB? -

c# - Attempting to upload to FTP: System.Net.WebException: System error -

ios - UISlider customization: how to properly add shadow to custom knob image -