Caret position

We encourage users to post events happening in the community to the community events group on https://www.drupal.org.
ernestd's picture

While a user is writing content, we must find a means to avoid to interfere with them in every update of the content of the textarea. There are two main issues to solve to achieve this.
a) If a caret of a user is in a concrete position, it should remain in the same one even if new content is inserted before or after it.
b) if a user is writing at the moment it cannot be interrupted whatever the insertion is

The last point is explained in more detail in Stop typing
Here, we will talk about the first one. To solve this point we need to use consistent crossbrosser functions. A possible scenario could be the following:
1. In a specific moment the client gets our caret or selection position and save the data
2. The asynchronous call happens and therefore the content of the text area is updated with new changes (we suppose there is new content from the server)
3. The client gets the length of the new content and add up the value to the data we stored
4. With the updated data the client uses the crossbrowser functions again to set the caret or selection in the same position as before the asynchronous call

See the handleResponse() in the js file to see the steps above

Getting the parameters of the caret position in FF is much easier than in IE which needs some more steps and range duplicates to do the same:

function getCaretPosition()
{
    var textArea = getTextArea();
  var start = 0;
var end = 0;
   // a bit weird but we need the range object to set the caret in setCaretPosition() for IE
        var rangeCopy = null;
 
if(document.getSelection) // FF
{
   start = textArea.selectionStart;
   end = textArea.selectionEnd;
}
else if(document.selection) // IE
{
// The current selection
   var range = document.selection.createRange();
  rangeCopy = range.duplicate();
// Select all text
rangeCopy.moveToElementText(textArea);
// Now move 'dummy' end point to end point of original range
rangeCopy.setEndPoint( 'EndToEnd', range );
  // Now we can calculate start and end points
   start = rangeCopy.text.length - range.text.length;
end = start + range.text.length;
}
return {start: start, end: end, rangeCopy: rangeCopy};
}



// We set the caret position, even in selection cases, with the values returned by getCaretPosition()
function setCaretPosition(start,end,rangeCopy)
{
  var textArea = getTextArea();
  if(document.getSelection) // FF
    {
      // what a pleasure in FF ;)
        textArea.setSelectionRange(start,end); 
   }
  else if(document.selection) // IE
  {
      rangeCopy.collapse(true);
      rangeCopy.moveStart("character",start);
      rangeCopy.moveEnd("character",end-start);
        rangeCopy.select();
    }
}

Possible bug: It seems that if you are not looking at the IE browser in the moment of the update the caret goes whatever position but the right one