web-dev-qa-db-ja.com

ContentEditable divの文字数を制限する

Webアプリケーションでcontenteditable div要素を使用しています。エリアで許可される文字数を制限するソリューションを考えています。制限に達すると、文字を入力しようとしても何も起こりません。これは私がこれまでに持っているものです:

var content_id = 'editable_div';

//binding keyup/down events on the contenteditable div
$('#'+content_id).keyup(function(){ check_charcount(content_id, max); });
$('#'+content_id).keydown(function(){ check_charcount(content_id, max); });

function check_charcount(content_id, max)
{   
    if($('#'+content_id).text().length > max)
    {
        $('#'+content_id).text($('#'+content_id).text().substring(0, max));
    }
}

これにより、文字数は「max」で指定された数に制限されますが、領域のテキストがjquery .text()関数によって設定されると、カーソルは領域の先頭に自動的にリセットされます。したがって、ユーザーが入力し続けると、新しく入力された文字がテキストの先頭に挿入され、テキストの最後の文字が削除されます。ですから、本当に、編集可能な領域のテキストの最後にカーソルを置く方法が必要です。

37
Bill Dami

eventオブジェクトを関数に渡し、最大値に達した場合にe.preventDefault()を呼び出すのはどうですか?

var content_id = 'editable_div';  

max = 10;

//binding keyup/down events on the contenteditable div
$('#'+content_id).keyup(function(e){ check_charcount(content_id, max, e); });
$('#'+content_id).keydown(function(e){ check_charcount(content_id, max, e); });

function check_charcount(content_id, max, e)
{   
    if(e.which != 8 && $('#'+content_id).text().length > max)
    {
       // $('#'+content_id).text($('#'+content_id).text().substring(0, max));
       e.preventDefault();
    }
}

ただし、ユーザーが「削除」などの操作を行えるようにするには、もう少し作業が必要になる場合があります。


編集:

「削除」キーのサポートが追加されました。


編集2:

また、おそらくkeyupハンドラーを取り除くことができます。 keydownで十分です。

45
user113716

これを達成する簡単な方法:

<div onkeypress="return (this.innerText.length <= 256)" contenteditable="true">
20
Bala Velayutham

まず、この種のことはユーザーを苛立たせます。代わりにStackOverflowのコメントフィールドに似た操作を行うことをお勧めします。また、多すぎるか少なすぎるか、および長さが無効なコメントの送信を拒否します。

第二に、本当にテキストの長さを制限する必要がある場合、コンテンツが長すぎる場合は、キーストロークごとに_<div>_のコンテンツ全体を置換することは不必要に高価であり、低速のマシンではエディターが応答しなくなります。 keypressイベントを処理し、イベントでpreventDefault()を使用して(またはIEでイベントのreturnValuetrueに設定して、文字が挿入されないようにすることをお勧めします。 、attachEvent)を使用していると仮定します。これにより、ユーザーがテキストを貼り付けることが妨げられることはないため、pasteイベント(OperaまたはFirefox <3には存在しない)を処理する必要があります。事前に貼り付けられているコンテンツにアクセスできないため、貼り付けによって文字数制限を超えてしまうかどうかを知る方法がありません。したがって、貼り付けの直後にタイマーを設定して長さを再度チェックする必要があります。

17
Tim Down

次のソリューションでは、コントロールキー(印刷できない文字に対応)も考慮します。

//Maximum number of characters
var max = 200;

$('#editable_div').keydown(function(e) {
    var keycode = e.keyCode;

    //List of keycodes of printable characters from:
    //http://stackoverflow.com/questions/12467240/determine-if-javascript-e-keycode-is-a-printable-non-control-character
    var printable = 
        (keycode > 47 && keycode < 58)   || // number keys
        keycode == 32 || keycode == 13   || // spacebar & return key(s) (if you want to allow carriage returns)
        (keycode > 64 && keycode < 91)   || // letter keys
        (keycode > 95 && keycode < 112)  || // numpad keys
        (keycode > 185 && keycode < 193) || // ;=,-./` (in order)
        (keycode > 218 && keycode < 223);   // [\]' (in order)

    if (printable) {
        //Based on the Bala Velayutham's answer
        return $(this).text().length <= max; 
    }
});
4
Vito Gentile

これは、jQueryバインディングで行った方法であり、プロパティdata-input-lengthをコンテンツの編集可能な要素に追加するだけで簡単になります。ドキュメントの任意の場所にjavascriptコードを追加するだけです。

$(document).ready(function(){
        // Excempt keys(arrows, del, backspace, home, end);
        var excempt = [37,38,39,40,46,8,36,35];
        // Loop through every editiable thing
        $("[contenteditable='true']").each(function(index,elem) {
            var $elem = $(elem);
            // Check for a property called data-input-length="value" (<div contenteditiable="true" data-input-length="100">)
            var length = $elem.data('input-length');
            // Validation of value
            if(!isNaN(length)) {
                // Register keydown handler
                $elem.on('keydown',function(evt){
                        // If the key isn't excempt AND the text is longer than length stop the action.
                    if(excempt.indexOf(evt.which) === -1 && $elem.text().length > length) {
                       evt.preventDefault();
                       return false;
                    }
                });
            }
        });
});
div {
  background-color:#eee;
  border: 1px solid black;
  margin:5px;
  width:300px;
  height:100px;
  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div contenteditable="true" data-input-length="100">
You can type a 100 characters here
</div>
<div contenteditable="true" data-input-length="150">
You can type a 150 characters here
</div>
<div contenteditable="true" data-input-length="10">
You can type a 10 characters here
</div>
4
Tschallacka

これは、この最も一般化されたフォームを行うための最良の方法であり、私にとっては素晴らしい仕事です!

<div contenteditable="true" name="choice1" class="textfield" max="255"></div>
    $('.textfield').on("keypress paste", function (e) {
        if (this.innerHTML.length >= this.getAttribute("max")) {
            e.preventDefault();
            return false;
        }
    });
4
VizardCrawler
$("[contenteditable=true]").keydown(function(e) {
    var max = $(this).attr("maxlength");
    if (e.which != 8 && $(this).text().length > max) {
        e.preventDefault();
    }
});
1
Yuval Perelman

複数のコンテンツ編集可能なフィールドでは機能しない@ user113716の回答のより一般化されたリビジョン(特定のIDに一致するすべての要素の合計文字数をカウントするため、最大文字数しか入力できませんtotal onページ)。

このソリューションでは、一般的なクラスを使用でき、各コンテンツ編集可能フィールドの文字数を個別に制限できます。

html:

<div contenteditable="true" name="choice1" class="textfield"></div>

そしてJavaScript:

MAX_TEXTINPUT = 10;
TEXTFIELD_CLASS = "textfield"

$(document).ready(function() {

    //binding keyup/down events on the contenteditable div
    $('.'+TEXTFIELD_CLASS).keydown(function(e){ check_charcount(TEXTFIELD_CLASS, MAX_TEXTINPUT, e); });

})

function check_charcount(inputclass, max, e) {   
    var focused = $(document.activeElement)

    if(focused.hasClass(inputclass) && e.which != 8 && $(focused).text().length >= max)
    {
        e.preventDefault();
    }
}
0
Wes Modes

@ user113716の回答の別のバージョン。 「貼り付け」イベント、およびCTRL + Aなどのテキストホットキーをサポートします。

$('#'+content_id).on('keydown paste', function (e) { maxLimitForContenteditableDiv(e, 140) });

function maxLimitForContenteditableDiv(e, limit) {
    var allowedKeys = false;

    if (e.type === 'keydown') {
        allowedKeys = (
            e.which === 8 ||  /* BACKSPACE */
            e.which === 35 || /* END */
            e.which === 36 || /* HOME */
            e.which === 37 || /* LEFT */
            e.which === 38 || /* UP */
            e.which === 39 || /* RIGHT*/
            e.which === 40 || /* DOWN */
            e.which === 46 || /* DEL*/
            e.ctrlKey === true && e.which === 65 || /* CTRL + A */
            e.ctrlKey === true && e.which === 88 || /* CTRL + X */
            e.ctrlKey === true && e.which === 67 || /* CTRL + C */
            e.ctrlKey === true && e.which === 86 || /* CTRL + V */
            e.ctrlKey === true && e.which === 90    /* CTRL + Z */
        )
    }

    if (e.type === 'paste') {
        setTimeout(function () {
            $(e.target).text($(e.target).text().slice(0, limit));
        });
    }

    if (!allowedKeys && $(e.target).text().length >= limit) {
        e.preventDefault();
    }
0
vodnycheck
var onKeyPress = function () {
    var keyCode = window.event.keyCode,
        isNumeric = (keyCode > 47 && keyCode < 58),
        isNotEnterKey = !!(window.event.keyCode !== 13);

        (isNotEnterKey) || (this.blur());

        return (isNumeric && this.innerText.length < 3);
};
0
shawndumas

クラスで動作させたい場合。言い換えれば、要素はクラス名を共有することができ、それでも独自の一意のカウントを持つことができます。

var content_id = '.myclass';  

max = 1;
//binding keyup/down events on the contenteditable div
$(content_id).keyup(function(e){ check_charcount(this, max, e); });
$(content_id).keydown(function(e){ check_charcount(this, max, e); });

function check_charcount(elem, max, e){   
    if(e.which != 8 && $(elem).text().length >= max){       
        e.preventDefault();
    }
}
0
Al Serize