disable textarea by height not characters - javascript

So many times we want to limit how much a user can write, but here I have a special sized box that it has to fit in, so I want to disable adding more characters if it would surpass a specific height. here is what I did:
var over;
$('textarea').keypress(function(e){
var key = e.charCode ? e.charCode : e.keyCode ? e.keyCode : 0;
var t = $(this).val();
jQuery('<div/>', {
style: "visibility:hidden",
text: t,
id: "test"
}).appendTo('body');
var h = $('#test').height();
if(h >= 100){
over = true;
}
else{
over = false;
}
if(over){
//code goes here
}
$('#test').remove();
});
I got the limiting code (what goes where I have the "code goes here" comment) from here and it ALMOST works.
There is only one problem:
if somebody copies and pastes, it can place multiple characters and therefore still go over the limit.
How can I fix this issue?
jsfiddle

Another somewhat hacky solution could be to check scroll on key up. If scroll exists, delete the last character while scroll exists:
function restrictScroll(e){
if(e.target.clientHeight<e.target.scrollHeight){
while(e.target.clientHeight<e.target.scrollHeight){
e.target.value = e.target.value.substring(0, e.target.value.length-1);
}
}
};
document.getElementById("textareaid").addEventListener('keyup', restrictScroll);
This would work as you type and if you paste blocks of text. Large text blocks may take a little longer to loop through though. In which case you may want to split on "\n" and remove lines first, then characters.
jsfiddle

If you want your function to fire whenever the text in your field changes, you can bind it to the input and propertychange events, as per this answer:
https://stackoverflow.com/a/5494697/20578
Like this:
$('#descrip').on('input propertychange', function(e){
This will make sure your code fires when e.g. the user pastes in content using the mouse.
As for stopping them from entering content that would go over the limit, I think you have to keep track of what content they've entered yourself, and then revert their last edit if it infringed your criteria.
Note that e.g. Twitter doesn't stop the user from entering more characters if they've gone over the limit - they just tell the user they're over the limit, and tell them when they're back under. That might be the most usable design.

You may try this:
$('#descrip').bind('paste',function(e) {
var el = $(this);
setTimeout(function() {
//Get text after pasting
var text = $(el).val();
//wath yu want to do
}, 100);
};
Jsfiddle
The solution is taken from here and here. It works by binding to the paste event. Since paste event is fired before the text is pasted, you need to use a setTimeout to catch the text after pasting. There is still some rough edges (i.e. if you select text and press backspace, it does not update).
Still, Spudley comment has some valid points, that you may want to consider.
Edit:
Note on the jsfiddle: It allow you to go over the limit when pasting, but once over the limits, you cannot paste (or type) more text until you go under the limit again.
Must be taken into account that, since you are limiting the text length by the size it ocuppies after rendering (wich have it own issues as pointed by Spudley), and not a defined lenth, you can know if a text fits or not, but not know how much of the text is inside the limits, and how much is out of them.
You may consider reseting textbox value to its previous value if pasted text makes imput go over the limit, like in this one.
However, for cutting down the text after pasting so as non-fitting text is left out, but the rest of the pasted text is allowed, you need an entirely different approach. You may try iterating over the text until you find how much of the new text is enough.
By the way, line feeds and seems to cause your original script to behave weirdly.

I've been able to get the program working:
var over = false;
var num = 0;
var valid_entry = "";
$('#descrip').keyup(function(e){
var key = e.charCode ? e.charCode : e.keyCode ? e.keyCode : 0;
var t = $(this).val();
getMaxRow(t,key,this);
});
function getMaxRow(t,key,obj) {
jQuery('<div/>', {
"class": "hide",
text: t,
id: "test"
}).appendTo('body');
var h = $('#test').height();
$('#test').remove();
if(h >= 100){
num += 1;
if(num == 1){
var div = '<div id="message">You have run out of room</div>'
$('body').append(div);
}
over = true;
}
else{
over = false;
valid_entry = t;
if(num >= 1){
$('#message').remove();
num = 0;
}
}
if( over ) {
//Do this for copy and paste event:
while ( over ) {
//Try using a substring here
t = t.substr(0,(t.length-1));
over = getMaxRow(t,key,obj);
}
}
$(obj).val(valid_entry);
return over;
}

Related

How to use jquery to prevent a editable div reach over our restricting length

Let's said I have the following code:
<div id="editing" contenteditable onclick="document.execCommand('selectAll',false,null)">Put text here...</div>
In this case, I want to restrict my user, for example, can only put 200 characters in it (including space), how can I restrict it? I know I might achieve it with jquery but most example on webs checks it when they click a button, and as I redesign my code with this StackOverflow question as base, it checks it when the div is clicked but with that in mind you can't alert user when the types over 200 words.
So how can I continuously checking words user type in a contenteditable div and alert them when they reach the limit?
The input event is supported with contenteditable, then just stop the event if there is too much text like so:
var el = document.getElementById('editing');
var max = 20;
el.addEventListener('input', function(e) {
if (el.innerHTML.length > max) {
el.innerHTML = el.innerHTML.substr(0, max); // just in case
alert('Not allowed more than ' + max + ' characters');
}
});
<div id="editing" contenteditable onclick="document.execCommand('selectAll',false,null)">Put text here...</div>
However, just stay away from contenteditable events. they are bad
Here is simple pure js solution: if anything is there please comment i will update my answer.. :D
function check()
{
// get the HTML value.
var content = document.getElementById('editing').innerHTML;
//Edit : replace spaces from content (ideally you have to figure out how to remove the posible html tags that user might enter)
content = content.replace(/ /g," ");
console.log(content);
// validate value againts limit say 10 or any constant value.
if(content.length > 20)
{
// alert user.
alert('limit reached');
// flush extra characters from end.
document.getElementById('editing').innerHTML = content.slice(0,content.length-1);
return;
}
}
//Edit : if you want remove placeholder from annoying user you can flush it when user gets the focus on it say
function checkPlaceholder()
{
document.getElementById('editing').innerHTML = "";
}
<div id="editing" contenteditable onInput="check();" onfocus="checkPlaceholder();">Put text here...</div>
<div id="editing" contenteditable onkeypress = "if($(this).text().length >= 200) {return false; }"onclick="alert(document.execCommand('selectAll',false,null)">Put text here...</div>
You return false onkeypress when the character count is greater than or equal to 200
// Detect when you add a character to the div.
$('div#editing').on('keydown',function(e) {
// Check if you already have 200 characters (but allow 'backspace' and 'del' keys).
if (e.keyCode != 8 && e.keyCode != 46 && $(this).text().length >= 200) {
alert('The field is limited to 200 characters');
return false; // This will make the new character to be ignored.
}
});

Javascript: Cannot move back in HTML Input

I have a form where a user can enter a URL but I wanted to have it automatically remove spaces.
To do this I have the following jQuery function:
$('#URL').on('change keyup', function() {
var sanitized = $(this).val().replace(' ', '');
$(this).val(sanitized);
});
But the problem with this code is that you cannot use the arrow keys to move in the input. i.e. if I type in http://oogle.com and I want to use arrow keys to fix my spelling mistake, it will automatically keep the cursor on the very last character. On top of this, I cannot use Ctrl+A to select all the text.
Is there a way to have jQuery/Javascript automatically remove spaces while still being able to move around the input or select it all?
Here is my jsFiddle showing my issue.
Use keypress instead of keyup, so only characters are caught. In this case, discard a space if it is pressed.
Also check for a paste event, and use a regular expression to replace all spaces. Change the value within a timeout in order to capture the pasted value:
$('#URL')
.on('keypress', function(e) {
if(e.which === 32) return false;
})
.on('paste', function() {
$self= $(this);
setTimeout(function() {
$self.val($self.val().replace(/\s/g, ''));
});
});
Fiddle
Fiddle
You can:
Record the cursor position
Execute your original code
Then restore the cursor position
Update:
Make sure to change your .replace to .replace(/\ /g, "")
Update 2 (cursor position):
This fixes the cursor position when inserting spaces.
For example copy and pasting the following will now work with any cursor position:
341 10365
34 1 1 03 65
First you need to get the string to the left of the cursor:
var leftString = $(this).val().substring(0, start);
Then you need to count the spaces in that string:
var leftSpaces = (leftString.match(/ /g) || []).length;
Then subtract leftSpaces from the start and end variables.
Javascript
$('#URL').on('change keyup', function() {
// Store cursor position
var start = this.selectionStart;
var end = this.selectionEnd;
// Check for newly inserted spaces
var leftString = $(this).val().substring(0, start);
var leftSpaces = (leftString.match(/ /g) || []).length;
newStart = start - leftSpaces;
newEnd = end - leftSpaces;
// Original Code
var sanitized = $(this).val().replace(/\ /g, "");
$(this).val(sanitized);
// Place cursor in correct position
this.setSelectionRange(newStart, newEnd);
});
Another option would be to add a delay after the keyup event
$('#URL').on('change keyup', function() {
delay(function(){
var sanitized = $('#URL').val().replace(' ', '');
$('#URL').val(sanitized);
}, 1000 );
});
http://jsfiddle.net/xv2e9bLe/
The usual way to adjust user input in a form is done when user finish their input or edit. It's pretty awkward to adjust user input on the fly. So, the onBlur event usually the best event to catch and sanitize a form input.
Based on the answer from adriancarriger, I use the 'blur' event which catch the user input after the user finish the input and do something else.
$('#URL').on('blur', function() {
var start = this.selectionStart,
end = this.selectionEnd;
var sanitized = $(this).val().replace(/\ /g, "");
$(this).val(sanitized);
this.setSelectionRange(start, end);
});
This should work well. If you have a real form submit, you can also catch the user input at onSubmit event of the form as well. Note that onSubmit happens at the form object, not the input object.

In contenteditable how do you add a paragraph after blockquote on Enter key press?

I have the following problem. Once I add a blockquote in contenteditable, by pressing Enter key it moves to a new line and adds another blockquote element. It goes on forever, and I can’t escape the formatting. The desired functionality would be that of the unordered list. When you press the Enter key it adds a new empty <li> element, but if you press Enter again, it escapes the formatting, removes the previously created <li> and adds a <p>.
Check out the demo: http://jsfiddle.net/wa9pM/
One hack I found was to create an empty <p> under the blockquote, before you create a blockquote. But is there a way to break this formatting behaviour with JavaScript? No idea how I would check: if where the cursor is, it’s the end of the line and if it’s a blockquote and on Enter key press, don’t add a new blockquote.
I’m using this code to generate a blockquote in JS:
document.execCommand('formatBlock', false, 'blockquote');
While creating a rich text editor for an iOS application i faced the same problem. Every time i've inserted a <blockquote> tag in my text field and pressed Enter, it was impossible to get rid off the block-quote.
After researching a bit, i've found a working solution.
Finding inner HTML tags:
function whichTag(tagName){
var sel, containerNode;
var tagFound = false;
tagName = tagName.toUpperCase();
if (window.getSelection) {
sel = window.getSelection();
if (sel.rangeCount > 0) {
containerNode = sel.getRangeAt(0).commonAncestorContainer;
}
}else if( (sel = document.selection) && sel.type != "Control" ) {
containerNode = sel.createRange().parentElement();
}
while (containerNode) {
if (containerNode.nodeType == 1 && containerNode.tagName == tagName) {
tagFound = true;
containerNode = null;
}else{
containerNode = containerNode.parentNode;
}
}
return tagFound;
}
Checking for occurrences of the block-quote tag:
function checkBlockquote(){
var input = document.getElementById('text_field_id');
input.onkeydown = function() {
var key = event.keyCode || event.charCode;
if( key == 13){
if (whichTag("blockquote")){
document.execCommand('InsertParagraph');
document.execCommand('Outdent');
}
}
};
}
Triggering the key down events:
<body onLoad="checkBlockquote();">
<!-- stuff... -->
</body>
I believe the code above can be adjusted to fit your needs easily. If you need further help, feel free to ask.
Something like this did the work for me (at least on Chrome and Safari).
Demo at http://jsfiddle.net/XLPrw/
$("[contenteditable]").on("keypress", function(e) {
var range = window.getSelection().getRangeAt();
var element = range.commonAncestorContainer;
if(element.nodeName == "BLOCKQUOTE") {
element.parentElement.removeChild(element);
}
});
Didn't make any extensive test, but it looks like range.commonAncestorElement returns the current textnode in case the blockquote contains text, or the blockquote element itself in case it contains no textnode (on Chrome, a <br> is added and caret is positioned after it). You can remove the newly created blockquote in this case. Anyway, after deleting the element the caret looks like getting positioned somewhere upon the contenteditable, although typing confirms that it's right after the original blackquote.
Hope this points you to a more conclusive solution.
Super late answer, but this was a much simpler solution for me. Hopefully it helps anyone else looking. Browser compatibility may vary.
YOUR_EDITABLE_ELEMENT.addEventListener('keyup', e => {
if (e.which || e.keyCode === 13) {
if (document.queryCommandValue('formatBlock') === 'blockquote') {
exec('formatBlock', '<P>')
}
}
})

How can I block further input in textarea using maxlength

I have a textarea that I want to block input on if the entered characters reaches a max-length.
I currently have a Jquery script for the textbox that calculates the characters entered and want to add something that will block input in the textarea once 150 characters are entered.
I have tried using max-length plugins in conjunction with my script but they don't seem to work. Help is appreciated.
CURRENT CODE
(function($) {
$.fn.charCount = function(options){
// default configuration properties
var defaults = {
allowed: 150,
warning: 25,
css: 'counter',
counterElement: 'span',
cssWarning: 'warning',
cssExceeded: 'exceeded',
counterText: '',
container: undefined // New option, accepts a selector string
};
var options = $.extend(defaults, options);
function calculate(obj,$cont) {
// $cont is the container, now passed in instead.
var count = $(obj).val().length;
var available = options.allowed - count;
if(available <= options.warning && available >= 0){
$cont.addClass(options.cssWarning);
} else {
$cont.removeClass(options.cssWarning);
}
if(available < 0){
$cont.addClass(options.cssExceeded);
} else {
$cont.removeClass(options.cssExceeded);
}
$cont.html(options.counterText + available);
};
this.each(function() {
// $container is the passed selector, or create the default container
var $container = (options.container)
? $(options.container)
.text(options.counterText)
.addClass(options.css)
: $('<'+ options.counterElement +' class="' + options.css + '">'+ options.counterText +'</'+ options.counterElement +'>').insertAfter(this);
calculate(this,$container);
$(this).keyup(function(){calculate(this,$container)});
$(this).change(function(){calculate(this,$container)});
});
};
})(jQuery);
Have you tried ​the maxlength attribute? That will block input once the character limit is reached.
<textarea maxlength='150'></textarea>​​​​​​​​​​​​​​​​​​​​​​​​​​ // Won't work
<input type='text' maxlength='150' />
Edit It appears that maxlength for a textarea works in Chrome, but not in other browsers, my bad. Well, another approach would just be to monitor keydown events and if length>150, return false/preventDefault/however you want to stop the default action. You'd still want allow backspace and enter however, so monitor keycode as well.
$('#yourTextarea').keydown(function(e) {
if (this.value.length > 150)
if ( !(e.which == '46' || e.which == '8' || e.which == '13') ) // backspace/enter/del
e.preventDefault();
});
You're much better off not trying to prevent the user from typing in too many characters and instead showing a counter and only enforcing the character limit when the user tries to submit. The comment boxes Stack Overflow are a decent example. It's both easier technically and more importantly better for the user to do it this way: it's really irritating not to be able to type/paste/drag text into a textarea even if you know there's a character limit.
Textarea maxlength with Jquery works OK but probably doesn't solve the issue of pasting in larger amounts of text.
PB Edit: Has since been updated here
Try this code below i hope will work, remember to include jQuery library
<div class="texCount"></div>
<textarea class="comment"></textarea>
$(document).ready(function(){
var text_Max = 200;
$('.texCount').html(text_Max+'Words');
$('.comment').keyup(function(){
var text_Length = $('.comment').val().length;
var text_Remain = text_Max - text_Length;
$('.texCount').html(text_Remain + 'Words');
$('.comment').keydown(function(e){
if(text_Remain == 0){
e.preventDefault();
}
});
});
});
You can truncate the contents of the textarea if it is over 150 characters as described at http://web.enavu.com/daily-tip/maxlength-for-textarea-with-jquery/. I can see some issues with copy/pasting if that brings the text over the limit though.

Keypress in jQuery: Press TAB inside TEXTAREA (when editing an existing text)

I want to insert TAB characters inside a TEXTAREA, like this:
<textarea>{KEYPRESS-INSERTS-TAB-HERE}Hello World</textarea>
I can insert before/after the existing TEXTAREA text - and I can insert / replace all text in the TEXTAREA - but have not yet been able to insert inside the existing TEXTAREA text (by the cursor) in a simple way.
$('textarea:input').live('keypress', function(e) {
if (e.keyCode == 9) {
e.preventDefault();
// Press TAB to append a string (keeps the original TEXTAREA text).
$(this).append("TAB TAB TAB AFTER TEXTAREA TEXT");
// Press TAB to append a string (keeps the original TEXTAREA text).
$(this).focus().prepend("TAB TAB TAB BEFORE TEXTAREA TEXT");
// Press TAB to replace a all text inside TEXTAREA.
$(this).val("INSERT INTO TEXTAREA / REPLACE EXISTING TEXT");
}
});
There is a "tabs in textarea" plug-in for jQuery ("Tabby") - but it's 254 code lines - I was hoping for just a few lines of code.
A few links that I studied: (again, I would prefer fewer code lines).
http://www.dynamicdrive.com/forums/showthread.php?t=34452
http://www.webdeveloper.com/forum/showthread.php?t=32317
http://pallieter.org/Projects/insertTab/
Please advise. Thanks.
I was creating a AJAX powered simple IDE for myself so I can rapidly test out PHP snippets.
I remember stumbling upon the same problem, here's how I solved it:
$('#input').keypress(function (e) {
if (e.keyCode == 9) {
var myValue = "\t";
var startPos = this.selectionStart;
var endPos = this.selectionEnd;
var scrollTop = this.scrollTop;
this.value = this.value.substring(0, startPos) + myValue + this.value.substring(endPos,this.value.length);
this.focus();
this.selectionStart = startPos + myValue.length;
this.selectionEnd = startPos + myValue.length;
this.scrollTop = scrollTop;
e.preventDefault();
}
});
#input is the ID of the textarea.
The code is not completely mine, I found it on Google somewhere.
I've only tested it on FF 3.5 and IE7. It does not work on IE7 sadly.
Unfortunately, manipulating the text inside textarea elements is not as simple as one might hope. The reason that Tabby is larger than those simple snippets is that it works better. It has better cross-browser compatibility and handles things like tabbing selections.
When minified, it's only about 5k. I'd suggest using it. You'll either have to discover and troubleshoot those same edge cases yourself anyway, or might not even know about them if users don't report them.
Yeah, dealing with input field selections across the different browsers is an annoyance, especially as in IE there are a few methods that look like they should work but actually don't. (Notably, combining using setEndPoint then measuring length, which looks OK until the selection starts or ends in newlines.)
Here's a couple of utility functions I use to deal with input selections. It returns the value of the input split into bits that are before, inside and after the selection (with the selection counting as an empty string at the input focus position if it's not a selection). This makes it fairly simply to replace and insert content at the point you want, whilst taking care of the IE CRLF problem.
(There may be a jQuery that does something like this, but I have yet to meet one.)
// getPartitionedValue: for an input/textarea, return the value text, split into
// an array of [before-selection, selection, after-selection] strings.
//
function getPartitionedValue(input) {
var value= input.value;
var start= input.value.length;
var end= start;
if (input.selectionStart!==undefined) {
start= input.selectionStart;
end= input.selectionEnd;
} else if (document.selection!==undefined) {
value= value.split('\r').join('');
start=end= value.length;
var range= document.selection.createRange();
if (range.parentElement()===input) {
var start= -range.moveStart('character', -10000000);
var end= -range.moveEnd('character', -10000000);
range.moveToElementText(input);
var error= -range.moveStart('character', -10000000);
start-= error;
end-= error;
}
}
return [
value.substring(0, start),
value.substring(start, end),
value.substring(end)
];
}
// setPartitionedValue: set the value text and selected region in an input/
// textarea.
//
function setPartitionedValue(input, value) {
var oldtop= input.scrollTop!==undefined? input.scrollTop : null;
input.value= value.join('');
input.focus();
var start= value[0].length;
var end= value[0].length+value[1].length;
if (input.selectionStart!==undefined) {
input.selectionStart= start;
input.selectionEnd= end;
if (oldtop!==null)
input.scrollTop= oldtop;
}
else if (document.selection!==undefined) {
var range= input.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', start);
range.select();
}
}
btw, see also:
http://aspalliance.com/346_Tabbing_in_the_TextArea

Categories

Resources