How do i use javascript/jquery to select all $('td.created') and split the html on <br>, then wrap each section in span tags (so that i can add a class to span:first in order to style it).
The format of the string which is returned from $('td.created').html() is something like
posted by User123 <br> Posted on 1/2/12 at 4:15PM
Possible universal solution (works not only for 2 lines):
$("td.created").each(function() {
var text = this.innerHTML.split("<br>");
for (var i = 0; i < text.length; i++) {
var span = $("<span />").html(text[i]);
if (i == 0) span.addClass("first");
span.appendTo("#element");
}
});
DEMO: http://jsfiddle.net/7xQAL/
$('td.created').each(function(i, html) {
var newHtml = $(this).contents(),
spans = [];
newHtml.each(function() {
var html = (this.nodeName.toLowerCase() == 'br') ? '<br>' : '<span>' + this.textContent + '</span>';
spans.push(html);
});
$(this).html(spans.join(''));
});
DEMO ( using DIV Container)
http://jsfiddle.net/PVLek/
Related
I am trying to make a hashtag system, so I reached the edit text feature where I want to replace the entered edit with hashtag links if the user type hashtag words. So I am using JavaScript and jQuery to do this but the problem is that the for loop is only replacing the last word in the string and not all the string with a links.
// Turn hashtags into links
var discussionText = "#example #text #string #one #two #three #hashtag #word";
var wordsArray = discussionText.split(" ");
for (i = 0; i < wordsArray.length; i++) {
console.log(i);
if (wordsArray[i].indexOf('#') > -1) {
var wordWithoutHashtag = wordsArray[i].replace("#", "");
console.log(wordWithoutHashtag);
$("#" + editDiscussionButtonId + "-" + editDiscussionButtonUserId + "-spanDiscussionEdit").html(function() {
return $(this).text().replace(wordsArray[i], "<a href='search.php?sec=all&q=" + wordWithoutHashtag + "' class='hashtag_link'>" + wordsArray[i] + "</a>");
});
}
}
Change the html(function) to use the existing html argument. When you use text() it doesn't return the previous <a> you created in previous iterations of the loop, only the text inside the <a>.
$(selector).html(function(index, existingHtml){
return existingHtml.replace(wordsArray[i], ....
});
Similarly if you just changed $(this).text().replace.. to $(this).html().replace... it would work.
A more efficient approach would be the get the existing content once before the loop and do all the modifications to the string stored in variable, then replace the modified content once after the loop completes
After i posted this question, i continue trying with solutions until i came up with the below which works perfectly for all cases tags
var discussionText = "#example #text #string #one #two #three #hashtag #word";
var wordsArray = discussionText.split(" ");
var fullText = "";
for(i=0; i < wordsArray.length; i++) {
if (wordsArray[i].indexOf('#') > -1) {
var wordWithoutHashtag = wordsArray[i].replace("#", "");
var wordLink = wordsArray[i].replace(wordsArray[i], "<a href='search.php?sec=all&q="+wordWithoutHashtag+"' class='hashtag_link'>"+wordsArray[i]+"</a>");
fullText += " " + wordLink;
$("#"+editDiscussionButtonId+"-"+editDiscussionButtonUserId+"-spanDiscussionEdit").html(fullText);
} else {
fullText += " "+wordsArray[i];
}
}
I have the following javascript function that aims to append a BIDI code to text that matches a specific criteria.The problem with the current function is that it works great with text only content but is problematic with content that has HTML Content. To summarize, I am splitting the text into words and checking if any of the characters in each word is matching a certain criteria to append the BIDI code to it.
The current status:
<div>This is the text that I am processing</div> //This works great
<div><span>This is the text</span><p>that I am processing</p></div> // This doesn't work well.
I want the function to work is for the text but also to keep the wrapping HTML tags in their place in order to keep etc....
function flipper(flipselector) {
var pagetitle = $(flipselector);
var text = pagetitle.text().split(' '); //I know that I am using text function here but .html didn't work either
var newtext="";
for( var i = 1, len = text.length; i < len; i=i+1 ) {
//text[i] = '<span>' + text[i] + '</span>';
newstring="";
if (matches = text[i].match(/\d/))
{
var currentstring=text[i];
for (var x = 0, charlen = currentstring.length; x < charlen; x++) {
if (matches = currentstring[x].match(/\d/)) {
varnewchar=currentstring[x];
}else {
varnewchar= "" + currentstring[x];
}
newstring=newstring + varnewchar;
}
} else {
newstring= text[i];
}
newtext=newtext + " " + newstring;
}
pagetitle.html(newtext);
}
I want to replace all matched text with another text, but I don't want replace if that text is in the alt or href attribute.
Example:
<p>Hello world!</p>
<p><img src="hello.jpg" alt="Hello"/></p>
Hello
My code:
var replacepattern = new RegExp('Hello', 'gi');
newcontent = newcontent.replace(replacepattern, function(match, contents, offset, s) {
var link = 'demo.com'
index++;
if (link != '') {
return '' + match + '';
} else {
return match;
}
});
It works perfect with text only. How can I match text except img src, alt etc?
You can use jQuery itself to help you with the replacement:
$(html)
.contents()
.filter(function() {
return this.nodeType == 1 || this.nodeType == 3;
}).each(function() {
this.textContent = this.textContent.replace(replacepattern, 'whatever');
});
Note that the last occurrence of Hello is not replaced, because it's technically invalid to have a text node as a child of <body>.
Also, you would have to modify it to work in IE < 9 or 10; basically the browser is expected to support node.textContent :)
Update
The problem was slightly more complicated; or maybe my mind is making it more difficult than it is. Replacing text nodes with jQuery ain't the easiest to do, so some pure JS is required for that:
$('<div><p>Hello world!</p><p><img src="hello.jpg" alt="Hello"/></p>Hello</div>')
.find('*')
.andSelf()
.each(function() {
for (var i = 0, nodes = this.childNodes, n = nodes.length; i < n; ++i) {
if (nodes[i].nodeType == 3) {
var txt = nodes[i].textContent || nodes[i].innerText,
newtxt = txt.replace(/Hello/g, 'Bye');
if (txt != newtxt) {
var txtnode = document.createTextNode(newtxt);
this.replaceChild(txtnode, nodes[i]);
}
}
}
})
.end()
.end()
.appendTo('body');
<p class="example">i want to split this paragraph into
words and fade them in one by one</p>
the jquery/js:
$(document).ready(function() {
var $txt = $(".example")
,$words = $txt.text()
,$splitWords = $words.split(" ");
$txt.hide();
for(i = 0; i < $splitWords.length; i++){
// i want fade in each $splitWords[i]
//$splitWords[i].fadeIn(.... - i tried this doesnt work
}
});
im trying to split the paragraph into words, and fade them in one by one, thier might be an easier way to do this without splitting the words, please shed some light on this. thanks
Text by itself can't have an opacity, therefore you must wrap the text with an element that can have opacity (such as a span). You can then fade in those spans.
Try this:
http://jsfiddle.net/6czap/
var $el = $(".example:first"), text = $el.text(),
words = text.split(" "), html = "";
for (var i = 0; i < words.length; i++) {
html += "<span>" + words[i] + " </span>";
}
$el.html(html).children().hide().each(function(i){
$(this).delay(i*500).fadeIn(700);
});
Update for benekastah: http://jsfiddle.net/6czap/3/
var $el = $(".example:first"), text = $.trim($el.text()),
words = text.split(" "), html = "";
for (var i = 0; i < words.length; i++) {
html += "<span>" + words[i] + ((i+1) === words.length ? "" : " ") + "</span>";
};
$el.html(html).children().hide().each(function(i){
$(this).delay(i*200).fadeIn(700);
});
$el.find("span").promise().done(function(){
$el.text(function(i, text){
return $.trim(text);
});
});
You will need to fade in elements, text nodes can't have a opacity.
See demo at jsfiddle.net
var p = $("p.example").hide(); // possible flash! You should add some script
// to the <head> that writes a stylesheet
// to hide them right from the start
(function oneParagraph(i) {
if (p.length <= i)
return;
var cur = p.eq(i),
words = cur.text().split(/\s/),
span = $("<span>"),
before = document.createTextNode("");
cur.empty().show().append(before, span);
(function oneWord(j) {
if (j < words.length) {
span.hide().text(words[j]).fadeIn(200, function() {
span.empty();
before.data += words[j]+" ";
oneWord(j+1);
});
} else {
span.remove();
before.data = words.join(" ");
setTimeout(function(){
oneParagraph(i+1);
}, 500);
}
})(0);
})(0);
If you need only one paragraph, you can leave out all the things beloning to the oneParagraph function - just make cur the selected element.
If you want to have a smoother animation, you'd need to animate multiple words at the same time (demo), or dont fade but append letterwise like in here. Alternatively you could make the fading-time dependent on the length of the current word.
You'll have a couple problems with the suggestions mentioned so far.
First, splitting and then hiding the text in Javascript will result in a Flash of Unstyled Content. Second, the number of reflows is going to be pretty bad for long text.
Rather than hiding the text, consider setting the foreground and background to the same color, and then changing it back.
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.