What I am trying to do:
Double click a line in a textarea.
Prevent text from being selected.
Prepend a dash to that line.
I know some basic jquery but can't seem to understand the lower level javascript that is required. Here is what I have so far:
$("textarea").dblclick(function() {
//TODO: Prevent selection
//TODO: Get the line number??
//TODO: prepend a dash to the line
// or replace the line with itself
// plus the dash at the front??
});
Here is the fiddle.
There may be a number of things you need to do, but something like this should be enough to get you started:
$("textarea").dblclick(function() {
//first, get the position of the cursor
var cursorPosition = $(this).prop("selectionStart");
//get the text value at the cursor position
var textValue = $(this).val().substr(cursorPosition,1);
//use a loop to look backward until we find the first newline character \n
while(textValue != '\n' && cursorPosition >= 0) {
cursorPosition--;
textValue = $(this).val().substr(cursorPosition,1);
}
//update the textarea, combining everything before the current position, a dash, and everything after the current position.
$(this).val(($(this).val().substr(0,cursorPosition+1) + '-' + $(this).val().substr(cursorPosition+1)))
});
You can see an example in this JS Fiddle:
http://jsfiddle.net/igor_9000/4zk5otvm/2/
There will probably be a lot more you need to add to this, depending on what you want to be able to do with the function and what limits you want to enforce, but that should be enough to get you started. Hope that helps!
I needed something similar, here's what you might've been looking for with vanilla JS (without jQuery or anything):
function dblClickEvt(obj) {
let pos = obj.selectionStart;
let text = obj.value;
let lineStart = text.lastIndexOf("\n", pos);
let lineEnd = text.indexOf("\n", pos);
let before = ( lineStart === -1 ? '' : text.slice(0, lineStart + 1) ); // row(s) before incl. line break
let after = '';
if(lineEnd === -1) // -> last row is selected
lineEnd = undefined; // because -1 would cause the selection to strip the last character
else
after = text.slice(lineEnd); // row(s) after the selection
let selected = text.slice(lineStart + 1, lineEnd); // the selected row
// write new value (manipulate before, selection a/o after if you want)
obj.value = before + '-' + selected + after;
// reset cursor position:
obj.selectionStart = pos;
obj.selectionEnd = pos;
}
Use the "ondblclick" attribute of your textarea to call the function:
<textarea ondblclick="dblClickEvt(this)"></textarea>
This only supports modern browsers, if you want to support older browsers, then you need to get the method that calculates selectionStart. This is not fully tested and if you double click on a line that is selected, it toggles the dash. And when you set the new value, the selection goes away.
$("textarea").on("dblclick", function (evt) {
var taValue = this.value;
//if there is no text than there is nothing to do
if(!taValue.length) return;
//get the position of the selection (not supported old browsers)
var se = this.selectionStart;
//find where the previous line break is located (array lastIndexOf not supported old browsers)
//thinking about it, probably do not need to split... :)
var loc = taValue.substr(0, se).split("").lastIndexOf("\n")+1;
//separate the text by characters
var parts = taValue.split("");
//if the character is a -, than remove it
if (parts[loc]==="-") {
parts.splice(loc, 1);
} else { //else inject the -
parts.splice(loc, 0, "-");
}
//join the array back up into a string and set the value
this.value = parts.join("");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea rows=10 cols=30>FOO FOO FOO
BAR BAR BAR
CAKE CAKE CAKE
WORLD WORLD WORLD</textarea>
Related
I have an input where I want to replace the value of the number on keyup event. Using Intl.NumberFormat().format(num); to accomplish this.
All is fine and it works great until you click inside of the already formatted value and start adding more numbers, the cursor jumps.
I tried to solve this by setting the cursor, but it still behaves badly.
In short, how can I change this snippet so that no matter where you edit the value, the cursor remains in the expected position?
const input = document.getElementById("foo");
input.addEventListener("keyup", handleKeyUp);
function handleKeyUp(e) {
const num = e.target.value.replace(/,/g, "");
const formatted = new Intl.NumberFormat().format(num);
var cursor = e.target.selectionStart;// + 1;
input.value = formatted;
e.target.setSelectionRange(cursor, cursor);
}
// Try the following
// 1) 123456789
// 2) 123
// 3) place cursor between the 1 and 2 and add a number
// If I ++cursor then #1 is resolved
// And #2 initially appears to be resolved unless I keep going with more numbers
<input id="foo" type="text">
Not a very elegant solution, but I moved the cursor based on if a comma was added/removed from the text field (left or right respectively).
See snippet below:
const input = document.getElementById("foo");
input.addEventListener("keyup", handleKeyUp);
let commas = 0;
function handleKeyUp(e) {
const num = e.target.value.replace(/,/g, "");
const formatted = new Intl.NumberFormat().format(num);
// get total commas in number
let totalCommas = (formatted.match(/,/g) || []).length;
var cursor = e.target.selectionStart;
if(commas > totalCommas) {
//shift cursor to the left (a comma was removed)
commas--;
cursor--;
} else if (commas < totalCommas){
// shift cursor to the right (a comma was added)
commas++;
cursor++;
}
input.value = formatted;
e.target.setSelectionRange(cursor, cursor);
}
// Try the following
// 1) 123456789
// 2) 123
// 3) place cursor between the 1 and 2 and add a number
// If I ++cursor then #1 is resolved
// And #2 initially appears to be resolved unless I keep going with more numbers
<input id="foo" type="text">
I have a text area where I add the number of orderlist item on click of a button.This is my code,
var addListItem = function() {
if (!this.addListItem.num) {
this.addListItem.num = 0
}
++this.addListItem.num;
var text = document.getElementById('editor').value;
console.log('text', text);
var exp = '\n' + this.addListItem.num + '.\xa0';
text = text.concat(exp);
document.getElementById('editor').value = text;
}
<div>
<button onclick="addListItem()">NumberList</button>
<textarea id="editor" col=10 rows=10></textarea>
</div>
As I have used a static variable to increment it increments on every click and so if I delete the list and create a new list again it doesn't starts from '1' and also I couldn't figure out how to update the numbers when a item is added in between.Could anyone suggest me how to fix this?
If you want a more robust solution that handles all sorts of different cases, you can use regular expressions to detect what number you're at in your list.
This solution also allows users to type in their own numbers and the button click WILL STILL WORK!
That's because this solution uses the text area content as the source of truth and doesn't track state on the side.
var addListItem = function() {
var text = document.getElementById('editor').value;
// regex to match against any new line that has a number and a period
// and extracts the number. feel free to use regex101.com to understand
// this in more depth.
var listNumberRegex = /^[0-9]+(?=\.)/gm;
var existingNums = [];
var num;
// get all the matches
while ((num = listNumberRegex.exec(text)) !== null) {
existingNums.push(num);
}
// sort the values
existingNums.sort();
// use the existing biggest number + 1 or use 1.
var addListItemNum;
if (existingNums.length > 0) {
// get last number and add 1
addListItemNum = parseInt(existingNums[existingNums.length - 1], 10) + 1;
} else {
// otherwise if there's nothing, just use 1.
addListItemNum = 1;
}
var exp = '\n' + addListItemNum + '.\xa0';
text = text.concat(exp);
document.getElementById('editor').value = text;
}
<div>
<button onclick="addListItem()">NumberList</button>
<textarea id="editor" col=10 rows=10></textarea>
</div>
understanding regular expressions is tricky, feel free to view https://regex101.com/r/gyX7oO/1 to get a better understanding of what is going on.
You can try something like this:
Logic:
On every click, get the text in textarea and split it be new line.
Now that you have line items, you need to get last sentence that starts with a numeric value. But user can enter new lines on his own to format text.
For this, loop on every line and validate it it starts with number followed by ..
If yes, use substring to fetch this number and parse it to int. If no match is found, you can return 0.
This will ensure the numbering system and you do not need a variable to hold last value.
Note: This logic assumes that last value will be the maximum. If you wish to handle that, you can just compare n and parseInt and assign maximum value
Sample:
var addListItem = function() {
var text = document.getElementById('editor').value;
var exp = '\n' + (getLastNumber(text) + 1) + '.\xa0';
text = text.concat(exp);
document.getElementById('editor').value = text;
}
function getLastNumber(str){
var list = str.split(/[\r\n]/g);
var n = 0;
list.forEach(function(s){
if(/^\d+\./.test(s)){
n = parseInt(s.substring(0, s.indexOf(".")));
}
});
return n;
}
<div>
<button onclick="addListItem()">NumberList</button>
<textarea id="editor" col=10 rows=10></textarea>
</div>
If you delete the list and create a new list again it will start from '1'.
also, counts from whatever the last number is.
var addListItem = function() {
if (!this.addListItem.num) {
this.addListItem.num = 0
}
++this.addListItem.num;
var text = document.getElementById('editor').value;
//HERE start new counting if textarea is empty
if(text.trim() == ''){
this.addListItem.num = 1; //restart counting here
}
//else check if textarea has previous numbers to proceed counting
else {
var lastLine = text.substr(text.lastIndexOf("\n") + 1).trim();
this.addListItem.num = parseInt(lastLine.slice(0, -1)) + 1; //add 1 to last number
}
console.log('text', text);
var exp = '\n' + this.addListItem.num + '.\xa0';
text = text.concat(exp);
document.getElementById('editor').value = text;
}
<div>
<button onclick="addListItem()">NumberList</button>
<textarea id="editor" col=10 rows=10></textarea>
</div>
Here is my code:
$("body").on('input', 'textarea', function() {
var el = $(this);
var len = el.val().length;
if (len <= 1){
var x = new RegExp("[A-Za-z]"); // is ascii
var isAscii = x.test(el.val().substring(0, 1));
if(isAscii){
el.css("direction", "ltr");
} else {
el.css("direction", "rtl");
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea>dynamic direction</textarea>
My current code changes the direction of such a textarea. It is based on the first character:
If the first character is either a Persian character or a sign, it sets rlt direction to that textarea.
If the first character is a English character, it sets lrt direction to that textarea.
Well that's not what I want. I want this:
If the first letter (not signs) is a English letter, then set the textarea ltr direction. Otherwise set it rtl.
Here is some examples:
var test = "..!"; // rtl
var test = "te"; // ltr
var test = "!te"; // ltr
var test = "..ق"; // rtl
var test = "مب"; // rtl
var test = "eس"; // ltr
var test = "سe"; // rtl
var test = "^سe"; // rtl
var test = ".32eس"; // ltr
How can I do that?
If I read the question correctly, the goal is to have the text read left-to-right if the first non-symbol/sign/punctuation character is an ASCII character, otherwise read right-to-left.
I think all you need to do is change your regex to first match 0 or more symbols/signs/punctuation-marks, and then to test if the next character is an ASCII character.
The regex [-!$%^&*()_+|~=`{}\[\]:";'<>?,.\/] is a fairly complete regex for symbols/signs/punctuation-marks, found here: https://stackoverflow.com/a/8359631/4132627. You may need to add to it as you see fit.
Putting that together we'd get something like [-!$%^&*()_+|~=`{}\[\]:";'<>?,.\/]*[A-Za-z]. The * between the two character groups means "match 0 or more of the previous group".
I've updated your snippet with that regex and it appears to work as expected. Also removed the length check as this needs to run no matter how many characters there are.
This probably isn't perfect - there are many cases probably being left out. You may need to play with it a bit. For example, should that second character group also include numbers ([A-Za-z0-9])?
In any case, I hope this helps!
$("body").on('input', 'textarea', function() {
var el = $(this);
var len = el.val().length;
//if (len <= 1){
var x = /^[-!$%^&*()_+|~=`{}\[\]:\";'<>?,.\/]*[A-Za-z]/; // is ascii
var isAscii = x.test(el.val());
if(isAscii){
el.css("direction", "ltr");
} else {
el.css("direction", "rtl");
}
//}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea>dynamic direction</textarea>
You can have an array of persian, or any right to left, letters and check whether the first letter exists in the array using .inArray() function, something like this:
jsFiddle
var persianLetters = ['آ ', 'ا', 'ب', 'پ', 'ت', 'ث','ج', 'چ', 'ح', 'خ', 'د', 'ذ', 'ر', 'ز' , 'ژ', 'س', 'ش', 'ص', 'ض', 'ط', 'ظ', 'ع', 'غ', 'ف', 'ق', 'ک', 'گ' ,'ل', 'م', 'ن', 'و', 'ه', 'ى'];
$("#ta").on('input', function() {
var el = $(this);
var txt = el.val();
var len = txt.trim().length;
if (len <= 1){
var x = txt.substring(0, 1);
// if the letter is not in the array, the $.inArray() will return -1
console.log($.inArray(x, persianLetters));
if($.inArray(x, persianLetters) > -1){
el.css("direction", "rtl");
} else {
el.css("direction", "ltr");
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<textarea name="txt" id="ta" cols="30" rows="10"></textarea>
I am creating a live content editor for an element using textarea, but its output isn't like what the expected if the inputted value is symbol like > or < or mix up of those symbols and texts, instead of just texts, then it will not replacing instead of doubled it up.
Here is the Fiddle
And here is the jquery codes:
$("#changer").on("change keyup paste", function () {
// get current element
var thehtml = $("#tochange").html();
var thetext = $("#tochange").contents().filter(function () {
return this.nodeType === 3;
}).text().trim();
var thechange = $(this).val();
// if has element, then keep it, add text and put back
var thepurehtml = thehtml.replace(thetext, "");
var theoutput = thechange;
if ($.trim(thepurehtml) != '') {
var theoutput = thechange + thepurehtml;
}
$("#tochange").html("").html(theoutput);
return;
});
What's causing it and how to fix it up?
PS: I need to have the functionality of this line var theoutput = thechange + thepurehtml; because it is sometimes the edited element have html element other than just a blank or text node.
However i am going to delete this answer, As i don't have enough reputation to comment i am posting as answer.
So #SoursopTree, what you actually want to achieve?
What i found is when you enter < or > the line $.trim(thepurehtml) is returning empty string (null) and null!='', so the next statement var theoutput = thechange + thepurehtml; here thechange=> and thepurehtml=>. so you are getting two symbols instead of one.
You said you need to have the functionality of this line var theoutput = thechange + thepurehtml;
I have a text area that I need to parse. Each new line needs to be pulled out and an operation needs to be performed on it. After the operation is done the operation needs to be run on the next line. This is what I have at the moment. I know the indexOf search won't work because it's searching character by character.
function convertLines()
{
trueinput = document.getElementById(8).value; //get users input
length = trueinput.length; //getting the length of the user input
newinput=trueinput; //I know this looks silly but I'm using all of this later
userinput=newinput;
multiplelines=false; //this is a check to see if I should use the if statement later
for (var i = 0; i < length; i++) //loop threw each char in user input
{
teste=newinput.charAt(i); //gets the char at position i
if (teste.indexOf("<br />") != -1) //checks if the char is the same
{
//line break is found parse it out and run operation on it
userinput = newinput.substring(0,i+1);
submitinput(userinput);
newinput=newinput.substring(i+1);
multiplelines=true;
}
}
if (multiplelines==false)
submitinput(userinput);
}
So for the most part it is taking the userinput. If it has multiply lines it will run threw each line and seperatly and run submitinput. If you guys can help me I'd be eternally thankful. If you have any questions please ask
Line breaks within the value of a textarea are represented by line break characters (\r\n in most browsers, \n in IE and Opera) rather than an HTML <br> element, so you can get the individual lines by normalizing the line breaks to \n and then calling the split() method on the textarea's value. Here is a utility function that calls a function for every line of a textarea value:
function actOnEachLine(textarea, func) {
var lines = textarea.value.replace(/\r\n/g, "\n").split("\n");
var newLines, i;
// Use the map() method of Array where available
if (typeof lines.map != "undefined") {
newLines = lines.map(func);
} else {
newLines = [];
i = lines.length;
while (i--) {
newLines[i] = func(lines[i]);
}
}
textarea.value = newLines.join("\r\n");
}
var textarea = document.getElementById("your_textarea");
actOnEachLine(textarea, function(line) {
return "[START]" + line + "[END]";
});
If user is using enter key to go to next line in your text-area you can write,
var textAreaString = textarea.value;
textAreaString = textAreaString.replace(/\n\r/g,"<br />");
textAreaString = textAreaString.replace(/\n/g,"<br />");
textarea.value = textAreaString;
to simplify the answers, here is another approach..
var texta = document.getElementById('w3review');
function conv (el_id, dest_id){
var dest = document.getElementById(dest_id),
texta = document.getElementById(el_id),
val = texta.value.replace(/\n\r/g,"<br />").replace(/\n/g,"<br />");
dest.innerHTML = val;
}
<textarea id="targetted_textarea" rows="6" cols="50">
At https://www.a2z-eco-sys.com you will get more than what you need for your website, with less cost:
1) Advanced CMS (built on top of Wagtail-cms).
2) Multi-site management made easy.
3) Collectionized Media and file assets.
4) ...etc, to know more, visit: https://www.a2z-eco-sys.com
</textarea>
<button onclick="conv('targetted_textarea','destination')" id="convert">Convert</button>
<div id="destination">Had not been fetched yet click convert to fetch ..!</div>