2

I have a textarea field and I want the user to be able to enter not more than 3 lines.

Is that possible?

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
AnApprentice
  • 108,152
  • 195
  • 629
  • 1,012

2 Answers2

3

Fiddle: http://jsfiddle.net/nvLBZ/1/

I have just (2 hours) created a script which always restricts the height of the text-area to 3 lines.

  1. The largest possible width of a character is calculated for the specific textarea (if not already calculated earlier).
  2. The minimum words per line are calculated.
  3. The textarea is cloned, to test whether it's necessary to continue with the function. When the input is valid, the function returns without interrupting the user.

  4. Otherwise, the cloned textarea is used as a reference, and the user's textarea is erased. The user's textarea is also temporary invisible, for performance reasons.

  5. The textarea gets filled using an efficient method: Blocks which are known to be smaller than the textarea's width are added into the textarea.
  6. When the added blocks exceed the maximum size, the last characters are individually removed, until the maximum line limit has finally reached.
  7. The defaults are restored.

Code below, the code is implemented at the bottom ($(document).ready(...)).

(function(){        
    var wordWidthMappers = {};
    function checkHeight(textarea, maxLines){
        if(!(textarea instanceof $)) return; /*JQuery is required*/
        if(isNaN(maxLines) || !isFinite(maxLines) || maxLines == 0) return;
        var areaWidth = textarea.width();
        var oldHeight = textarea.css("height");
        var oldOverflow = textarea.css("overflow-y");
        var lineHeight = parseFloat(textarea.css("line-height"));
        var maxTxtHeight = maxLines*lineHeight + "px";

        /*Calculations for an efficient determination*/
        var fontstyles = "font-size:"+textarea.css("font-size");
        fontstyles += ";font-family:"+textarea.css("font-family");
        fontstyles += ";font-weight:"+textarea.css("font-weight");
        fontstyles += ";font-style:"+textarea.css("font-style");
        fontstyles += ";font-variant:"+textarea.css("font-variant");
        var wordWidth = wordWidthMappers[fontstyles];
        if(!wordWidth){
            var span = document.createElement("span");
            span.style.cssText = fontstyles+";display:inline;width:auto;min-width:0;padding:0;margin:0;border:none;";
            span.innerHTML = "W"; //Widest character
            document.body.appendChild(span);
            wordWidth = wordWidthMappers[fontstyles] = $(span).width();
            document.body.removeChild(span);
        }

        textarea = textarea[0];
        var temparea = textarea.cloneNode(false);
        temparea.style.visibility = "hidden";
        temparea.style.height = maxTxtHeight;
        temparea.value = textarea.value;
        document.body.appendChild(temparea);
        /*Math.round is necessary, to deal with browser-specific interpretations
          of height*/
        if(Math.round(temparea.scrollHeight/lineHeight) > maxLines){
            textarea.value = "";
            textarea.style.visibility = "hidden";
            if(oldOverflow != "scroll") textarea.style.overflowY = "hidden";
            textarea.style.height = maxTxtHeight;
            var i = 0;
            var textlen = temparea.value.length;
            var chars_per_line = Math.floor(areaWidth/wordWidth);
            while(i <= textlen){
                var curLines = Math.round(textarea.scrollHeight/lineHeight);
                if(curLines <= maxLines){
                    var str_to_add = temparea.value.substring(i, i+chars_per_line);
                    var nextLn = str_to_add.indexOf("\n");
                    if(nextLn > 0) str_to_add = str_to_add.substring(0, nextLn);
                    else if(nextLn == 0) str_to_add = "\n";
                    i += str_to_add.length;
                    textarea.value += str_to_add;
                } else if(curLines > maxLines){
                    textarea.value = textarea.value.substring(0, textarea.value.length-1);
                    i--;
                    if(Math.round(textarea.scrollHeight/lineHeight) <= maxLines) break;
                }
            }
            textarea.style.visibility = "visible";
            textarea.style.height = oldHeight;
            textarea.style.overflowY = oldOverflow;
        }
        temparea.parentNode.removeChild(temparea);
    }

    $(document).ready(function(){/* Add checker to the document */
        var tovalidate = $("#myTextarea");
        tovalidate.keyup(function(){
            /*Add keyup event handler. Optionally: onchange*/
            checkHeight(tovalidate, 3);
        });
    });
})();
Rob W
  • 341,306
  • 83
  • 791
  • 678
0

Possible? Maybe.

How do you measure a line? Do you include word wrap? If so, then you're not going to be able to do so reliably.

If you only count line breaks as a 'line' then you could always add a keypress event to the textarea and check the number of breaks in the area and not allow more than three.

Justin Niessner
  • 242,243
  • 40
  • 408
  • 536
  • unfortunately with this method (of counting how many characters make three lines) will yield inconsistent results because textboxes down't use a monospace font (padded m's will be longer than padded i's). Also you have the issue where the user enters a[newline]b[newline]c[newline]d[newline]. – Joseph Marikle Sep 22 '11 at 18:09
  • @Joseph - You're right. I updated. I assumed word wrap would count, etc. – Justin Niessner Sep 22 '11 at 18:12