Nadroev
Nadroev

Reputation: 363

Can a click at a specific location be simulated on a textarea?

I have two text areas that serve as the headers of two pages, so they need to always have the same content. In order for the undo/redo functionality to work I made it so only one of them has a toolbar and if the clone is selected it quickly swaps places with the original and the original is focused.

$(document.body).on('focus', '#TextEditor .headerofpage.clone', function(e){
    e.preventDefault();
    var editor = $('#TextEditor').find('.headerofpage[id]'),
    eParent = editor.parent(),
    index = editor.prevAll().length,
    thisElem = $(this);
    editor.insertBefore(thisElem);
    thisElem.insertBefore(eParent.children().eq(index));
    editor.trigger('focus');
});

The problem is that the focus places the text cursor at the beginning of the text area. I tried with the following event, but it doesn't work. It works for clicking on elements and triggering their click events, but it doesn't even put focus on text areas.

$(document.body).on('mouseup', '#TextEditor .headerofpage[id]', function(e){
    var x = e.clientX;
    var y = e.clientY;
    document.elementFromPoint(x, y).click();
});

There is a way to place the text cursor at a specific character in a text area, but I need the mouse's location, is it possible?

Upvotes: 1

Views: 728

Answers (2)

Louys Patrice Bessette
Louys Patrice Bessette

Reputation: 33933

From two other answers that I found on SO... I played a little and adapted it to your needs (I think... We'll see!)

So, the other answers references are in the code, one to get the cursor position (I did not modify this one at all) and the other to set the cursor position (I adapted it just a little).

The rest is just about to determine on which editable div the click occured and tie everything toguether in an event handler.

Have fun!

$("div").on("mouseup",function(){

  var that = $(this)[0];
  
  // Get the position
  var pos = getCaretPosition(that);
  //console.log(pos);

  var otherDiv;
  if($(this).attr("id")=="t1"){
    otherDiv = $("#t2")[0];
  }else{
    otherDiv = $("#t1")[0];
  }

  // Set the position
  otherDiv.focus();
  setCaretPosition(otherDiv,pos);
});

// From https://stackoverflow.com/a/6249440/2159528
function setCaretPosition(editableDiv,pos){
  var range = document.createRange();
  var sel = window.getSelection();
  range.setStart(editableDiv.childNodes[0], pos);
  range.collapse(true);
  sel.removeAllRanges();
  sel.addRange(range);
}

// From https://stackoverflow.com/a/3976125/2159528
function getCaretPosition(editableDiv) {
  var caretPos = 0,
      sel, range;
  if (window.getSelection) {
    sel = window.getSelection();
    if (sel.rangeCount) {
      range = sel.getRangeAt(0);
      if (range.commonAncestorContainer.parentNode == editableDiv) {
        caretPos = range.endOffset;
      }
    }
  } else if (document.selection && document.selection.createRange) {
    range = document.selection.createRange();
    if (range.parentElement() == editableDiv) {
      var tempEl = document.createElement("span");
      editableDiv.insertBefore(tempEl, editableDiv.firstChild);
      var tempRange = range.duplicate();
      tempRange.moveToElementText(tempEl);
      tempRange.setEndPoint("EndToEnd", range);
      caretPos = tempRange.text.length;
    }
  }
  return caretPos;
}
div{
  display:inline-block;
  width:40%;
  margin:4%;
  height:12em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="t1" contenteditable=true>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus facilisis nisi sit amet leo fringilla, et volutpat ligula viverra. Nam gravida dapibus consequat. Quisque id turpis justo. Vivamus ultricies, justo ac porttitor accumsan, massa quam pretium elit, non porttitor sem tellus sed est. In ultrices vestibulum diam, nec egestas lacus pellentesque et. Integer faucibus orci ut quam dictum imperdiet. Phasellus eleifend augue sed dapibus elementum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Maecenas dapibus enim quis ante vestibulum iaculis. Aliquam sed sapien vel velit tincidunt molestie. Nunc ac consectetur orci.
</div>
<div id="t2" contenteditable=true>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus facilisis nisi sit amet leo fringilla, et volutpat ligula viverra. Nam gravida dapibus consequat. Quisque id turpis justo. Vivamus ultricies, justo ac porttitor accumsan, massa quam pretium elit, non porttitor sem tellus sed est. In ultrices vestibulum diam, nec egestas lacus pellentesque et. Integer faucibus orci ut quam dictum imperdiet. Phasellus eleifend augue sed dapibus elementum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Maecenas dapibus enim quis ante vestibulum iaculis. Aliquam sed sapien vel velit tincidunt molestie. Nunc ac consectetur orci.
</div>

Upvotes: 1

Aminadav Glickshtein
Aminadav Glickshtein

Reputation: 24590

I recommending you to use this library: textarea-caret-position

Get the top and left coordinates of the caret in a or , in pixels. Useful for textarea autocompletes like GitHub or Twitter, or for single-line autocompletes like the name drop-down in Twitter or Facebook's search or the company dropdown on Google Finance.

I know you need xactly the opposite of what you want, but it is not a problem. You should check for every character what it is the X,Y position of it. Then you should place to cursor to the closest character you found relative to your mouse X,Y event.

This library have only one function:

getCaretCoordinates(element, position) element is the DOM element, either an or textarea

position is an integer indicating the location of the caret. Most often you'll want to pass this.selectionStart or this.selectionEnd. This way, the library isn't opinionated about what the caret is.

The function returns a caret coordinates object of the form {top: , left: , height: }, where:

top and left are the offsets in pixels from the upper-left corner of the element and (or presumably the upper-right, but this hasn't been tested), and height is the height of the caret - useful to calculate the bottom of the caret.

More Info:

Upvotes: 0

Related Questions