JSFiddle - React, Tailwind, and code Playground
HTML
<div id="p" contenteditable="true" class='input'>I like this thing</div>
CSS
div.input{ margin:10px; height:1.5em; padding:10px; border:3px solid #CCC; outline:none; position:relative; }
textarea{ color:transparent; position:absolute; top:0; left:0; bottom:0; right:0; border:0; padding:10px; outline:none; }
.exceeds{ color:#CCC; }
small{ padding:10px; font-size:12px; color:blue; }
JavaScript
$('div').on('focus', function(){
var that = this;
$(that).data('lastValue', $(that).text());
// USER WRITES SOMETHING
$(document)
.on('keypress', function(e){
setTimeout(function(){
validateInput(that, e.which);
},0);
}).on('keydown', function(e){
//console.log(e.which);
if( e.which == 8 ){
validateInput(that, e.which);
}
}).on('paste', function(e){
setTimeout(function(){
validateInput(that, e.which);
},0);
});
});
function validateInput(el, key){
var s = $(el).text();
var normalized = $.trim(s.replace(/\s+/g, ' '));
var numOfCharsRemoved = s.length - normalized.length;
var caretPos = selection.save(el);
caretPos.start -= numOfCharsRemoved;
caretPos.end -= numOfCharsRemoved;
// if no change
if( normalized == $(el).data('lastValue') )
return false;
var newValue = wordsLimiter(s);
// TEXT IS PARSED AND HTML IS CHANGED ACCORDINGLY
el.innerHTML = newValue;
$(el).data('lastValue', $(el).text());
// NOW NEED TO RESTORE CARET POSITION (REMEMBER - HTML HAS CHANGED)
selection.restore(el, caretPos);
}
// stop listening to keypresses
$('div').on('blur', function(){
$(document).off('keyup keydown keypress paste');
});
// validate words and returned parsed result
function wordsLimiter(s){
s = $.trim(s.replace(/\s+/g, ' '));
var maxWords = 5,
splitted = s.split(' '),
output = splitted.slice(0,maxWords).join(' '),
exceededWordsArr = splitted.slice(maxWords);
if( exceededWordsArr.length ){
output += '<span class="exceeds"> ' + exceededWordsArr.join(" ") + '</span>';
}
return output;
}
//-------- SELECTION METHODS --------//
var selection = {
save : function(containerEl) {
var charIndex = 0, start = 0, end = 0, foundStart = false, stop = {},
...