Forcing line break in the textarea after 38 characters using jquery - javascript

1Heres is my code but I am dont know how to add a line break and allow the user to continue typing. With the alert message is fine but I just want the user to continue typing and line break added by the script.
dom.query = jQuery.noConflict( true );
dom.query(document).ready(function() {
// var myTA = dom.query('#remaining_chars');
//alert(myTA[0].scrollHeight);
dom.query('#ta').keypress(function() {
var text =dom.query(this).val();
var arr = text.split("\n");
for(var i = 0; i < arr.length; i++) {
if(arr[i].length > 38) {
alert("Not more than 38 characters per line! Continue in next line!");
event.preventDefault(); // prevent characters from appearing
}
}
console.log(text);
dom.query('#ta').val(text);
});
});
Link to the code :http://jsfiddle.net/e5w5z/8/1

This code will automatically insert line breaks if the user continues to type and never backtracks. This only analyzes the last line in the textarea. Therefore, if they go back to a previous line and begin editing, they will be able to type more than the max characters allowed per line. It should be possible to have this analyze every line, but you'd have to write some more involved logic in order to insert line breaks at the correct positions and set the caret position properly after changing the textarea contents.
JSFiddle: http://jsfiddle.net/7V3kY/1/
var LINE_LENGTH_CHARS = 38;
$(function(){
$(document).on('input propertychange','textarea',function(e){
// Something was typed into the textarea
var lines = $(this).val().split("\n");
var last_line = lines[lines.length-1];
if (last_line.length >= LINE_LENGTH_CHARS) {
// Resetting the textarea val() in this way has the
// effect of adding a line break at the end of the
// textarea and putting the caret position at the
// end of the textarea
$(this).val($(this).val()+"\n");
}
});
});

Related

textarea.selectionEnd is always equal to the last character in textarea.value

function makeBold() {
ta = document.getElementById('instructions');
if (ta.selectionStart != ta.selectionEnd) {
ta.value = [ta.value.slice(0, ta.selectionStart), '<strong>', ta.value.slice(ta.selectionStart)].join('');
ta.value = [ta.value.slice(0, ta.selectionEnd), '</strong>', ta.value.slice(ta.selectionEnd)].join('');
}
}
I wrote this function that gets triggered by an on_click event for a button. .selectionStart returns the start of the selected text but .selectionEnd is always returning the last character of the textearea's value, not the index where the selected text ends.
I tested this with:
console.log(ta.selectionEnd, ta.value.length)
and they both return the same.
Can anyone help me see what I am misunderstanding here?
Bit of a rubber duck moment.
I have solved this with the code:
function makeBold() {
ta = document.getElementById('instructions');
const start = ta.selectionStart;
const end = ta.selectionEnd;
if (ta.selectionStart != ta.selectionEnd) {
ta.value = [ta.value.slice(0, start), '<strong>', ta.value.slice(start)].join('');
ta.value = [ta.value.slice(0, end+8), '</strong>', ta.value.slice(end+8)].join('');
}
}
I suspect editing the textarea's value removed the current selection, so I captured the start and end of the selection first, then make the edits. I also add 8 to the value of .selectionEnd to account for the 8 characters in ''.

Input not scrolling to the far right like it should

I have an input field where i append data at the cursor position.
after that, i set the selectionStart to the end of the field.
BUT, whenever i add something to the input (by button clicks), i only see the left part of it (until it reaches the right edge). everything more is there (i can select it with the mouse and scroll), but it doesn't automatically show the right edge.
how can i do that?
i want to add something to the input and jump right to the end of the string.
// add 2 digit number
$('button#2digit').on('click', function add2digit() {
addNumberToInput(10, 99);
});
function addNumberToInput(min, max) {
var problemInput = $('input#testProblem');
if (lastCharIsOperation() || problemInput.val().trim() < 1) { // if last char is an operation or first in string, just append the number
addAtCursor(randomNonPrime(min, max));
} else {
addAtCursor('+' + randomNonPrime(min, max));
}
}
function addAtCursor(toAdd) {
var problemInput = $('input#testProblem');
var oldText = problemInput.val();
var cursor = problemInput[0].selectionStart;
var pre = oldText.substring(0,cursor);
var post = oldText.substring(cursor, oldText.length);
//insert at cursor
problemInput.val(pre + toAdd + post);
//put cursor to end
problemInput[0].selectionStart = problemInput.val().length;
}
(it even skips back to the left on blur, i couldn't make a picture with the windows snipping tool, because i had to click it first)
From Set mouse focus and move cursor to end of input using jQuery.
var problemInput = $('input#testProblem');
problemInput.focus();
var t=problemInput.val();
problemInput.val('');
problemInput.val(t);
Here is the start of a full solution: https://jsfiddle.net/michaelgentry/vwm159pt/
This will still cause the scroll to jump back to the left on blur, but does what you are asking:
var elem = document.getElementById('myInput');
elem.focus();
elem.scrollLeft = elem.scrollWidth;

How to know if Ckeditor anchor is encapsulated within span?

This is specifically for the developers of CKEditor.
The goal is to know when the cursor is either inside or outside a span of custom atttributes.
When using the Ckeditor, if inserted a custom span like below from a plug-in, occassionally when you stop typing, un focus the textarea and replace your cusor to the end of the line - as though you are continuing typing where you had left off. The text can either be inside the span or outside with no encapsulation.
Example before unfocus:
<span style="color:blue;line-height:12px;font-size:10px;font-family:arial;" class="master-span">
<span style="color:red;line-height:20px;font-size:18px;font-family:museo;" class="child-span">Text is here</span>
</span>
Re-Focus and positioning cusor on screen at the end of "here" and start typing.
<span style="color:blue;line-height:12px;font-size:10px;font-family:arial;" class="master-span">
<span style="color:red;line-height:20px;font-size:18px;font-family:museo;" class="child-span">Text is here</span> Text is now outside!!!
</span>
What I'm asking is that where would I target my troubleshoot to know when the cursor/anchor is within the span or outside of it i.e. Is there a calculation being made in the code to determine this?
The reason for this enquiry is that the span formmating is extremely important and we can't use a master span in the surrounding textarea as this can be altered by the user. We find also, that using bulletpoints are troublesome due to the browsers inability to set line-height so ensuring text is always within the span would be a major help.
P.S I've downloaded the source code to see where I could find it.
Many Thanks for any help.
Upon clicking of the text area of any of my CKeditor instances I looked for the parent of the cursor to see if it was an LI node. This indicating that the cursor had landed outside of my span within a bullet point. I proceeded to find the most outside Text Node I could find as my assumption is that if the cursor was outside the span thus the user wanted to continue typing from the last character.
In my setup, within a span there can be a number of multiple sub spans with no limitation of number. So I had to find the most outside span that had a text node at the end (or close to the end).
I did by getting the Node List and reversing the order to find the first text node within the reverse order. I created a function that could loop the number of span and break upon finding the first text node.
Once I had my text node I then set up ranges and calculated the length of the text in order to place it at the end. Below is my final solution which works on latest Chrome/FF/IE.
$("#preview-text-3827").on("click", function(){
var CKEDITOR = window.parent.CKEDITOR;
var ck_instance_name = false;
for ( var ck_instance in CKEDITOR.instances ){
if (CKEDITOR.instances[ck_instance].focusManager.hasFocus){
ck_instance_name = ck_instance;
break;
}
}
var editor = CKEDITOR.instances[ck_instance_name];
var selection = editor.getSelection();
var parent_attrs = "";
if (selection.getType() == CKEDITOR.SELECTION_TEXT) {
parent_attrs = selection.getStartElement();
if(parent_attrs.getName() == "li"){
var nodeList = parent_attrs.getChildren();
console.log( "Now Reverse" );
for ( var i = nodeList.count() - 1; i > -1; --i ) {
//console.log( nodeList.getItem( i).nodeName );
var el = nodeList.getItem( i);
if(el.$.nodeName == "#text"){
// This is the last text but it's inside the li which is WRONG
}
if(el.$.nodeName == "SPAN"){
// This should be the last span
// Jump into this span and find the children.
var result = retractLiPosition(el);
if(result.text == true){
var inner = result.result;
var text = inner.$.textContent || inner.$.innerText;
var length = text.length;
var range = editor.createRange();
range.setStart( inner , length);
range.setEnd( inner, length);
editor.getSelection().selectRanges( [ range ] );
break;
}
}
}
}
}
});
function retractLiPosition(element){
var returning = new Object();
returning.result = element;
returning.text = false;
var result = element;
var nodeList = element.getChildren();
for ( var i = nodeList.count() - 1; i > -1; --i ) {
var el = nodeList.getItem( i);
if(el.$.nodeName == "#text"){
returning.result = el;
returning.text = true;
break;
}
if(el.$.nodeName == "SPAN"){
// This should be the last span
// Jump into this span and find the children.
returning = retractLiPosition(el);
}
}
return returning;
}
});

Firing an event when the caret gets within a particular div/span/a tag and also, when the caret leaves the tag

The idea is this -
There is a contenteditable element with some text in it. Am trying to build out a tagging mechanism (kind of like twitter's people tagging when you type '#'). Whenever a user types '#', it shows up a popover with suggestions and filters when they continue typing. Until here it's easy and I have got it figured out. The problem comes when I need to show the popover if/only if the caret is over the element containing the tag.
<div contenteditable="">
<p>Some random text before
<a href="javascript:;"
class="name-suggest"
style="color:inherit !important;text-decoration:inherit !important">#samadams</a>
Some random text after</p>
</div>
Now, whenever the user moves the caret over the a tag / clicks on it, I want to trigger an event that shows the popover, and remove it whenever the caret leaves the a tag. (kind of like focus / blur but they don't seem to work). onmousedown works but there is no way to tell if the cursor has been moved into the anchor tag with the keyboard.
Also, am doing this in angularjs, so, any solution targeted towards that would be preferable but not necessary.
Have been trying to get this to work for a day and any help is greatly appreciated.
This will let you know when your caret position is in an anchor node containing an #
$('#content').on('mouseup keydown keyup', function (event) {
var sel = getSelection();
if (sel.type === "Caret") {
var anchorNodeVal = sel.anchorNode.nodeValue;
if ( anchorNodeVal.indexOf('#') >= 0) {
$('#pop').show()
} else {
$('#pop').hide()
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="content" contenteditable="">
<p>Some random text before
<a href="javascript:;"
class="name-suggest"
style="color:inherit !important;text-decoration:inherit !important">#samadams</a>
Some random text after</p>
</div>
<div id="pop" style="display:none">Twitter node found</div>
You could add some regex to further validate the selection.
There is a weird move with RegExps and offset calculation in the code below, but let me explain why it's a better solution.
I've been building a complicated editor using contenteditable about a year ago. It wasn't just a disaster. It was a fucking disaster. There is no cover-all-the-cases spec. Browsers behave differently in every possible detail and it changes frequently. Put a caret before # char and you will get this is Gecko:
<a href="#">|#name
And this in WebKit:
|<a href="#">#name
Well, unless <a> is paragraph's first child. Then result would be the same as in Gecko. Try to put caret after the nickname and both will tell it's inside the link. Start typing, and caret will pop out the element - a year ago Gecko wasn't doing it.
I've used native Selection & Range APIs in this example, they are IE9+. You may want to use Rangy instead.
$el = $('#content');
var showTip = function (nickname) {
// ...
console.log('Show: ' + nickname);
};
var dismissTip = function () {
// ...
console.log('Hide');
};
// I'm sure there is a better RegExp for this :)
var nicknameRegexp = /(^|\b|\s)\#(\w+)(\s|\b|$)/g;
var trackSelection = function () {
var selection = window.getSelection(),
range = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
if (range == null || $el[0].contains(range.commonAncestorContainer) == false) {
return dismissTip();
}
var comparer = range.cloneRange();
comparer.setStart($el[0], 0);
var offset = comparer.toString().length;
var match, from, to;
while (match = nicknameRegexp.exec($el[0].textContent)) {
from = match.index + match[1].length;
to = match.index + match[1].length + match[2].length + 1;
if (offset >= from && offset <= to) {
// Force rewind, otherwise next time result might be incorrect
nicknameRegexp.lastIndex = 0;
return showTip(match[2]);
}
}
return dismissTip();
};
$el.on({
// `mousedown` can happen outside #content
'mousedown': function (e) {
$(document).one('mouseup', function (e) {
// Calling function without a tiny delay will lead to a wrong selection info
setTimeout(trackSelection, 5);
});
},
'keyup': trackSelection
});
Just looked at Fire event when caret enters span element which led me here, pretending your case was quite similar except finding if current word is specifically beginning with # for the modal to show...
The thing you need is a way to get the word we're on at the moment we move or type, then check the first character and hide/show the modal pane accordingly will be pretty easy.
function getSelectedWord(grab=document.getSelection()) {
var i = grab.focusOffset, node = grab.focusNode, // find cursor
text = node.data || node.innerText, // get focus-node text
a = text.substr(0, i), p = text.substr(i); // split on caret
return a.split(/\s/).pop() + p.split(/\s/)[0]} // cut-out at spaces
Now you can listen for keydown or selectionchange events and show your pane knowning what have already been written of the current/selected word.
editor.addEventListener('keydown', ev => {
if (ev.key.substr(0, 5) != 'Arrow') // react when we move caret or
if (ev.key != '#') return; // react when we type an '#' or quit
var word = getSelectedWord(); // <-- checking value
if (word[0] == '#') showModal(word.substr(1)); // pass without '#'
});
Note that social networks and code completion usually stops at caret position while I did check for word tail... You can go usual by removing p off of getSelectedWord function definition if desired.
Hope this still helps; Happy coding ! ;)

TextArea with 10 lines and 35 characters per line

I have an HTML page with many elements. The page is scrollable, that means the page has a scrollbar in it. Down to the page I have a HTML textarea with a specified rows and columns attribute.
Now I want a simple JavaScript solution which will help me to validate the the following points each time user enters any character:
The number of lines in the textarea is not greater than 10
Each line has less than or equal to 35 characters
If user crosses 35 character limit for any particular line then the 36th character will be automatically start from next line only if the total line numbers does not exceed 10, else it will show an error popup message and stops there.
User should be able to modify any lines(it may be last line or any middle lines) and still should follow all the above 3 points.
I used the following to limit the amount of characters allowed in my textarea.
This not only counts the amount of characters it trims it if it gets to the end and it also writes out how many characters you have left.
I think all you need to do now is figure out how to add a new line (try something like text += "\r\n";) <- Not 100% sure on this peice.
function textCounter(txtfield, cntFld, maxlimit){
var field = document.getElementById(txtfield);
var countfield = document.getElementById(cntFld);
if (field.value.length > maxlimit) // if too long...trim it!
{
field.value = field.value.substring(0, maxlimit);
}else { // otherwise, update 'characters left' counter
countfield.innerHTML = maxlimit - field.value.length;
}
}
I have done a similar case :
MaxLenght of textarea = 1875 ;
MaxLenght of row = 75 ;
Disable Enter, because over 75's multiple, SW automatically wrap text ;
This is it, with onkeydown trigger:
function wrapTextArea(event,id,maxLineLenght){
// delete and canc
if((recuperaKeyCode(event)!=8) && (recuperaKeyCode(event)!=46)) {
var field = document.getElementById(id).value;
var nextIndex = 0;
for(var i=0; field.length>nextIndex; i++){
nextIndex=maxLineLenght*(i+1)+i;
if(field.length==nextIndex){
if(field.charAt(nextIndex)!= "\n"){
field=field.substring(0, nextIndex)+"\n"+field.substring(nextIndex, field.lenght);
}
}
}
document.getElementById(id).value = field;
}
}
This is how I disabled enter key, where key = 13 :
function disableKey(event,key){
if(recuperaKeyCode(event)==key){
event.preventDefault();
}
}

Categories