Obter a posição atual do cursor em um Textarea.

Recuperar a posição atual do cursor, ou mesmo uma seleção de texto, dentro de um textarea é mais fácil do que você pensa.

É possível deduzir esse valor (da posição do cursor e do texto selecionado) das propriedades selectionStart e selectionEnd do elemento. Esses valores (início e fim) fornecem sempre um valor inteiro com o índice do texto selecionado.

Caso nenhum texto seja selecionado, esses valores (início e fim) serão os mesmos, o que significa que são equivalentes à posição do cursor no elemento.

Sobre as propriedades utilizadas.

selectionStart =>return integer
Obter ou definir o início da parte selecionada do texto. Use em conjunto com a propriedade selectionEnd. O valor especifica o índice do primeiro caractere selecionado.

selectionEnd => return integer
Obter ou definir o final da parte selecionada do texto. Use em conjunto com a propriedade selectionStart. O valor especifica o índice do caractere após a seleção.

Caso nenhum texto seja selecionado, esses valores (início e fim) serão os mesmos, o que significa que são equivalentes à posição do cursor no elemento.

Para deixar mais simples, montei um exemplo pratico usando Bootstrap.

Explicando o exemplo.

O primeiro código é um HTML completo. Foi montado com os elementos necessários para deixar o exemplo limpo e fácil de entender.

Contem um textarea que vai ter seu conteúdo analisado e exibido no espaço reservado abaixo. Não é necessário nenhuma ação adicional do usuário, somente colocar o texto na área destinada.

Programei a ação para ser utilizada todas as vezes que uma tecla for acionada ou quando houver um clique do mouse.

Segue o código (sample.html):

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
        <title>Textarea Text Analyser</title>
        <!-- Bootstrap core CSS -->
        <link href="http://leandrolisura.com.br/wp-content/uploads/2017/11/bootstrap.min_.css   " rel="stylesheet">
        <style type="text/css">
            body {
                padding-top: 50px;
            }
            .starter-template {
                padding: 40px 15px;
                text-align: center;
            }
        </style>
    </head>
    <body>
        <nav class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <a class="navbar-brand" href="#">Leandro Lisura</a>
                </div>
                <!--/.nav-collapse -->
            </div>
        </nav>
        <div class="container">
            <div class="page-header">
                <h3>Textarea Text Analyser</h3>
            </div>
            <div class="row" style="margin-top:10px;" >
                <div class="form-group">
                    <div class="col-md-12">
                        <textarea class="form-control" rows="10" style="font-family: monospace; white-space: nowrap;"></textarea>
                    </div>
                </div>
            </div>
            <div class="row" style="margin-top:10px;" >
                <div class="form-group">
                    <div class="col-md-12">
                        <pre id="line_information"></pre>
                    </div>
                </div>
            </div>
            <hr />
        </div>
        <!-- /.container -->
        <!-- Bootstrap core JavaScript -->
        <!-- Placed at the end of the document so the pages load faster -->
        <script src="http://leandrolisura.com.br/wp-content/uploads/2017/11/jquery.min_.js"></script>
        <script src="http://leandrolisura.com.br/wp-content/uploads/2017/11/bootstrap.min_.js"></script>
        <script src="cursor.functions.js"></script>
        <script type="text/javascript">
            $(document).ready(function () {
                // => Analyze text after every new letter
                $('textarea').keyup(function (element) {
                    check_text_position(element);
                });
                // => Analyze text after mouse click
                $('textarea').mouseup(function (element) {
                    check_text_position(element);
                });
            });

            /**
             * This function makes all the line analysis
             */
            function check_text_position(element) {

                var text = $(element.currentTarget).val();
                var lines = text.split("\n");
                var cursor_position = $(element.currentTarget).getCursorPosition();
                var cursor_election_start = $(element.currentTarget).getSelectionStart();
                var cursor_election_end = $(element.currentTarget).getSelectionEnd();

                var total_size = 0;
                user_line = 0;
                $.each(lines, function (key, value) {
                    var line_number = key;
                    var line_size = value.length;
                    if (key != 0) {
                        total_size = total_size + line_size + 1; // => add break line
                    } else {
                        total_size = total_size + line_size; // => in the end of first line does not have to count break line
                    }
                    if (cursor_position <= total_size) { // => if true, the cursor is on this line
                        user_line = line_number + 1;
                        select_cursor_begin = cursor_election_start - total_size + line_size + 1;
                        select_cursor_end = cursor_election_end - total_size + line_size;
                        select_cursor_total = select_cursor_end - select_cursor_begin + 1;
                        return false; // => breaks the each jquey function
                    }
                });
                var message_selection = '';
                if (cursor_election_start == cursor_election_end) { // => if starts iquals ends, the user did not select any text.
                    message_selection = 'Cursor at position: ' + select_cursor_begin;
                } else {
                    message_selection = "You've selected text (" + select_cursor_begin + " to " + select_cursor_end + ") in a total of: " + select_cursor_total;
                }
                $('#line_information').html('Line:' + user_line + ' - ' + message_selection);
            }

        </script>
    </body>
</html>

Para as funções getCursorPosition, getSelectionStart e getSelectionEnd montei um arquivo Javascrit separado que adicionei no exemplo acima.

Sem este arquivos (ou funções) o algoritmo não vai funcionar. Estas funções foram montadas de modo a ser usadas como funções jQuery, mas podem ser adaptadas facilmente para outro tipo de uso.

Segue o código (cursor.functions.js):

// => This functions are from 
// => https://www.sitepoint.com/6-jquery-cursor-functions/

jQuery.fn.getSelectionStart = function () {
    if (this.lengh == 0) {
        return -1;
    }
    input = this[0];
    var pos = input.value.length;
    if (input.createTextRange) {
        var r = document.selection.createRange().duplicate();
        r.moveEnd('character', input.value.length);
        if (r.text == '') {
            pos = input.value.length;
        }
        pos = input.value.lastIndexOf(r.text);
    } else if (typeof (input.selectionStart) != "undefined") {
        pos = input.selectionStart;
    }
    return pos;
};

jQuery.fn.getSelectionEnd = function () {
    if (this.lengh == 0) {
        return -1;
    }
    input = this[0];
    var pos = input.value.length;
    if (input.createTextRange) {
        var r = document.selection.createRange().duplicate();
        r.moveStart('character', -input.value.length);
        if (r.text == '') {
            pos = input.value.length;
        }
        pos = input.value.lastIndexOf(r.text);
    } else if (typeof (input.selectionEnd) != "undefined") {
        pos = input.selectionEnd;
    }
    return pos;
};

jQuery.fn.getSelection = function () {
    if (this.lengh == 0) {
        return -1;
    }
    var s = $(this).getSelectionStart();
    var e = $(this).getSelectionEnd();
    return this[0].value.substring(s, e);
};

jQuery.fn.getCursorPosition = function () {
    if (this.lengh == 0)
        return -1;
    return $(this).getSelectionStart();
};

Acredito que desta maneira ficou muito simples de usar e possivelmente adaptar estas funções em qualquer projeto.

Qualquer dúvida ou dicas, entre em contato: leandrolt@gmail.com

Leave a Reply

Your email address will not be published. Required fields are marked *