Lets say I have a text such as this
"This is a long text. It contains 150 characters. You can find more about this text on this link http://www.somewebsite.com/RDFCCSDVDS".
So in above text I want to find that link and convert it into a link so that when user clicks on it, the user will be taken directly to this website.
How can I achieve this goal?
Use regular expressions:
$('p').html(function(i, text) {
return text.replace(
/\bhttp:\/\/([\w\.-]+\.)+[a-z]{2,}\/.+\b/gi,
'$&'
);
});
demo
I suspect that I could much improve upon this, though at the minute this is the best I can offer (albeit I think that some kind of replace might work more efficiently):
var $words = $('p').text().split(' ');
for (i in $words) {
if ($words[i].indexOf('http://') == 0) {
$words[i] = '' + $words[i] + '';
}
}
$('p').html($words.join(' '));
JS Fiddle demo.
A slightly improved version of the above (but good lord, it's ugly...):
var punctuation = ['!',"'",'"',',','.'];
$('p').each(
function(){
$words = $(this).text().split(' ');
for (i in $words){
if ($.inArray($words[i].charAt(0),punctuation) > -1 && $words[i].indexOf('http://') == 1){
alert($words[i]);
}
else if ($.inArray($words[i].charAt($words[i].length - 1),punctuation) > -1 && ($words[i].indexOf('http://') == 1 || $words[i].indexOf('http://') == 0)){
$words[i] = '' + $words[i].substring(0,$words[i].length-1) + '' + $words[i].charAt($words[i].length-1);
}
else if ($words[i].indexOf('http://') == 0){
$words[i] = '' + $words[i] + '';
}
}
$(this).html($words.join(' '));
});
JS Fiddle demo.
I'm not quite sure what to do about quoted links, though (text such as "http://google.com", for example); and, honestly, I think that regex is probably the far, far better approach to this problem.
#Eric solution is brilliant, but I discovered that could be wrong if the url has spaces after it. Try his jsfiddle example with a text like this:
<p>This is a long text. It contains 150 characters. You can find more about this text on this link http://api.som-ewebsite.com/RDFCCS-VDS/#!/?p1=foo&p2=bar right here</p>
So I changed the latest part of the regex to intercept pretty much every URL-friendly character excluding the space, which is a url "terminator" to me (in the real world it's not, of course, but I couldn't find a way to separate normal spaces and spaces belonging to a URL in a plain text).
$('p').html(function(i, text) {
return text.replace(
/\bhttp:\/\/([\w\.-]+\.)+[a-z]{2,}([\/\w\.\-\_\?\=\!\#,\&]+)/gi,
'$&'
);
});
I think it can be improved, suggestions are welcome as always :)
EDITED:
Anyway, I think this is the best solution around: How to replace plain URLs with links?
using regular expression
var e = /http:\/\/([A-Za-z0-9\.-_]{2,}\.)+[A-Za-z]{2,}(\/.+)/,
s = "This is a long text. It contains 150 characters. You can find more about this text on this link http://www.somewebsite.com/RDFCCSDVDS";
if (s.match(e)) {
var url = RegExp['$&'];
s = s.replace(url, '' + url + '');
}
in jquery, you can use the tag in your selector to get all the links of the page ie.. $("a")
So if you want to do something to every link on the page, you could use
$("a").each(function() {
//your code here. you can access the link by using $(this)
});
Related
i would build a page with Bootstrap and i would use the navbar-search form for find the searched text in the same page.
What JS script i should use for do this?
I would that for every found text in the page the script add class "lead" to the p tag like this
<p class="lead">...</p>
How i can do this?
Thanks.
As Bootstrap requires jQuery for its plugins to work, I'll use it for your solution:
If your navbar-search is a class:
$(".navbar-search").on("keyup", function () {
var v = $(this).val();
$(".lead").removeClass("lead");
$("p").each(function () {
if (v != "" && $(this).text().search(v) != -1) {
$(this).addClass("lead");
}
});
});
Bear in mind that this will not look for words but for characters (so when you start typing say a, it will select both paragraphs straight away since both of them contain 'a'). If you want to search for words, you need to amend your code accordingly.
This solution is case-sensitive.
JSFiddle
So if you want to search for whole words, do this:
$(".navbar-search").on("keyup", function () {
var v = $(this).val();
$(".lead").removeClass("lead");
var re = new RegExp("\\b" + v + "\\b","g")
$("p").each(function () {
if (v != "" && $(this).text().search(re) != -1) {
$(this).addClass("lead");
}
});
});
Just bear in mind that you might want to escape your v before inserting it into the regexp if you expect people to search for something silly.
JSFiddle
I have a div tag with contenteditable set to true.
I am trying to find out the last entered word in the div.
For example, if I type in This is a test and I hit a space, I want to be able to get the word test
I want to be able to use this logic so that I can test each word being typed (after the space is pressed).
It would be great if someone could help me with this.
An easy solution would be the following
var str = "This is a test "; // Content of the div
var lastWord = str.substr(str.trim().lastIndexOf(" ")+1);
trim might need a shim for older browsers. (.replace(/\s$/,""))
To strip punctuation like " Test!!! " you could additionally do a replace like following:
lastWord.replace(/[\W]/g,"");
You might want to do a more specific definition of the characters to omit than \W, depending on your needs.
If you want to trigger your eventhandler also on punctuation characters and not only on space, the last replace is not needed.
You first have to know when the content is edited. Using jQuery, that can be done with
$("div").on("keyup", function(){ /* code */ });
Then, you'll have to get the whole text and split it into words
var words = $(this).text().trim().split(' ');
And getting the last word is as complicated as getting the last element of the words array.
Here's the whole code
HTML
<div contenteditable="true">Add text here</div>
JavaScript (using jQuery)
$("div").on("keyup", function(){
var words = $(this).text().trim().split(' '),
lastWord = words[words.length - 1];
console.log(lastWord);
});
Demo
This is the ultimate way:
// listen to changes (do it any way you want...)
document.querySelectorAll('div')[0].addEventListener('input', function(e) {
console.log( getLastWord(this.textContent) );
}, false);
function getLastWord(str){
// strip punctuations
str = str.replace(/[\.,-\/#!$%\^&\*;:{}=\_`~()]/g,' ');
// get the last word
return str.trim().split(' ').reverse()[0];
}
DEMO PAGE
You can try this to get last word from a editable div.
HTML
<div id='edit' contenteditable='true' onkeypress="getLastWord(event,this)">
</div>
JS
function getLastWord(event,element){
var keyPressed = event.which;
if(keyPressed == 32){ //Hits Space
var val = element.innerText.trim();
val = val.replace(/(\r\n|\n|\r)/gm," ");
var idx = val.lastIndexOf(' ');
var lastWord = val.substring(idx+1);
console.log("Last Word " + lastWord);
}
}
Try this link http://jsfiddle.net/vV2mN/18/
Lets say we have a <div style="width:100px;">This text is too long to fit</div>
The text in the div is dynamic. And I'd like to force the text to fit in width and not break.
So i need some kind of functionality to test if the text is going to fit, and if it is not, then i'd like to display the portion of the text that will actually fit. And append ...to the end.
Result for a too long text should be something like this: "This text is..."
Is there some standard way of doing what i want? Either by javascript, jquery, jsp or java?
Thanks!
Edit:
Thanks for your quick and many answers! I was doing this in java by guessing how many characters would fit. It seemed like a less than optimal solution, so thats why i came here.
The css solution is perfect for me. Its not that big of a deal that it doesnt work for firefox, since my clients all use ie anyway. :)
you could do it with css3 using text-overflow:ellipsis http://www.css3.com/css-text-overflow/
or if you insist on using the js way, you can wrap the text-node inside your div and then compare the width of the wrap with the with of the parent.
If you want to process the data you can use a function:
function TextAbstract(text, length) {
if (text == null) {
return "";
}
if (text.length <= length) {
return text;
}
text = text.substring(0, length);
last = text.lastIndexOf(" ");
text = text.substring(0, last);
return text + "...";
}
text = "I am not the shortest string of a short lenth with all these cows in here cows cows cows cows";
alert(TextAbstract(text,20));
EDIT: process all div with excess length in the text:
var maxlengthwanted=20;
$('div').each(function(){
if ($('div').text().length > maxlengthwanted)
$(this).text(TextAbstract($(this).text()));
});
EDIT: More compact version to process all div with excess length in the text, breaks on space.
function textAbstract(el, maxlength = 20, delimiter = " ") {
let txt = $(el).text();
if (el == null) {
return "";
}
if (txt.length <= maxlength) {
return txt;
}
let t = txt.substring(0, maxlength);
let re = /\s+\S*$/;
let m = re.exec(t);
t = t.substring(0, m.index);
return t + "...";
}
var maxlengthwanted = 23;
$('.makeshort').each(function(index, element) {
$(element).text(textAbstract(element, maxlengthwanted, " "));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="makeshort">This is a fun thing to process, modification of this is going to just be soo much fun</div>
<div class="makeshort">second This is a fun thing to process, modification of this is going to just be soo much fun</div>
<div class="makeshort">IBShort Wilson</div>
<div class="makeshort">another This is a fun thing to process, modification of this is going to just be soo much fun</div>
<div class="makeshort">more This is a fun thing to process, modification of this is going to just be soo much fun</div>
<span class="makeshort">Me also, a span that is a fun thing to process, modification of this is going to just be soo much fun</span>
<span class="makeshort">more This is a fun thing to process, modification of this is going to just be soo much fun</span>
<ul>
<li class="makeshort">li1 more This is a fun thing to process, modification of this is going to just be soo much fun</li>
<li class="makeshort">li 2 more This
is a
fun thing to process, modification of this is going to just be soo much fun</li>
<li class="makeshort">li 3 also moreThis is a fun thing to process, modification of this is going to just be soo much fun</li>
<li class="makeshort">li 4 also more This is fun thing to process, modification of this is going to just be soo much fun</li>
</ul>
if(text.length > number_of_characters) {
text = text.substring(from, to);
}
One liner using JavaScript
The below truncates the string to 10 characters with an ellipsis. If the length of the truncated string is below the limit (10 in the example below) then no ellipsis is added to the output.
const output = "abcdefghijk".split('', 10).reduce((o, c) => o.length === 9 ? `${o}${c}...` : `${o}${c}` , '');
Easiest way to shorten the variable using JavaScript:
function truncate(string, length){
if (string.length > length)
return string.substring(0,length)+'...';
else
return string;
};
Inspired by this answer: I want to truncate a text or line with ellipsis using JavaScript
If the string is a one-liner you can use the CSS solution. If its a multiline string you need to clip, i prefer using a lightweight JS plugin called cuttr.js.
Just a minimum of code needed to get it done. You could even omit the endingoption, because the three dots are the default output.
Vanilla JS implementation:
new Cuttr('.selector', {
length: 15,
ending: '...'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/cuttr/1.3.2/cuttr.min.js"></script>
<div class="selector" style="width:100px;">This text is too long to fit</div>
jQuery implementation:
$('.selector').Cuttr({
length: 15,
ending: '...'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cuttr/1.3.2/cuttr.min.js"></script>
<div class="selector" style="width:100px;">This text is too long to fit</div>
Simply add a class to the div and init the plugin. You can read more about truncating a text or line with ellipsis on the plugins website or github page - there are multiple ways to clip the string, even without messing up HTML tags.
text-overflow: ellipis
div {
text-overflow: ellipsis
}
Will be supported in FireFox 7 http://caniuse.com/#search=text-overflow
If you add an id tag to the div, you can use document.getElementById("divid").innerHTML to get the contents of the div. From there, you can use .length to get the length of the string. If the length of the string is over a certain threshold, just take a substring and append a "...".
You should try to do this server-side if you can, though. Relying on Javascript/CSS to format it correctly for the user is a less than ideal solution.
Try the CSS text-overflow property.
A more likely situation is that you can't possibly know how many characters are going to fit in a dom element, given it has its own font and so on. CSS3 is not currently an option (for me anyway). So, I create a little div offscreen and keep jamming test strings into it until the width is correct:
var text = 'Try to fit this text into 100 pixels!';
var max_width = 100;
var test = document.createElement('div');
test.className = 'Same Class as your real element'; // give it the same font, etc as a normal button
test.style.width = 'auto';
test.style.position = 'absolute';
test.style.left = '-2000px';
document.body.appendChild(test);
test.innerHTML = text;
if ($(test).width() > max_width) {
for (var i=text.length; i >= 0; i--) {
test.innerHTML = text.substring(0, i) + '...';
if ($(test).width() <= max_width) {
text = text.substring(0, i) + '...';
break;
}
}
}
document.body.removeChild(test);
I am using a 'contenteditable' <div/> and enabling PASTE.
It is amazing the amount of markup code that gets pasted in from a clipboard copy from Microsoft Word. I am battling this, and have gotten about 1/2 way there using Prototypes' stripTags() function (which unfortunately does not seem to enable me to keep some tags).
However, even after that, I wind up with a mind-blowing amount of unneeded markup code.
So my question is, is there some function (using JavaScript), or approach I can use that will clean up the majority of this unneeded markup?
Here is the function I wound up writing that does the job fairly well (as far as I can tell anyway).
I am certainly open for improvement suggestions if anyone has any. Thanks.
function cleanWordPaste( in_word_text ) {
var tmp = document.createElement("DIV");
tmp.innerHTML = in_word_text;
var newString = tmp.textContent||tmp.innerText;
// this next piece converts line breaks into break tags
// and removes the seemingly endless crap code
newString = newString.replace(/\n\n/g, "<br />").replace(/.*<!--.*-->/g,"");
// this next piece removes any break tags (up to 10) at beginning
for ( i=0; i<10; i++ ) {
if ( newString.substr(0,6)=="<br />" ) {
newString = newString.replace("<br />", "");
}
}
return newString;
}
Hope this is helpful to some of you.
You can either use the full CKEditor which cleans on paste, or look at the source.
I am using this:
$(body_doc).find('body').bind('paste',function(e){
var rte = $(this);
_activeRTEData = $(rte).html();
beginLen = $.trim($(rte).html()).length;
setTimeout(function(){
var text = $(rte).html();
var newLen = $.trim(text).length;
//identify the first char that changed to determine caret location
caret = 0;
for(i=0;i < newLen; i++){
if(_activeRTEData[i] != text[i]){
caret = i-1;
break;
}
}
var origText = text.slice(0,caret);
var newText = text.slice(caret, newLen - beginLen + caret + 4);
var tailText = text.slice(newLen - beginLen + caret + 4, newLen);
var newText = newText.replace(/(.*(?:endif-->))|([ ]?<[^>]*>[ ]?)|( )|([^}]*})/g,'');
newText = newText.replace(/[·]/g,'');
$(rte).html(origText + newText + tailText);
$(rte).contents().last().focus();
},100);
});
body_doc is the editable iframe, if you are using an editable div you could drop out the .find('body') part. Basically it detects a paste event, checks the location cleans the new text and then places the cleaned text back where it was pasted. (Sounds confusing... but it's not really as bad as it sounds.
The setTimeout is needed because you can't grab the text until it is actually pasted into the element, paste events fire as soon as the paste begins.
How about having a "paste as plain text" button which displays a <textarea>, allowing the user to paste the text in there? that way, all tags will be stripped for you. That's what I do with my CMS; I gave up trying to clean up Word's mess.
You can do it with regex
Remove head tag
Remove script tags
Remove styles tag
let clipboardData = event.clipboardData || window.clipboardData;
let pastedText = clipboardData.getData('text/html');
pastedText = pastedText.replace(/\<head[^>]*\>([^]*)\<\/head/g, '');
pastedText = pastedText.replace(/\<script[^>]*\>([^]*)\<\/script/g, '');
pastedText = pastedText.replace(/\<style[^>]*\>([^]*)\<\/style/g, '');
// pastedText = pastedText.replace(/<(?!(\/\s*)?(b|i|u)[>,\s])([^>])*>/g, '');
here the sample : https://stackblitz.com/edit/angular-u9vprc
I did something like that long ago, where i totally cleaned up the stuff in a rich text editor and converted font tags to styles, brs to p's, etc, to keep it consistant between browsers and prevent certain ugly things from getting in via paste. I took my recursive function and ripped out most of it except for the core logic, this might be a good starting point ("result" is an object that accumulates the result, which probably takes a second pass to convert to a string), if that is what you need:
var cleanDom = function(result, n) {
var nn = n.nodeName;
if(nn=="#text") {
var text = n.nodeValue;
}
else {
if(nn=="A" && n.href)
...;
else if(nn=="IMG" & n.src) {
....
}
else if(nn=="DIV") {
if(n.className=="indent")
...
}
else if(nn=="FONT") {
}
else if(nn=="BR") {
}
if(!UNSUPPORTED_ELEMENTS[nn]) {
if(n.childNodes.length > 0)
for(var i=0; i<n.childNodes.length; i++)
cleanDom(result, n.childNodes[i]);
}
}
}
This works great to remove any comments from HTML text, including those from Word:
function CleanWordPastedHTML(sTextHTML) {
var sStartComment = "<!--", sEndComment = "-->";
while (true) {
var iStart = sTextHTML.indexOf(sStartComment);
if (iStart == -1) break;
var iEnd = sTextHTML.indexOf(sEndComment, iStart);
if (iEnd == -1) break;
sTextHTML = sTextHTML.substring(0, iStart) + sTextHTML.substring(iEnd + sEndComment.length);
}
return sTextHTML;
}
Had a similar issue with line-breaks being counted as characters and I had to remove them.
$(document).ready(function(){
$(".section-overview textarea").bind({
paste : function(){
setTimeout(function(){
//textarea
var text = $(".section-overview textarea").val();
// look for any "\n" occurences and replace them
var newString = text.replace(/\n/g, '');
// print new string
$(".section-overview textarea").val(newString);
},100);
}
});
});
Could you paste to a hidden textarea, copy from same textarea, and paste to your target?
Hate to say it, but I eventually gave up making TinyMCE handle Word crap the way I want. Now I just have an email sent to me every time a user's input contains certain HTML (look for <span lang="en-US"> for example) and I correct it manually.
I was wondering if it is possible to use JavaScript to add a <div> tag around a word in an HTML page.
I have a JS search that searches a set of HTML files and returns a list of files that contain the keyword. I'd like to be able to dynamically add a <div class="highlight"> around the keyword so it stands out.
If an alternate search is performed, the original <div>'s will need to be removed and new ones added. Does anyone know if this is even possible?
Any tips or suggestions would be really appreciated.
Cheers,
Laurie.
In general you will need to parse the html code in order to ensure that you are only highlighting keywords and not invisible text or code (such as alt text attributes for images or actual markup). If you do as Jesse Hallett suggested:
$('body').html($('body').html().replace(/(pretzel)/gi, '<b>$1</b>'));
You will run into problems with certain keywords and documents. For example:
<html>
<head><title>A history of tables and tableware</title></head>
<body>
<p>The table has a fantastic history. Consider the following:</p>
<table><tr><td>Year</td><td>Number of tables made</td></tr>
<tr><td>1999</td><td>12</td></tr>
<tr><td>2009</td><td>14</td></tr>
</table>
<img src="/images/a_grand_table.jpg" alt="A grand table from designer John Tableius">
</body>
</html>
This relatively simple document might be found by searching for the word "table", but if you just replace text with wrapped text you could end up with this:
<<span class="highlight">table</span>><tr><td>Year</td><td>Number of <span class="highlight">table</span>s made</td></tr>
and this:
<img src="/images/a_grand_<span class="highlight">table</span>.jpg" alt="A grand <span class="highlight">table</span> from designer John <span class="highlight">Table</span>ius">
This means you need parsed HTML. And parsing HTML is tricky. But if you can assume a certain quality control over the html documents (i.e. no open-angle-brackets without closing angle brackets, etc) then you should be able to scan the text looking for non-tag, non-attribute data that can be further-marked-up.
Here is some Javascript which can do that:
function highlight(word, text) {
var result = '';
//char currentChar;
var csc; // current search char
var wordPos = 0;
var textPos = 0;
var partialMatch = ''; // container for partial match
var inTag = false;
// iterate over the characters in the array
// if we find an HTML element, ignore the element and its attributes.
// otherwise try to match the characters to the characters in the word
// if we find a match append the highlight text, then the word, then the close-highlight
// otherwise, just append whatever we find.
for (textPos = 0; textPos < text.length; textPos++) {
csc = text.charAt(textPos);
if (csc == '<') {
inTag = true;
result += partialMatch;
partialMatch = '';
wordPos = 0;
}
if (inTag) {
result += csc ;
} else {
var currentChar = word.charAt(wordPos);
if (csc == currentChar && textPos + (word.length - wordPos) <= text.length) {
// we are matching the current word
partialMatch += csc;
wordPos++;
if (wordPos == word.length) {
// we've matched the whole word
result += '<span class="highlight">';
result += partialMatch;
result += '</span>';
wordPos = 0;
partialMatch = '';
}
} else if (wordPos > 0) {
// we thought we had a match, but we don't, so append the partial match and move on
result += partialMatch;
result += csc;
partialMatch = '';
wordPos = 0;
} else {
result += csc;
}
}
if (inTag && csc == '>') {
inTag = false;
}
}
return result;
}
Wrapping is pretty easy with jQuery:
$('span').wrap('<div class="highlight"></div>'); // wraps spans in a b tag
Then, to remove, something like this:
$('div.highlight').each(function(){ $(this).after( $(this).text() ); }).remove();
Sounds like you will have to do some string splitting, though, so wrap may not work unless you want to pre-wrap all your words with some tag (ie. span).
The DOM API does not provide a super easy way to do this. As far as I know the best solution is to read text into JavaScript, use replace to make the changes that you want, and write the entire content back. You can do this either one HTML node at a time, or modify the whole <body> at once.
Here is how that might work in jQuery:
$('body').html($('body').html().replace(/(pretzel)/gi, '<b>$1</b>'));
couldn't you just write a selector as such to wrap it all?
$("* :contains('foo')").wrap("<div class='bar'></div>");
adam wrote the code above to do the removal:
$('div.bar').each(function(){ $(this).after( $(this).text() ); }).remove();
edit: on second thought, the first statement returns an element which would wrap the element with the div tag and not the sole word. maybe a regex replace would be a better solution here.