Search code examples
jquerycaretcapitalizationgetcaretpos

Get caret position in input to capitalize words on keyup while being able to edit the content


I decided to open a new question because I was trying to capitalize the first letter of words with 4 or more letters and with the exception of a few key words and I have this working code for that: http://jsfiddle.net/Q2tFx/11/

$.fn.capitalize = function () {
 var wordsToIgnore = ["to", "and", "the", "it", "or", "that", "this"],
    minLength = 3;

  function getWords(str) {
    return str.match(/\S+\s*/g);
  }
  this.each(function () {
    var words = getWords(this.value);
    $.each(words, function (i, word) {
      // only continue if word is not in ignore list
      if (wordsToIgnore.indexOf($.trim(word).toLowerCase()) == -1 && $.trim(word).length > minLength) {
        words[i] = words[i].charAt(0).toUpperCase() + words[i].slice(1);
      }
    });
    this.value = words.join("");
  });
};

$('.title').on('keyup', function () {
  $(this).capitalize();
}).capitalize();

But I have a problem while running the function on "keyup". I can't edit something in the middle of the input without getting the cursor at the end of the input. And I also can't "select all".

I know there are solutions to get the caret position and take care of things like this, but I really don't know how to integrate them to my code.

Any idea on how could I do this?


Solution

  • You could do this, using two functions, from here: http://blog.vishalon.net/index.php/javascript-getting-and-setting-caret-position-in-textarea

    See working jsfiddle: http://jsfiddle.net/Q2tFx/14/

    $.fn.capitalize = function (e) {
      if(e.ctrlKey) return false;
      var wordsToIgnore = ["to", "and", "the", "it", "or", "that", "this"],
        minLength = 3;
    
      function getWords(str) {
        return str.match(/\S+\s*/g);
      }
      this.each(function () {
        var words = getWords(this.value);
        $.each(words, function (i, word) {
          // only continue if word is not in ignore list
          if (wordsToIgnore.indexOf($.trim(word).toLowerCase()) == -1 && $.trim(word).length > minLength) {
            words[i] = words[i].charAt(0).toUpperCase() + words[i].slice(1);
          }
        });
        var pos = getCaretPosition(this);
        this.value = words.join("");
        setCaretPosition(this, pos);
      });
    };
    
    $('.title').on('keyup', function (e) {
      var e = window.event || evt;
      if( e.keyCode == 17 || e.which == 17) return false;
      $(this).capitalize(e);
    }).capitalize();
    
    
    function getCaretPosition (ctrl) {
        var CaretPos = 0;   // IE Support
        if (document.selection) {
        ctrl.focus ();
            var Sel = document.selection.createRange ();
            Sel.moveStart ('character', -ctrl.value.length);
            CaretPos = Sel.text.length;
        }
        // Firefox support
        else if (ctrl.selectionStart || ctrl.selectionStart == '0')
            CaretPos = ctrl.selectionStart;
        return (CaretPos);
    }
    function setCaretPosition(ctrl, pos){
        if(ctrl.setSelectionRange)
        {
            ctrl.focus();
            ctrl.setSelectionRange(pos,pos);
        }
        else if (ctrl.createTextRange) {
            var range = ctrl.createTextRange();
            range.collapse(true);
            range.moveEnd('character', pos);
            range.moveStart('character', pos);
            range.select();
        }
    }
    

    NOTE

    You should incorporate this two functions in your capitalize function scope