1

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?

Nadroev
  • 363
  • 1
  • 11
  • Why don't you change the value directly? I mean instead of mouse clicking the textarea. – orabis Jan 04 '18 at 07:44
  • @orabis You mean edit the clone directly and apply the changes to the original instead of swapping them? Because the undo/redo functionality can't be linked between them. I have to edit the same field every time for it to work properly. – Nadroev Jan 04 '18 at 07:53

2 Answers2

1

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>
Louys Patrice Bessette
  • 33,375
  • 6
  • 36
  • 64
0

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:

Aminadav Glickshtein
  • 23,232
  • 12
  • 77
  • 117
  • I marked your answer as correct since it answers my question, though I forgot that in my case the text areas are actually `
    `s with editable contents.
    – Nadroev Jan 04 '18 at 08:10