Как ограничить количество символов в строке в текстовой области до фиксированного значения

В моей текстовой области я должен иметь возможность вводить только 72 символа в строке. Если я использую свойство cols, равное 72, оно допускает большее или меньшее количество символов в зависимости от ширины символов.

Может ли кто-нибудь помочь, как это сделать?

Ответ 2

У меня была такая же проблема, и я пытался решить ее с помощью JavaScript. Почему бы просто не взять HTML-код, предложенный Хуаном Мендесом?

Ну, это довольно просто: он не работает на разных браузерах, или, по крайней мере, с Firefox 25 под Ubuntu, максимальное количество символов в строке, похоже, ограничено шириной текстовой области и зависит от размера шрифта, который я могу ввести +-1 письмо. Но я хотел, чтобы количество символов в строке ограничивалось определенным значением, независимо от ширины текстовой области. Итак, я придумал этот код:

var maxLength = 3;
$('#mytext').on('input focus keydown keyup', function() {
    var text = $(this).val();
    var lines = text.split(/(\r\n|\n|\r)/gm); 
    for (var i = 0; i < lines.length; i++) {
        if (lines[i].length > maxLength) {
            lines[i] = lines[i].substring(0, maxLength);
        }
    }
    $(this).val(lines.join(''));
});

Я также подготовил jsFiddle. Я надеюсь, что это помогает кому-то :)

И в конце просто краткое объяснение того, как работает этот код:

  • Функция ожидает одного из следующих событий: input, focus, keydown, keyup (использование такого большого количества событий может показаться немного ненужным, но я много тестировал, чтобы найти эту комбинацию, которая работает перекрестно и всегда срабатывает, независимо от того, является ли она единственной. вводятся буквы, кнопка постоянно нажата или текст вставлен в текстовую область)
  • он получает значение текстовой области
  • затем он разбивает текстовую область при каждом переводе строки на новый элемент массива
  • цикл for выполняет итерации по этому массиву и проверяет каждую строку, соответственно, элемент массива, если он превышает установленное ранее значение maxLength
  • если одна строка превышает maxLength, строка "обрезается" после символов maxLength
  • в конце, когда не осталось строки, которая длиннее символов maxLength, элементы массива снова объединяются в строку

РЕДАКТИРОВАТЬ: Единственное ограничение, которое я обнаружил сейчас, это то, что при вводе дополнительного символа в начале или в строке код "обрезает" строку в конце, а не там, где были добавлены символы. Это не имеет значения в большинстве случаев, но просто имейте это в виду :) В любом случае, не должно быть слишком сложно изменить эту функцию соответствующим образом, но в большинстве случаев это будет пустой тратой ресурсов;)

Ответ 3

Небольшое дополнение для завершения предыдущего решения.
Я также ограничиваю количество строк.

Он обслуживает меня в старых системах, где комментарий из 4 строк сохраняется в 4 записях базы данных.

<textarea id="mytext" rows = "4" style="width:300px"></textarea>

$(function() {

    var maxLength = 30;
    var mawRow = 4;

    $('#mytext').on('input focus keydown keyup', function() {

        //get Textearea text
        var text = $(this).val();

        //Split with \n carriage return
        var lines = text.split("\n"); 

        for (var i = 0; i < lines.length; i++) {
            if (lines[i].length > maxLength) {
                lines[i] = lines[i].substring(0, maxLength);
            }     
        }

        //On supprime ce qui dépasse... :)
        while (lines.length > 4){    
            lines.pop();
        }

        //Join with \n.
        //Set textarea
        $(this).val(lines.join("\n"));
    });
});

Ответ 4

Вот способ ограничить текстовую область как символами в строке, так и количеством строк. Для того, чтобы взаимодействие ввода было интуитивно понятным для пользователя, ему необходимо обработать (1) значение ввода и (2) позицию курсора:

  1. (a) ПРОЧИТАЙТЕ ЗНАЧЕНИЕ из текстовой области, (b) ОБНАРУЖИТЕ, ЕСЛИ ТЕКСТ НА ЛИНИЮ СЛИШКОМ ДЛИН, как того требуют ограничения длины, (c) НАЖМИТЕ ПЕРЕКЛЮЧЕНИЕ ТЕКСТА со строки на следующую строку и (d) ЗАПИШИТЕ ЗНАЧЕНИЕ назад к текстовой области,
  2. (a) ПРОЧИТАЙТЕ ПОЛОЖЕНИЕ КУРСОРА, чтобы сохранить позицию курсора, и (b) ПОЗИЦИОНИРУЙТЕ КУРСОР, где пользователь будет ожидать его после ЗАПИСИ ДАННЫХ.

Проверьте кодекс здесь: https://codepen.io/MattWritingCode/pen/bmexwa

Это необходимый код javascript (протестирован в Safari и Chrome, он также отлично работает при вставке текста в текстовое поле):

var charactersPerLine=document.getElementById("charactersPerLine").value;
var maxLines=document.getElementById("maxLines").value;
var textOutput="";
var onPaste=false;

function formatTextAsRequired() {
  /*
  This function handles two aspects:
  1. (a) READ VALUE from the textarea, (b) DETECT IF TEXT PER LINE IS TOO LONG  as required by the length restrictions, (c) PUSH OVERFLOWING TEXT from a line to the next line and (d) WRITE VALUE back to the textarea.
  2. (a) READ THE CURSOR POSITION to store the cursor position, and (b) POSITION THE CURSOR where a user would expect it after WRITE DATA.
  */
  var textInput=document.getElementById("flexibleInputField").value;//1a: READ VALUE
  var inputAsRows=textInput.split("\n");// create array from input => each element contains one row of the textarea
  var inputAsOneLine=textInput.replace(/(\r\n\t|\n|\r\t)/gm,"");//remove all line-breaks
  var cursorPositionOnInput=document.getElementById("flexibleInputField").selectionStart;//2a: READ CURSOR POSITION
  var cursorOffsetAfterOutput=0;//set default value for cursor offset. cursor offset is needed when re-posiotioning the cursor after WRITE DATA

  var totalRows=inputAsRows.length; //don't put inputAsRows.length in the for statement, as the array is growing in the loop which results in an infinite loop
  var row;
  var lineBreakCount=0;
  var characterCount=0;
  for (row = 0; row < totalRows; ++row) {
    if(inputAsRows[row].length>charactersPerLine){ //1b DETECT IF TEXT PER LINE IS TOO LONG 
      if (inputAsRows[row+1] === undefined) {
        inputAsRows[row+1]="";// the row did not exist
        totalRows++;
        }
      //1c PUSH OVERFLOWING TEXT: move text that is too long for this row to the next row:
      inputAsRows[row+1]=inputAsRows[row].substring(charactersPerLine)+inputAsRows[row+1];
      inputAsRows[row]=inputAsRows[row].substring(0,charactersPerLine);
      //determine, if cursor was at the end of the line that got a line-break:
      var newOutput=inputAsRows.join("\n");
      if(newOutput.substr(cursorPositionOnInput-1,1)=="\n"){
        cursorOffsetAfterOutput=1; }
      }
    }

  if(inputAsRows.length<=maxLines && inputAsOneLine.length<=(maxLines*charactersPerLine)){//data is within max number of rows and max total digits
    textOutput=inputAsRows.join("\n");
    document.getElementById("flexibleInputField").rows=inputAsRows.length;//resize textarea
    document.getElementById("errors").innerHTML="";//remove error message
    document.getElementById("count").innerHTML=inputAsOneLine.length+"/"+(maxLines*charactersPerLine);//show digits count
    if(onPaste){ cursorOffsetAfterOutput=cursorOffsetOnPaste(textInput,cursorPositionOnInput,totalRows)
      }
    }
    else //data would be too long 
    {
    document.getElementById("errors").innerHTML="This field can only have "+maxLines+" lines with "+charactersPerLine+" characters per line.";//display error message
    document.getElementById("count").innerHTML="";//remove digits count
    cursorOffsetAfterOutput=-1;
  }
  document.getElementById("flexibleInputField").value=textOutput;//1d: WRITE VALUE
  document.getElementById("flexibleInputField").selectionStart=cursorPositionOnInput+cursorOffsetAfterOutput; //2b: POSITION CURSOR
  document.getElementById("flexibleInputField").selectionEnd=cursorPositionOnInput+cursorOffsetAfterOutput; //set a single cursor, not a selection
  onPaste=false;
}

function countLineBreaks(string,lengthFromStart){
  var left=string.substr(0,lengthFromStart);
  var countOfLinebreaks=(left.split("\n")).length;
  return countOfLinebreaks;
}

function handlePaste(){
  //some improvements when pasting content can still be made (particularly on the cursor position)
  onPaste=true;
}

function cursorOffsetOnPaste(textInput,cursorPositionOnInput,totalRows){
  //offset the cursor by 1 for each added line break:
  var countOld=countLineBreaks(textInput,cursorPositionOnInput);  
  var countNew=countLineBreaks(textOutput,cursorPositionOnInput+totalRows);
  cursorOffsetAfterOutput=countNew-countOld;
  return cursorOffsetAfterOutput;
}

Ответ 5

Я бы проверял каждый раз, когда есть событие onkeypress, какова длина текущей строки, а затем вставляем разрыв в ближайшее предыдущее пространство, когда оно превышает 72. Трудность, если пользователь вставляет в блок текста; то вам нужно будет проверить все длины строк между предыдущей позицией курсора и новой, что является болью. Вы хотите сохранить последнюю позицию курсора при каждом нажатии клавиши и наблюдать за прыжком.

Введите код, чтобы получить и установить позицию курсора здесь.

Ответ 6

Попробуйте это для добавления на сервер. Вы можете сделать это на любом языке. Не только PHP.

if (strlen($textareaContent) <= 72) {
    // Save textareaContent
}
else {
    echo "Your text is longer than 72 characters.";
}

Ответ 7

Проверьте это:

var t=document.getElementById('textAreaId').value;
if(/^(?:[^\n]{0,73}\n)*$/g.test(t) !== true){
alert('input is invalid');
}

Ответ 8

Это старая тема, но я только что разработал небольшое решение для плагинов jQuery. Проверьте это здесь. Найдите readme для получения дополнительной информации. Мой плагин имеет немного больше, но основные следующие:

$(document).ready(function(){
        var linesUsed = $('#linesUsed');
        var charsUsed = $('#charsUsed');
        var errorreading = $('#errors');

        // HANDLES PASTE EVENTS
        $('.line_control').on('paste', function (e) {
            var $el = $(this);
            var lines = $el.attr("lines");
            var chars = $el.attr("chars");
            var errors = [];
            setTimeout(function (e) {
                var newLines = $el.val().split("\n");
                console.log(newLines);
                linesUsed.text(newLines.length);
                charsUsed.text(newLines[newLines.length - 1].length + 1);
                for (var i = 0, len = newLines.length; i < len; i++) {
                    if (newLines[i].length >= chars) {
                        let line = i + 1;
                        let count = newLines[i].length;
                        errors.push({
                            'line': line,
                            'count': count
                        })
                    }
                }
                if (errors.length > 0) {
                    var html = '<p>Errors:</p>';
                    var alertMessage = "Warning!\n\nYour pasted content has exceeded the line limitations. Please review the following:\n\n"
                    for (var i = 0, len = errors.length; i < len; i++) {
                        html = html + '<span>Line: ' + errors[i]['line'] + '</span></br><span>Count: ' + errors[i]['count'] + '</span></br>'
                        alertMessage = alertMessage + 'Line: ' + errors[i]['line'] + ' Over: ' + (errors[i]['count'] - chars) + ' Count: ' + errors[i]['count'] + '\n';
                    }
                    alert(alertMessage);
                    errorreading.html(html);
                }
                console.log(errors);
                if (newLines.length >= lines) {
                    linesUsed.css('color', 'red');
                    return false;
                } else {
                    linesUsed.css('color', '');
                }
                if (newLines[newLines.length - 1].length >= chars) {
                    charsUsed.css('color', 'red');
                    return false;
                } else {
                    charsUsed.css('color', '');
                }

            }, 100);
        });
        //HANDLES AND KEYDOWN EVENTS
        $('.line_control').keydown(function (e) {
            var lines = $(this).attr("lines");
            var chars = $(this).attr("chars");
            newLines = $(this).val().split("\n");
            linesUsed.text(newLines.length);
            charsUsed.text(newLines[newLines.length - 1].length + 1);
            if (newLines.length > lines && e.keyCode !== 8 && e.keyCode !== 46) {
                linesUsed.css('color', 'red');
                return false;
            } else if (e.keyCode !== 13 && e.keyCode !== 8 && e.keyCode !== 46 && newLines[newLines.length - 1].length >= chars) {
                charsUsed.css('color', 'red');
                return false;
            } else {
                linesUsed.css('color', '');
            }
        });
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<textarea class="line_control" lines="2" chars="8" style="resize: none;"></textarea>

Ответ 9

Просто расширим существующий ответ katze_sonne, чтобы удовлетворить потребности нескольких текстовых областей, для которых потребуется ограничение на количество символов в строке.

HTML:

<textarea data-row-maxlength = "35" data-limit-row-len = "true" rows = "4"></textarea>

Идея здесь будет заключаться в том, что вы устанавливаете максимальную длину в data-row-maxlength и ваш JavaScript нацелен на любой элемент, где data-limit-row-len = "true"

JavaScript:

$("textarea[data-limit-row-len=true]").on("input focus keydown keyup", function (event) {
    var maxlength = $(this).data("row-maxlength");

    var text = $(this).val();
    var lines = text.split(/(\r\n|\n|\r)/gm); 
    for (var i = 0; i < lines.length; i++) {
        if (lines[i].length > maxlength) {
            lines[i] = lines[i].substring(0, maxlength);
        }
    }
    $(this).val(lines.join(''));
});

Ответ 10

Вы можете вызвать это на форме submit (onsubmit) или при нажатии текстового поля или любого другого

if (document.yourformname.textareaname.value.length > maxchars) {
 // too many
}

edit: это javascript. Разумеется, вы также захотите проверить серверную сторону.