In the below script I am trying to highlight all the words in a sentence
function SearchQueue(text)
{
if(text !== null)
{
text = text.replace(/“/g, "\"");
text = text.replace(/”/g, "\"");
text = text.replace(/’/g, "\'");
text = text.replace(/‘/g, "\'");
text = text.replace(/–/g, "\-");
text = text.replace(/ +(?= )/g,'');
$.trim(text);
text = text.replace(/\d\.\s+|[a-z]\)\s+|•\s+|[A-Z]\.\s+|[IVX]+\.\s+/g, "");
text = text.replace(/([0-9A-Z]+[.)]|•)\s+/gi, "");
text = text.replace(/(\r\n|\n|\r)/gm," ");
}
var words = text.split(' ');
for(var i=0;i<words.length;i++)
$('*').highlight(''+words[i]+''); // Will highlight the script with background color
}
But this is making my page "unresponsive". Please suggest me to improve the script...
You are selecting the entire dom tree in each iteration which may explain the unresponsiveness.
Try the following:
var body = $('body'); // since thats where all the text should live
for(var i=0;i<words.length;i++){
body.highlight(''+words[i]+''); // Will highlight the script with background color
}
Here's my first set of adjustments:
var $all = $('*');
function SearchQueue(text) {
if(text) {
text = text.replace(/[“”]/g, '"');
text = text.replace(/[’‘]/g, "'");
text = text.replace(/–/g, '-');
text = text.replace(/\s+/g, ' ');
$.trim(text);
text = text.replace(/\d\.\s+|[a-z]\)\s+|•\s+|[A-Z]\.\s+|[IVX]+\.\s+/g, '');
text = text.replace(/([0-9A-Za-z]+[.)]|•)\s+/g, '');
var words = text.split(' ');
for(var i = 0; i < words.length; i++) {
$all.highlight(words[i]); // Will highlight the script with background color
}
}
}
You can combine a few of your replaces using a match evaluator (don't know what javascript calls them).
example : http://jsfiddle.net/zyqVE/
function match_eval(m){
switch (m){
case "“":case "”":
return "\"";
case "‘":case "’":
return "'";
// etc...
}
return m;
}
alert("this “i“ a test".replace(/[““’‘–]/g, match_eval));
in context :
function match_eval(m){
switch (m){
case "“":case "”":
return "\"";
case "‘":case "’":
return "'";
case "–"
return "-";
}
return m;
}
function SearchQueue(text)
{
if(text !== null)
{
text = text.replace(/[“”’‘–]/g, match_eval);
text = text.replace(/ +(?= )/g,'');
$.trim(text);
text = text.replace(/\d\.\s+|[a-z]\)\s+|•\s+|[A-Z]\.\s+|[IVX]+\.\s+/g, "");
text = text.replace(/([0-9A-Z]+[.)]|•)\s+/gi, "");
text = text.replace(/(\r\n|\n|\r)/gm," ");
}
var words = text.split(' ');
for(var i=0;i<words.length;i++)
$('*').highlight(''+words[i]+''); // Will highlight the script with background color
}
Related
I am trying to split text with comma and show them as links. I am converting them as as text but don't know how to convert them into links. I am using this code.
$('.tags').keyup(function() {
var ref = $('.tags').val();
var str_array = ref.split(',');
for(var i = 0; i < str_array.length; i++) {
// Trim the excess whitespace.
str_array[i] = str_array[i].replace(/^\s*/, "").replace(/\s*$/, "");
// Add additional code here, such as:
$('.tag').html($(this).val());
}
});
What I am Getting is
<span class="tag">hello, world</span>
what I want is
<span class="tag">hello, world</span>
This solution is done with pure JS. No need for JQuery
var tags = document.getElementById("tags");
tags.addEventListener("keyup", convert);
function convert() {
let tag = document.getElementById('tag');
tag.innerHTML = "";
let str = tags.value;
let res = str.split(",");
res.forEach(function(element, idx, array) {
let comma;
idx === array.length - 1 ? comma = '' : comma = ' , ';
let trimmedElement = element.trim();
tag.innerHTML += ''+ trimmedElement +''+ comma ;
});
}
<input type="text" id="tags">
<span id="tag"></span>
You can do as follows in jQuery:
var ref = $('.tags').val();
var str_array = ref.split(',');
var tagLinks = '';
for(var i = 0; i < str_array.length; i++) {
// Trim the excess whitespace.
str_array[i] = str_array[i].replace(/^\s*/, "").replace(/\s*$/, "");
tagLinks += ''+str_array[i]+', ';
}
tagLinks = tagLinks.slice(0, -2);
$('.tag').html(tagLinks);
With jQuery:
// Element Selector
let selector = $(".tag");
// Get Text
let text = selector.text();
// Remove extra characters
text = text.replace(/[^a-zA-Z ]/ig, '');
// Convert my text to array
let tags = text.split(" ");
// Empty the element
selector.html('');
// Append Tags
tags.forEach(function(tag){
selector.append(`${tag} `)
});
I have text, in which on selection I need to replace the text.
Here my requirement is, the space must be remain same after replacing the characters which contains spaces between them.
JavaScript:
function getSel() {
// obtain the object reference for the textarea>
var txtarea = document.getElementById("mytextarea");
// obtain the index of the first selected character
var start = txtarea.selectionStart;
// obtain the index of the last selected character
var finish = txtarea.selectionEnd;
//obtain all Text
var allText = txtarea.value;
// obtain the selected text
var sel = Array(finish - start).join("*");
//append te text;
var newText = allText.substring(0, start) + sel + allText.substring(finish, allText.length);
txtarea.value = newText;
$('#newpost').offset({ top: 0, left: 0 }).hide();
}
$(document).ready(function () {
var position;
$('#newpost').hide();
$('#mytextarea').on('select', function (e) {
$('#newpost').offset(position).show();
var txtarea = document.getElementById("mytextarea");
var start = txtarea.selectionStart;
var finish = txtarea.selectionEnd;
$('#newpost p').text(Array(finish - start).join("*"));
}).on('mousedown', function (e) {
position = { top: e.pageY-5, left: e.pageX};
});
$('#newpost').hide();
});
Here is my plunker
I am getting output as shown in above image but in expected output the space must not be replaced with asterisk .
Use string.replace instead, try this:
console.log('g2ggg gggGG'.replace(/[a-zA-Z0-9]/g, '*'))
Your all string manipulation logic will be only 1 line:
newText = allText.replace(/[a-zA-Z0-9]/g, '*')
I'm not very good at regex so I used a for-loop but maybe this still helps you.
$(document).ready(function () {
$('#mytextarea').on('select', function (e) {
var $output = $("#output");
var $txtarea = $("#mytextarea");
var start = $txtarea[0].selectionStart;
var finish = $txtarea[0].selectionEnd;
var subtext = $txtarea.text().substr(start, finish);
var out = "";
for (var i = 0; i < subtext.length; i++) {
var char = subtext[i];
if (char == " ") {
out += " ";
} else {
out += "*";
}
}
$output.text(out);
});
});
Based on your code you can see the working example in this fiddle:
I've found this piece of code on the internet. It takes a sentence and makes every single word into link with this word. But it has weak side: if a sentence has HTML in it, this script doesn't remove it.
For example: it replaces '<b>asserted</b>' with 'http://www.merriam-webster.com/dictionary/<b>asserted</b>'
Could you please tell me what to change in this code for it to change '<b>asserted</b>' to 'http://www.merriam-webster.com/dictionary/asserted'.
var content = document.getElementById("sentence").innerHTML;
var punctuationless = content.replace(/[.,\/#!$%\؟^?&\*;:{}=\-_`~()”“"]/g, "");
var mixedCase = punctuationless.replace(/\s{2,}/g);
var finalString = mixedCase.toLowerCase();
var words = (finalString).split(" ");
var punctuatedWords = (content).split(" ");
var processed = "";
for (i = 0; i < words.length; i++) {
processed += "<a href = \"http://www.merriam-webster.com/dictionary/" + words[i] + "\">";
processed += punctuatedWords[i];
processed += "</a> ";
}
document.getElementById("sentence").innerHTML = processed;
This regex /<{1}[^<>]{1,}>{1}/g should replace any text in a string that is between two of these <> and the brackets themselves with a white space. This
var str = "<hi>How are you<hi><table><tr>I<tr><table>love cake<g>"
str = str.replace(/<{1}[^<>]{1,}>{1}/g," ")
document.writeln(str);
will give back " How are you I love cake".
If you paste this
var stripHTML = str.mixedCase(/<{1}[^<>]{1,}>{1}/g,"")
just below this
var mixedCase = punctuationless.replace(/\s{2,}/g);
and replace mixedCase with stripHTML in the line after, it will probably work
function stripAllHtml(str) {
if (!str || !str.length) return ''
str = str.replace(/<script.*?>.*?<\/script>/igm, '')
let tmp = document.createElement("DIV");
tmp.innerHTML = str;
return tmp.textContent || tmp.innerText || "";
}
stripAllHtml('<a>test</a>')
This function will strip all the HTML and return only text.
Hopefully, this will work for you
if you need to remove HTML tags And HTML Entities You can use
const text = '<p>test content </p><p><strong>test bold</strong> </p>'
text.replace(/<[^>]*(>|$)| ||»|«|>/g, '');
the result will be "test content test bold"
I have a contenteditable div
<div id="divTest" contenteditable="true">
I need to get the last word from caret position and on certain condition I have to test and remove this specific word only. Below is how am I doing
$('#divTest').on('keyup focus', function (e) {
if (e.keyCode == 32) {
var lastWord = getWordPrecedingCaret(this), spanLastWord = $('#lastWord');
}
});
function getWordPrecedingCaret(containerEl) {
var preceding = "",
sel,
range,
precedingRange;
if (window.getSelection) {
sel = window.getSelection();
if (sel.rangeCount > 0) {
range = sel.getRangeAt(0).cloneRange();
range.collapse(true);
range.setStart(containerEl, 0);
preceding = range.toString();
}
} else if ((sel = document.selection) && sel.type != "Control") {
range = sel.createRange();
precedingRange = range.duplicate();
precedingRange.moveToElementText(containerEl);
precedingRange.setEndPoint("EndToStart", range);
preceding = precedingRange.text;
}
var words = range.toString().trim().split(' '),
lastWord = words[words.length - 1];
if (lastWord) {
var resultValue = 'some'; // this value is coming from some other function
if (resultValue == lastWord) {
alert('do nothing');
// do nothing
}
else
{
alert('replace word');
// delete That specific word and replace if with resultValue
}
return lastWord;
}
}
Demo: http://codepen.io/anon/pen/ogzpXV
I have tried range.deleteContents(); but that will delete all the content in the div.
How can I replace specific word only?
To work with Ranges we need to keep in mind that we are working with Nodes, not only the text that is rendered. The structure you want to manipulate is:
<div id="divTest" contenteditable="true"> <-- Element Node
"some text" <-- TextNode
</div>
But it also could be:
<div id="divTest" contenteditable="true"> <-- Element Node
"some text" <-- TextNode
"more text" <-- TextNode
"" <-- TextNode
</div>
To solve your problem is simplier to handle only one TextNode, I propose to use the normalize() function to join all of them into a single one.
Then you only need to set the Range to the word's bounds before deleteContents(). Once deleted, you can insert a new TextNode with the substitution using insertNode().
var wordStart = range.toString().lastIndexOf(lastWord);
var wordEnd = wordStart + lastWord.length;
/* containerEl.firstChild refers to the div's TextNode */
range.setStart(containerEl.firstChild, wordStart);
range.setEnd(containerEl.firstChild, wordEnd);
range.deleteContents();
range.insertNode(document.createTextNode(resultValue));
For this to work, you need that the text is in a single TextNode. But after ìnsertNode the div will contain multiple text nodes. To fix this simply call normalize() to join all TextNode elements.
containerEl.normalize();
Edit:
As Basj points out, the original solution fails for multiline. That's because when hitting ENTER the structure changes from:
<div id="divTest" contenteditable="true"> <-- Element Node
"some text" <-- TextNode
</div>
to something like:
<div id="divTest" contenteditable="true"> <-- Element Node
<div>"some text"</div>
<div>"more text"</div>
</div>
I've updated this answer, but it's also worth to read Basj's answer at this question: Replace word before cursor, when multiple lines in contenteditable
JSFiddle demo or runnable code snippet:
document.getElementById('divTest').onkeyup = function (e) {
if (e.keyCode == 32) {
getWordPrecedingCaret(this);
}
};
function getWordPrecedingCaret(containerEl) {
var preceding = "",
sel,
range,
precedingRange;
if (window.getSelection) {
sel = window.getSelection();
if (sel.rangeCount > 0) {
range = sel.getRangeAt(0).cloneRange();
range.collapse(true);
range.setStart(containerEl, 0);
preceding = range.toString();
}
} else if ((sel = document.selection) && sel.type != "Control") {
range = sel.createRange();
precedingRange = range.duplicate();
precedingRange.moveToElementText(containerEl);
precedingRange.setEndPoint("EndToStart", range);
preceding = precedingRange.text;
}
var words = range.toString().trim().split(' '),
lastWord = words[words.length - 1];
if (lastWord) {
var resultValue = 'some'; // this value is coming from some other function
if (resultValue == lastWord) {
console.log('do nothing: ' + lastWord);
// do nothing
} else {
console.log('replace word ' + lastWord);
/* Find word start and end */
var wordStart = range.endContainer.data.lastIndexOf(lastWord);
var wordEnd = wordStart + lastWord.length;
console.log("pos: (" + wordStart + ", " + wordEnd + ")");
range.setStart(range.endContainer, wordStart);
range.setEnd(range.endContainer, wordEnd);
range.deleteContents();
range.insertNode(document.createTextNode(resultValue));
// delete That specific word and replace if with resultValue
/* Merge multiple text nodes */
containerEl.normalize();
}
return lastWord;
}
}
<div id="divTest" contenteditable="true">Write words here and hit SPACE BAR</div>
words = ['oele', 'geel', 'politie', 'foo bar'];
function markWords() {
var html = div.html().replace(/<\/?strong>/gi, ''),
text = html.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' '),
exp;
$.each(words, function(i, word) {
exp = new RegExp('\\b(' + word + ')\\b', 'gi');
html = html.replace(exp, function(m) {
console.log('WORD MATCH:', m);
return '<strong>' + m + '</strong>';
});
});
//html = html.replace(' ', ' ').replace(/\s+/g, ' ');
console.log('HTML:', html);
console.log('----');
div.html(html);
}
Call this function on setinterval
Fiddle
Tobías' solution works well for single-line contenteditable div. But if you add multiple lines, it doesn't work anymore.
Here is a general solution that works for both single-line or multiline contenteditable div.
I have a div which is content editable, and JS function to search the input for certain words. If a match is found, the content od the div turns blue, but I want only the matched word to turn blue. How can I do this?
Here is my JS...
function init() {
window.setInterval(function() {
var div = document.getElementById("texty");
var html = div.innerHTML;
var buzzword = ["function","()","{", "}","[", "]",".getElementById", ".getElementsByClassName",".style","$"];
for(var i = 0; i < buzzword.length; i++)
{
var regex = new RegExp(buzzword[i], 'g');
html = html.replace(regex, "<span style='color:blue'>" + buzzword[i] + "</span>");
}
div.innerHTML = html;
}, 100);
}
and my HTML is this...
<div id="texty" contenteditable="true" onfocus="init()"></div>
Get the html of the div then do a regex replace and add a span around the word. Code would look something like this:
var escape= function(s) {
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
};
var div = document.getElementById("texty");
var html = div.innerHTML;
var buzzword = ["function","()","{", "}","[", "]",".getElementById", ".getElementsByClassName",".style","$"];
for(var i = 0; i < buzzword.length; i++)
{
var regex = new RegExp(escape(buzzword[i]), 'g');
html = html.replace(regex, "<span style='color:blue'>" + buzzword[i] + "</span>");
}
div.innerHTML = html;