Search code examples
javascriptknockout.jsredactor

How to limit number of lines in Textarea (Redactor)?


I am currently having difficulty getting the Enter key to stop creating new lines in my textarea after the maximum number of rows has been reached. The number of rows are passed as a parameter in the component that I have made. My textarea is a Redactor editor and the new lines are separated by linebreaks.

I have a computed observable that determines the number of rows based on the number of linebreaks in the text and it is returning the correct value:

self.numberOfRows = ko.computed(function () {
        return self.value().split(/<br>/).length;
    }, this);

In my Redactor settings I have a keydownCallback function that compares the number of rows to the maximum number of rows and should prevent the enter key from creating a new row when the max is reached or exceeded:

keydownCallback: function (e) {
            if (e.keyCode > 48 || e.keyCode === 32) {
                if (self.remainingCharacters() <= 0) {                    
                    e.preventDefault();
                }
            } else if (e.keyCode === 13) {
                if (self.maxRows != null) {
                    if (self.numberOfRows() >= self.maxRows) {
                        e.preventDefault();
                    }
                }
            }
        },

The first part of the callback function limits the number of characters and is working properly, however the enter key still creates new lines. I have also tried "return false;" instead of preventDefault and I've also tried stopPropagation before preventDefault, but no luck. I am not concerned about users pasting values into the textarea, nor am I concerned about word wrap. Suggestions?

Separated callbacks:

        enterCallback: function(e) {
            if (self.maxRows != null) {
                if (self.numberOfRows() >= self.maxRows) {
                    return false;
                }
            }
        },
        keydownCallback: function (e) {
            if (e.keyCode > 48 || e.keyCode === 32) {
                if (self.remainingCharacters() <= 0) {
                    e.preventDefault();
                }
            }
        },

Solution

  • UPDATE

    Had a chance to play around with Redactor and noticed that when I press return, no <br> are inserted and instead, new <p> tags are created. An empty paragraph would contain <p><br></p>. So the actual textarea value is something like:

    <h2>Foo</h2>
    <p>Bar
    </p>
    <p>Buz
    </p>
    

    I put together a minimal proof of concept of how this might be handled

    $('#content').redactor({
        focus: true,
        enterCallback: function(e)
        {
            var lines = this.code.get().split(/\r?\n/g).length;
            console.log(this.code.get(), lines);
            if (lines > 3) { // self.numberOfRows()
                return false;
            }
        },
        keydownCallback: function(e)
        {
            //
        }
    });
    

    I'm not sure though if splitting by new line is more reliable than splitting by closing tags like this.code.get().split(/<\/(p|h[1-6])>/).

    I would update the regex inside the self.numberOfRows function to either split by new lines or closing tags


    ORIGINAL ANSWER

    Have you checked their docs? There seem to be 2 separate callbacks for enter and keyup:

    You can return false in this callback to prevent Redactor from handling Enter/Return key inputs. It allows you to develop custom handlers for this event.

    $('#redactor').redactor({
        callbacks: {
            enter: function(e)
            {
                console.log(this.code.get());
                return false;
            }
        }   
    });
    

    Also if you look at their Limiter plugin, it just returns false:

    if (count >= this.opts.limiter)
    {
        return false;
    }