Ok I am making a text editor and have to try and make the last word typed change font color based on if it's a keyword or not... I have tried multiple solutions to this but nothing has prevailed... Here is what I have tried so far
function getLastWord() {
var input = document.getElementById("my_text").value;
//var input = document.getElementById(textArea.value);
var inputValue = input.value;
var lastWordTyped
var changeColorOfWord;
var ele = document.querySelector("#my_text");
//ele.style.color = "blue"
if (input == null) {
input == " ";
}
lastWordTyped = input.substr(input.trim().lastIndexOf(" ") + 1);
//lastWordTyped = inputValue.substr(inputValue.trim().lastIndexOf(" ") + 1);
if (input != null) {
for (var i = 0; i < reservedKeyWords.length; i++) {
if ( lastWordTyped == reservedKeyWords[i] ) {
//changeColor(lastWordTyped);
//my_text.replace(inputValue, lastWordTyped);
//ele.fieldNameElement.innerHTML = lastWordTyped;
//ele.innerHTML = lastWordTyped;
ele.innerHTML.fontcolor = 'Blue';
return;
} else if (lastWordTyped !== reservedKeyWords[i]) {
//ele.innerHTML = ele.innerHTML.replace(lastWordTyped, '<span style="color:black"></span>');
//resetFontColor();
}
}
}
}
I have tried this function (found from SO)
function changeColor(word) {
var ele = document.querySelector("my_text");
ele.onkeypress = function () {
setTimeout(function () {
//the setTimeout is so the content is inserted before execution
document.getElementById('view_text').value = ele.textContent;
if (ele.innerHTML.indexOf(word) !== -1) {
ele.innerHTML = ele.innerHTML.replace(word, '<span style="color:blue">' + word + '</span>');
}
}, 50);
}
}
Also I have tried this one:
function colorMyKeyword(keywordColor, text) {
return '<span style="color:' + keywordColor + '>' + text + '</span>';
}
None of these functions have gotten the job done though. I have it now so that it will change the text color to blue but then the problem is that it changes ALL of the text to blue after that word...
I would prefer this to be in javascript as I do not know how to use JQuery, or really CSS for that matter or even know how to write it..
Thank you for any responses.
Updated code based on comment(s) below (changed to div from input)
Not the best code in the world but it should work. The CSS should probably be done by adding a class instead of changing the style attribute.
<div id="my_text">This is some text</div>
var isKeyword = false;
var el = document.getElementById('my_text');
var arr = el.innerHTML.split(' ');
var lastWordTyped = arr.pop();
/* replace with yours*/
var reservedKeyWords = ['text','another','word', 'here'];
for (var i = 0, len = reservedKeyWords.length ; i < len ; i++) {
if ( lastWordTyped == reservedKeyWords[i] ) {
lastWordTyped = '<span style="color:blue">'+lastWordTyped +'</span>'; //update color
arr.push(lastWordTyped);
isKeyword = true;
}
}
if (!isKeyword) { arr.push(lastWordTyped); } //put original back
el.innerHTML = arr.join(' ');
UPDATED: Do the whole thing on keyup
here's a simple example that you can use: DEMO
$('#text').keyup(function(){
$('#result').html($('#text').val());
var splittedText=$('#result').html().split(/\s/);
var lastWord=splittedText[splittedText.length-1];
$('#result').html($('#result').html().replace(lastWord,'<span>'+lastWord+'</span>'));
$('#result').children('span').css('color',$('#color').val());
});
you need to write a sentence in the first input and a hexa-deciaml color in the second one.(including the # at the beginning)
Here is an attempt to answer your questions :
I am using #GaryStorey's answer as it was a better starting point than what I add (I do like pop&push).
The problem with his answer were that it only showed how to change the color but it wasn't relevant on how to do it in an input nor in a contenteditable element.
So here are my adjustements, with a setCaret function to deal with the fact that caret always returns to start if we do change the innerHTML of edited element.
Be carefull, it is still very buggy and you should not use it in any production,
however it can give you a good starting point.
var reservedKeyWords = ['text', 'another', 'word', 'here'];
var el = document.getElementById('my_text');
el.addEventListener('keyup', function (evt) {
if (evt.keyCode == 32 || evt.keyCode == 13) {
var isKeyword = false;
var arr = el.innerHTML.split(/\s/);
var lastWordTyped = arr.pop();
lastWordTyped = lastWordTyped.replace(' ', '');
for (var i = 0, len = reservedKeyWords.length; i < len; i++) {
if (lastWordTyped == reservedKeyWords[i]) {
lastWordTyped = '<span style="color:blue">' + lastWordTyped + '</span>'; //update color
arr.push(lastWordTyped);
isKeyword = true;
}
}
if (!isKeyword) {
arr.push(lastWordTyped);
} //put original back
el.innerHTML = arr.join(' ') + ' ';
setCaret(el);
}
});
function setCaret(el) {
var range = document.createRange();
var endNode = el.lastChild;
range.selectNodeContents(endNode);
range.setStart(endNode, range.endOffset);
range.setEnd(endNode, range.endOffset);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
#my_text {
min-width: 100%;
min-height: 2em;
padding: 0.5em;
display: block;
border : dashed 0.5px grey;
}
<p> list of KeyWords : 'text', 'another', 'word', 'here';</p>
<span id="my_text" contenteditable="true">Edit me using "reservedKeyWords" defined in JS</span>
Oh and note that I am using a span instead of a div, because div tag adds some <br> from nowhere after the textNode.
No this isn't a duplicate because all of the answers are different in other posts.
Does anyone know how to get replace something specific in a string? for example I'm trying to get rid of ALL commas that area together. Keep single commas but get rid of two only
For example:
w,h,o,,w,h,a,t,w,h,e,n,w,h,e,r,e,,t,h,e,n,,c,a,n,,b,u,t,,
I want to get rid of all instances where the double commas appear. Something kind of like:
var example = text.replace(/,,/g,' '); /*Space where ' ' is*/
If you understand what I mean. The next step is:
var text.replace(/,/g,'');
Thank you!
Code:
<html>
<head>
<script>
function decrypt() {
var input = document.getElementById("input").value;
var x = input.split(",");
var txtDisp="";
for(var i = 0; i < x.length; i++) {
if(x[i].type = "text") {
crack = 94-(x[i]-32)+32;
toTxt = String.fromCharCode(this, crack);
txtDisp = txtDisp+","+toTxt;
prep = txtDisp.replace(/,,/g,"");
}
document.getElementById("prompt").innerHTML=prep;
}
}
</script>
</head>
<body>
<textarea rows='4' cols='100' style='resize:none;' id='input'></textarea>
<br>
<input type='button' value='execute' onclick='decrypt()' />
<p id='prompt'>
</p>
</body>
</html>
P.s. this code is already posted somewhere else where I asked a question.
Why don't you do:
var text = "61,59,44,47,43,43, ,39,54,37, ,37,47,41,44, ,59,61,48, ,53,48,42,47, ,42,54,57,53,44, ,47,56,42,57,48, ,47,56,56, ,43,61,53,58, ,47,41,44, ,42,39,61,43, ,43,53,48,59,57, ,42,54,57,44,57, ,61,48,58, ,39,47,41,50,58";
example = text.split(",,").join("").split(", ,").join("");
the result is:
"w,h,ow,h,a,t,w,h,e,n,w,h,e,r,et,h,e,nc,a,nb,u,t"
I myself also tried to do it like:
example = text.replace(/,,/g,'').replace(/, ,/g,'');
the result was:
"w,h,ow,h,a,t,w,h,e,n,w,h,e,r,et,h,e,nc,a,nb,u,t"
I changed your code like this:
function decrypt() {
var val = document.getElementById("input").value;
var x = val.split(",");
var txtDisp = "";
for (var i = 0; i < x.length; i++) {
if (!isNaN(parseInt(x[i]))) {
var num = parseInt(x[i]);
crack = 94 - (num - 32) + 32;
toTxt = String.fromCharCode(this, crack);
txtDisp = txtDisp + "," + toTxt;
prep = txtDisp.replace(/,,/g, "").replace(/, ,/g, "");
}
document.getElementById("prompt").innerHTML = prep;
}
}
and it works. check this DEMO out.
Try this:
function decrypt() {
var input = document.getElementById("input").value;
var x = input.split(",");
var txtDisp = "";
for (var i = 0; i < x.length; i++) {
if (x[i] !== ' ') {
crack = 94 - (x[i] - 32) + 32;
toTxt = String.fromCharCode(this, crack);
txtDisp += "," + toTxt;
} else {
txtDisp += " ";
}
}
document.getElementById("prompt").innerHTML = txtDisp.replace(/,/g, "");
}
I have this in a Div (Text actually "wraps" because Div box has short width; except where line breaks are intentional):
"Now is the time
for all good men
to come to the aid
of their country"
"The quick brown fox
jumps over the
lazy dogs"
I would like this:
lazy dogs"
jumps over the
"The quick brown fox"
of their country"
to come to the aid
for all good men
"Now is the time
I've tried using Reverse(); but am not getting the desired results.
Note: I'm not trying to reverse a string per say, but actual lines of text (ie: sentences).
If you got line breaks like this \n, you can do the following:
var lineBreak = "\n",
text = "Now is the time\nfor all good men\nto come to the aid\nof their country";
text = text.split(lineBreak).reverse().join(lineBreak);
If the line break is another sign, change the variable lineBreak.
OK, got it eventually. Based on this answer of mine, I came up with a code that identifies the actual lines inside textarea, even when wrapped.
Next step was to translate div into textarea so we can use the above trick.
Having this, it's simple matter of manipulating the lines using .reverse() method.
Final code is:
$("#btnInvert").click(function() {
var placeholder = $("#MyPlaceholder");
if (!placeholder.length) {
alert("placeholder div doesn't exist");
return false;
}
var oTextarea = $("<textarea></textarea>").attr("class", placeholder.attr("class")).html(placeholder.text());
oTextarea.width(placeholder.width());
//important to assign same font to have same wrapping
oTextarea.css("font-family", placeholder.css("font-family"));
oTextarea.css("font-size", placeholder.css("font-size"));
oTextarea.css("padding", placeholder.css("padding"));
$("body").append(oTextarea);
//make sure we have no vertical scroll:
var rawTextarea = oTextarea[0];
rawTextarea.style.height = (rawTextarea.scrollHeight + 100) + "px";
var lines = GetActualLines(rawTextarea);
var paragraphs = GetParagraphs(lines).reverse();
lines = [];
for (var i = 0; i < paragraphs.length; i++) {
var reversedLines = paragraphs[i].reverse();
for (var j = 0; j < reversedLines.length; j++)
lines.push(reversedLines[j]);
if (i < (paragraphs.length - 1))
lines.push("");
}
rawTextarea.value = lines.join("\n");
placeholder.html(rawTextarea.value.replace(new RegExp("\\n", "g"), "<br />"));
oTextarea.remove();
});
function GetParagraphs(lines) {
var paragraphs = [];
var buffer = [];
$.each(lines, function(index, item) {
var curText = $.trim(item);
if (curText.length === 0) {
if (buffer.length > 0) {
paragraphs.push(buffer);
buffer = [];
}
} else {
buffer.push(curText);
}
});
if (buffer.length > 0)
paragraphs.push(buffer);
return paragraphs;
}
function GetActualLines(oTextarea) {
oTextarea.setAttribute("wrap", "off");
var strRawValue = oTextarea.value;
oTextarea.value = "";
var nEmptyWidth = oTextarea.scrollWidth;
var nLastWrappingIndex = -1;
for (var i = 0; i < strRawValue.length; i++) {
var curChar = strRawValue.charAt(i);
if (curChar == ' ' || curChar == '-' || curChar == '+')
nLastWrappingIndex = i;
oTextarea.value += curChar;
if (oTextarea.scrollWidth > nEmptyWidth) {
var buffer = "";
if (nLastWrappingIndex >= 0) {
for (var j = nLastWrappingIndex + 1; j < i; j++)
buffer += strRawValue.charAt(j);
nLastWrappingIndex = -1;
}
buffer += curChar;
oTextarea.value = oTextarea.value.substr(0, oTextarea.value.length - buffer.length);
oTextarea.value += "\n" + buffer;
}
}
oTextarea.setAttribute("wrap", "");
return oTextarea.value.split("\n");
}
Just put the actual ID of your div and it should work.
Live test case.
warning, this is pseudo code :
lines=[];
index=0;
start=0;
for(characters in alltext){
if(newLine){
lines.push(alltext.substring(start,index);
start=index;
}
i++
}
sortedLines=[]
for(var i=lines.length;i>-1;i--){
sortedLines.push(lines[i]);
html=$('selector').html();
html+=lines[i];
$('selector').append(html);
}
better use split
var a = document.querySelectorAll('.post .content div');
var b = a[7].childNodes;
for(i=0;i<b.length;i++){
var exp = /(\b(https?|ftp|file):\/\/[\-A-Z0-9+&##\/%?=~_|!:,.;]*[\-A-Z0-9+&##\/%=~_|])/ig;
if(b[i].nodeType === 3){
var ahref = document.createElement('a');
ahref.className="easyBBurlFetch";
ahref.href=b[i].nodeValue.replace(exp,'$1');
ahref.innerText=b[i].nodeValue.replace(exp,'$1');
b[i].parentNode.insertBefore(ahref,b[i]);
b[i].parentNode.removeChild(b[i].nextSibling);
}
}
Someone gave me the answer as I had this code though it wasn't working correct. Though I have the issue now if my text is like so:
This is just a test so click here www.youtube.com which then becomes
www.youtube.com%20which%20then%20becomes
It doesn't event keep the first line of text, I just need to parse the url while keeping the surrounding text.
In need the output to save the actual surrounding text but parse the urls that are inside the text to html anchor tags <a> so that they can then be clickable and actually follow through to a real website and not have unnessarcy text inside it from what my user was writing about. Thank you
UPDATE
I've got closer to making this work-- But I'm having a problem with the first text in the string is saying Undefined I've been debugging this and can't seem to figure out why this is happening. Here is code
var a = document.querySelectorAll('.post');
var b = a[0].childNodes;
var textArray;
var ahref;
for (i = 0; i < b.length; i++) {
var exp = /(\b(https?|ftp|file):\/\/[\-A-Z0-9+&##\/%?=~_|!:,.;]*[\-A-Z0-9+&##\/%=~_|])/ig;
if (b[i].nodeType === 3) {
var newHTML;
textArray = b[i].textContent.split(" ");
for (var j = 0; j < textArray.length; j++) {
if (textArray[j] !== "" && validURL(textArray[j])) {
ahref = document.createElement('a');
ahref.href = (/^(http:\/\/|https:\/\/)/).test(textArray[j]) ? textArray[j] : "http://" + textArray[j];
ahref.innerText = textArray[j];
ahref.className = "easyURLparse";
textArray[j] = ahref;
}
newHTML+= textArray[j].outerHTML ? textArray[j].outerHTML + " " : textArray[j] + " ";
}
var div = document.createElement('div');
div.innerHTML = newHTML;
newHTML = "";
b[i].parentNode.insertBefore(div, b[i]);
b[i].parentNode.removeChild(b[i].nextSibling);
}
}
function validURL(str) {
var pattern = new RegExp("([a-zA-Z0-9]+://)?([a-zA-Z0-9_]+:[a-zA-Z0-9_]+#)?([a-zA-Z0-9.-]+\\.[A-Za-z]{2,4})(:[0-9]+)?(/.*)?");
if (!pattern.test(str)) {
return false;
} else {
return true;
}
}
Testing Code
Just need to figure out the undefined and why it's adding it
this regexp will do the job
exp = /href="(\b(https?|ftp|file):\/\/[\-A-Z0-9+&##\/%?=~_|!:,.;]*[\-A-Z0-9+&##\/%=~_|])"/ig;
var a = document.querySelectorAll('.post');
var b = a[0].childNodes;
var textArray;
var ahref;
for (i = 0; i < b.length; i++) {
var exp = /(\b(https?|ftp|file):\/\/[\-A-Z0-9+&##\/%?=~_|!:,.;]*[\-A-Z0-9+&##\/%=~_|])/ig;
if (b[i].nodeType === 3) {
var newHTML;
if (validURL(b[i].textContent)) {
textArray = b[i].textContent.split(" ");
for (var j = 0; j < textArray.length; j++) {
if (textArray[j] !== undefined && textArray[j] !== "" && validURL(textArray[j]) && textArray[j] !== null) {
ahref = document.createElement('a');
ahref.href = (/^(http:\/\/|https:\/\/)/).test(textArray[j]) ? textArray[j] : "http://" + textArray[j];
ahref.innerText = textArray[j];
ahref.className = "easyURLparse";
textArray[j] = ahref;
}
newHTML += textArray[j].outerHTML ? textArray[j].outerHTML + " " : textArray[j] + " ";
}
var div = document.createElement('div');
div.innerHTML = newHTML;
div.className = "easyDiv";
b[i].parentNode.insertBefore(div, b[i]);
b[i].parentNode.removeChild(b[i].nextSibling);
}
newHTML = "";
}
}
function validURL(str) {
var pattern = new RegExp("([a-zA-Z0-9]+://)?([a-zA-Z0-9_]+:[a-zA-Z0-9_]+#)?([a-zA-Z0-9.-]+\\.[A-Za-z]{2,4})(:[0-9]+)?(/.*)?");
if (!pattern.test(str)) {
return false;
} else {
return true;
}
}
By taking the textNodes and splitting them into an array I can then change the url into an html element. Then taking the array elements seeing if there is outerHTML or not then placing it in a new string and replacing that textNode now with a workable link.
Working example
The following codes doesn't work and the result is broken because there are white spaces in a HTML tag.
HTML:
<div>Lorem ipsum <a id="demo" href="demo" rel="demo">dolor sit amet</a>, consectetur adipiscing elit.</div>
Javascript:
var div = document.getElementsByTagName('div')[0];
div.innerHTML = div.innerHTML.replace(/\s/g, '<span class="space"> </span>');
How to replace replace white spaces which are not in HTML tags?
It would be a better idea to actually use the DOM functions rather than some unreliable string manipulation using a regexp. splitText is a function of text nodes that allows you to split text nodes. It comes in handy here as it allows you to split at spaces and insert a <span> element between them. Here is a demo: http://jsfiddle.net/m5Qe8/2/.
var div = document.querySelector("div");
// generates a space span element
function space() {
var elem = document.createElement("span");
elem.className = "space";
elem.textContent = " ";
return elem;
}
// this function iterates over all nodes, replacing spaces
// with space span elements
function replace(elem) {
for(var i = 0; i < elem.childNodes.length; i++) {
var node = elem.childNodes[i];
if(node.nodeType === 1) {
// it's an element node, so call recursively
// (e.g. the <a> element)
replace(node);
} else {
var current = node;
var pos;
while(~(pos = current.nodeValue.indexOf(" "))) {
var next = current.splitText(pos + 1);
current.nodeValue = current.nodeValue.slice(0, -1);
current.parentNode.insertBefore(space(), next);
current = next;
i += 2; // childNodes is a live array-like object
// so it's necessary to advance the loop
// cursor as well
}
}
}
}
You can deal with the text content of the container, and ignore the markup.
var div = document.getElementsByTagName('div')[0];
if(div.textContent){
div.textContent=div.textContent.replace(/(\s+)/g,'<span class="space"> </span>';
}
else if(div.innerText){
div.innerText=div.innerText.replace(/(\s+)/g,'<span class="space"> </span>';
}
First split the string at every occurrence of > or <. Then fit together all parts to a string again by replacing spaces only at the even parts:
var div = document.getElementsByTagName('div')[0];
var parts = div.innerHTML.split(/[<>]/g);
var newHtml = '';
for (var i = 0; i < parts.length; i++) {
newHtml += (i % 2 == 0 ? parts[i].replace(/\s/g, '<span class="space"> </span>') : '<' + parts[i] + '>');
}
div.innerHTML = newHtml;
Also see this example.
=== UPDATE ===
Ok, the result of th IE split can be different then the result of split of all other browsers. With following workaround it should work:
var div = document.getElementsByTagName('div')[0];
var sHtml = ' ' + div.innerHTML;
var sHtml = sHtml.replace(/\>\</g, '> <');
var parts = sHtml.split(/[<>]/g);
var newHtml = '';
for (var i = 0; i < parts.length; i++) {
if (i == 0) {
parts[i] = parts[i].substr(1);
}
newHtml += (
i % 2 == 0 ?
parts[i].replace(/\s/g, '<span class="space"> </span>') :
'<' + parts[i] + '>'
);
}
div.innerHTML = newHtml;
Also see this updated example.
=== UPDATE ===
Ok, I have completly changed my script. It's tested with IE8 and current firefox.
function parseNodes(oElement) {
for (var i = oElement.childNodes.length - 1; i >= 0; i--) {
var oCurrent = oElement.childNodes[i];
if (oCurrent.nodeType != 3) {
parseNodes(oElement.childNodes[i]);
} else {
var sText = (typeof oCurrent.nodeValue != 'undefined' ? oCurrent.nodeValue : oCurrent.textContent);
var aParts = sText.split(/\s+/g);
for (var j = 0; j < aParts.length; j++) {
var oNew = document.createTextNode(aParts[j]);
oElement.insertBefore(oNew, oCurrent);
if (j < aParts.length - 1) {
var oSpan = document.createElement('span');
oSpan.className = 'space';
oElement.insertBefore(oSpan, oCurrent);
var oNew = document.createTextNode(' ');
oSpan.appendChild(oNew);
}
}
oElement.removeChild(oCurrent);
}
}
}
var div = document.getElementsByTagName('div')[0];
parseNodes(div);
Also see the new example.