Handling copy/paste and max length using contenteditable in Jquery - javascript

Is there a proper way to handle both copy/paste and max length using contenteditable in Jquery? Currently, I am using the code below only for max length. However, if a user decided to copy paste a text that is longer than the max length allowed, the text will still go through.
Basically, my goal is to set character's limit up to 200 in length, also I want a decent way to handle if a user decided to copy paste something, especially if it is longer than the max length allowed.
$('div').keydown(function (event) {
if($(this).text().length >= 200 && event.keyCode != 8) {
event.preventDefault();
}
});

You can add a paste Event:
$('div').on('paste', function(event) {
// handle event
});
Read more about it in the MDN Web Docs.
var editable = $('div');
editable.on('paste', function(event) {
if (editable.text().length >= 200) {
editable.textContent = editable.text().substr(0,200); // it uses the whole content of the editable div
}
});

Related

Characters being injected into input field

I am sure this is something really stupid I am missing.
I am writing a small snippet that adds a hyphen to a string grabbed from an input field. The hyphen is only added once we hit position 4, so I can type 123 and the hyphen will not appear. If I type 1234, it'll automatically change to 1234-. The problem is with handling pasting, somewhere down the line inside jQuery (after my code has executed), it's injecting more characters into the field.
My approach is simple enough. I look at the keyup and keydown event, check the input and insert the hyphen. For pasting I look at the paste even, grab the string, split it and insert a hyphen depending on if one is present or not.
$('[id$="field"]').on('paste', function (event) {
var element = this;
var text = event.originalEvent.clipboardData.getData('text').split('');
if (text.length > 4 && text.indexOf('-') < 0) {
text.splice(4, 0, '-');
$(element).val(text.join(''));
}
});
$('[id$="field"]').bind('keyup keydown', function (event) {
var input = $(this).val();
if (input.length === 4 && event.keyCode !== 8) {
$($(this).val(input + '-'));
}
});
The keyup and keydown listener works just fine. If I paste in 12345, I end up with 1234-5 when I hit $(element).val(text.join('')); yet afterwards that extra char pops whilst jQuery is doing its thing.
I am rather baffled.
Any ideas?
Since you are overriding the typical "paste" behavior by updating the value of the input box directly, you need to prevent the "default" paste behavior.
$('[id$="field"]').on('paste', function (event) {
event.preventDefault();
// ...

Get character at current position within TinyMCE when the input changes

Right now i can detect if the input changes in the TinyMCE Editor, but i can't seem to figure out how to get what was changed/typed.
setup:function(editor) {
editor.on('input', function(e){
//pseudo condition
if (this.value === 'X') {
console.log('You type X', e);
}
});
}
I would like it to reach the console.log if X is typed into the editor, and maybe a way to move from that position back and forward just in case i have read pre and post text from that specific position.
The purpose of this is to be able to trigger another action when a specific word is typed into the editor like for suggestions and such.
There is a slice() function in JavaScript that returns you a "slice" of a string. You can use it to determine (for example) what are the last 6 characters in your input.
Example:
setup:function(editor) {
editor.on('input', function(e){
if (this.value.slice(this.value.length - 6, this.value.length) === '{link:') {
//Do magic
}
});
}

get the new added characters to an input by js

I know this seems a quite easy target. I have an input[type=text], and I want to detect the new added character(s) in it. The normal way is:
$selector.keypress(function(e) {
//do sth here
var newchar = String.fromCharCode(e.which);
});
But the above method not working properly for some browsers on android devices. Typing the android virtual keyboard will not fire the keypress.
Then I found the following method is better:
$selector.on('input', function(e){
//do sth here
});
It works fine for android devices, and also, it can detect cut/paste.
Now the question is, is there a way to know the new added character(s) to the input? Do I need to do the complicated string comparison during inputing each time, i.e. compare the previous string and the new string in the input box? I said it's complicated because you may not always type in char(s) at the end, you may insert some char(s) in the middle of the previous string. Think about this, the previous string in the input box is "abc", the new string after pasting is "abcxabc", how can we know the new pasted string is "abcx", or "xabc"?
The method from keypress is quite simple:
String.fromCharCode(e.which);
So, is there similar way to do this by the on('input') method?
After reading Yeldar Kurmangaliyev's answer, I dived into this issue for a while, and find this is really more complicated than my previous expectation. The key point here is that there's a way to get the cursor position by calling: selectionEnd.
As Yeldar Kurmangaliyev mentioned, his answer can't cover the situation:
it is not working is when you select text and paste another text with
replacing the original one.
Based on his answer, I modified the getInputedString function as following:
function getInputedString(prev, curr, selEnd) {
if (selEnd === 0) {
return "";
}
//note: substr(start,length) and substring(start,end) are different
var preLen = prev.length;
var curLen = curr.length;
var index = (preLen > selEnd) ? selEnd : preLen;
var subStrPrev;
var subStrCurr;
for(i=index; i > 0; i--){
subStrPrev = prev.substr(0, i);
subStrCurr = curr.substr(0, i);
if (subStrCurr === subStrPrev) {
var subInterval = selEnd - i;
var interval = curLen - preLen;
if (interval>subInterval) {
return curr.substring(i, selEnd+(interval-subInterval));
}
else{
return curr.substring(i, selEnd);
}
}
}
return curr.substring(0, selEnd);
}
The code is quite self explanation. The core idea is, no matter what character(s) were added(type or paste), the new content MUST be ended at the cursor position.
There's also one issue for my code, e.g. when the prev is abcabc|, you select them all, and paste abc, the return value from my code will be "". Actually, I think it's reasonable, because for my scenario, I think this is just the same with delete the abc from previous abcabc|.
Also, I changed the on('input') event to on('keyup'), the reason is, for some android browsers, the this.selectionEnd will not work in a same way, e.g., the previous text is abc|, now I paste de and the current string will be abcde|, but depending on different browsers, the this.selectionEnd inside on('input') may be 3, or 5. i.e. some browsers will report the cursor position before adding the input, some will report the cursor position after adding the input.
Eventually, I found on('keyup') worked in the same way for all the browsers I tested.
The whole demo is as following:
DEMO ON JSFIDDLE
Working on the cross-browser compatibility is always difficult, especially when you need to consider the touch screen ones. Hope this can help someone, and have fun.
Important notes:
when a user types in a character, the cursor stands after it
when a user pastes the text, the cursor is also located after the pasted text
Assuming this, we can try to suggest the inputed \ pasted string.
For example, when we have a string abc and it becomes abcx|abc (| is a cursor) - we know that actually he pasted "abcx", but not "xabc".
How do this algorithmically? Lets assume that we have the previous input abc and the current input: abcx|abc (cursor is after x).
The new one is of length 7, while the previous one is of length 4. It means that a user inputed 4 characters. Just return these four characters :)
The only case when it is not working is when you select text and paste another text with replacing the original one. I am sure you will come up with a solution for it yoruself :)
Here is the working snippet:
function getInputedString(prev, curr, selEnd) {
if (prev.length > curr.length) {
console.log("User has removed \ cut character(s)");
return "";
}
var lengthOfPasted = curr.length - prev.length;
if (curr.substr(0, selEnd - lengthOfPasted) + curr.substr(selEnd) === prev)
{
return curr.substr(selEnd - lengthOfPasted, lengthOfPasted);
} else {
console.log("The user has replaced a selection :(");
return "n\\a";
}
}
var prevText = "";
$("input").on('input', function() {
var lastInput = getInputedString(prevText, this.value, this.selectionEnd);
prevText = this.value;
$("#result").text("Last input: " + lastInput);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" />
<div id="result">Start inputing...</div>

Stopping an draggable object from dragging

I'm currently working on a drag and drop plugin. I want to add a feature so the user can limit the amount of times the drggable object can be dragged and dropped. I will call this feature, dragLimitation.
This is what I have so far:
var limit = 0;
$(document).ready(function() {
$(oj).mouseup(function() {
if (o.dragLimitation !== false) {
if (limit > (o.dragLimitation-1)) {
//Code to Stop Drag Here
} else {
limit++;
$('#back').html(limit);
}
}
});
});
About the Code: There are couple of things I want to get clear to you guys so I can get an answer.
The var, oj in: $(oj).mouseup(function() { is just referring to this. In this case this would be: $('#drag').jDrag();, which is just to get my plugin running.
#drag = this
One thing I want to point out is o.dragLimitation. This is to get the amount of times the drag and drop item/object can be dropped(mouseup).
Example:
$('#drag').jDrag({
dragLimitation: 20
});
This would make #drag be able to be dragged and dropped 20 times.
I got a lot of the code but I just don't know how to stop the element from dragging. I don't to break the code either using:
$('body').append('<span>');
So the users can still use the rest of the page.
Here is where the code for the stop dragging should be:
if (limit > (o.dragLimitation - 1)) {
//Code to Stop Drag Here
}
I really hope someone can help me with the details I gave.
Thanks for any help.
(function($) {
$.extend($.fn, {
jDrag: function() {
var dragCount = this.data("jDrag.dragCount"),
limitation = this.data("jDrag.limitation");
if(typeof dragCount !== "number" || !isFinite(dragCount))
{
/*
* Drag count isn't a valid number.
* Give it a 0 value, and save it to the target.
*/
dragCount = 0;
this.data("jDrag.dragCount", dragCount);
}
if(typeof limiation !== "number" || !isFinite(limitation))
{
/*
* Limitation isn't a valid number.
* Load default limitation from plugin defaults.
*/
limitation = $.data("jDrag.defaults").limitation;
}
if(dragCount <= limitation)
{
/*
* Drag limitation isn't yet exceeded, increment count
* and save it to the target.
*/
this.data("jDrag.dragCount", ++dragCount);
/* Continue code here. */
}
}
});
})(jQuery);
Refer to jQuery.data method for internally storing data for your plugins. As you can probably see, the code above simply loads the amount of times the target has been dragged, and the limitation placed on the target. If the dragCount isn't a valid number, it gives it a dragCount of zero (, later changed to 1). If the limitation isn't a valid number, it loads the plugin's default limitation stored in the plugin's data.
Notice that we used this.data, but we later used $.data. When using this.data, this information is stored on the specific element. Using $.data will load data for the plugin itself. Since we use this.data to store information on the specific element, you can easily store different drag limitations on different elements, instead of making them all share the same limitations. If you follow this outline, you shouldn't have any problems.
Note: I didn't test this script. It is just a basic idea.
Update: Added comments to code for better understanding.
You don't necessarily need any code to stop the drag/drop functionality, you should just wrap the code for the drag/drop functionality in an if that checks if the limitation has been met. If it has then the dragging/dropping code wont execute.

What is the best JavaScript solution to limit the length of a textarea?

Is there a canonical solution for limiting the number of characters that someone can enter into a textarea?
I have server side validation of course, but would like to improve the user experience by adding client side code to simulate the experience you get with maxlength on an input[type="text"] so that users never see the "your input is too long" error message if they have javascript enabled.
My non-technical $0.02
Do what SO does in their comment fields, provide feedback as to what the user's character length remaining is and allow them to go past the maximum, but not submit > 300 characters. Here's why:
Allowing users to go over the maximum number of characters allows them to complete an idea. They can then go back and edit that idea. There's nothing worse than being at the end of a sentence and being unable to complete it.
Providing feedback to character length keeps people from having to guess what their length is at.
I would do it this way:
$ ('#textarea-id').bind (
'change input keyup keydown keypress mouseup mousedown cut copy paste',
function () { return ($(this).val().length <= maxlength) }
)
So many bingings just to be completely sure :-)
This will do it...
function textareaMaxLen(event) {
var max = parseInt(this.attr("maxlength"), 10);
if(this.value.length >= max)
this.value = this.value.substr(0, max);
}
$("textarea").keyup(textareaMaxLen).blur(textareaMaxLen);
Attach an onchange event to the textarea. There you can check if the value's larger than the appropriate or not. Example with jQuery:
$("#textarea-id").change(function (){
var text = $(this).val();
if( text.length > MAX ){
return false;
}
});
I've done it like this in the past:
<textarea onkeyup="checkLength(this);"></textarea>
Then implement this function:
function checkLength(control) {
if (control.value.length > 5) {
control.value = control.value.substr(0, 5);
}
}
It's a pretty basic example fixing the length to 5, but hopefully gives you the idea!

Categories

Resources