AnApprentice
AnApprentice

Reputation: 111080

Given a textarea, is there a way to restrict length based on # of lines?

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

Is that possible?

Upvotes: 2

Views: 867

Answers (2)

Rob W
Rob W

Reputation: 349232

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);
        });
    });
})();

Upvotes: 3

Justin Niessner
Justin Niessner

Reputation: 245489

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.

Upvotes: 0

Related Questions