how to search and replace through an entire block of text? - javascript

I'm trying to replace every image tag in a block of text with a unique string. So far I've tried to get the index of the beginning and end of a tag, create a substring, and then replace the substring. The problem is that I cannot do this an infinite number of times (the text block itself can be long with an n number of image tags).
Here is my code so far:
var txtBlock = currBlock.getElementsByClassName("txtContent")[0];
var imgStartPoint = txtBlock.indexOf("<img ");
var imgEndPoint = txtBlock.indexOf(" />");
var imgstring = txtBlock.substring(imgStartPoint, imgEndPoint);
How can I repeat this process n number of times?

The best way to approach this problem, and most programming problems in general, is to think about what you need to do and write out the steps that you need to perform in order to solve your problem in plain English.
To get you started, you should probably think about the following:
How many times does the code need to execute? How do you determine this?
How does the algorithm know that it is done? Can you think of a couple ways to achieve this?
Once you have a decent logical plan, the code will be much easier to write.
In general, break the problem down to smaller tasks and you should be able to tackle almost any programming problem, regardless of language, etc.
Let me know if you need further help.

It seems that you get your data from a DOM. So you can make yourself familiarly with the DOM operations and replace all image nodes with text nodes.
Helpful methodes:
DOM Document getElementsByTagName Method -
http://w3schools.com/jsref/met_document_getelementsbytagname.asp
DOM Node replaceChild Method -
http://w3schools.com/jsref/met_node_replacechild.asp
DOM Document createTextNode Method -
http://w3schools.com/jsref/met_document_createtextnode.asp

Related

Javascript alternative to document.write not innerHTML

I modified a little js script which compares a date to today and calculates the difference. (I'm a novice)
However, it uses document.write, which I've been told is bad.
I don't know why it's bad, people just say it's bad and never explain why.
Anyway, I'm looking for an alternative. innerHTML doesn't seem to work, and other questions answered on this site just point to DOM manipulation references without really answering the question.
Here's my script:
//Set the two dates
var iquit =new Date(2013, 1, 15);
today=new Date();
//Get 1 day in milliseconds
var one_day=1000*60*60*24;
var day_numeric=Math.ceil((today.getTime()-iquit.getTime())/(one_day));
//Calculate difference btw the two dates, and convert to days
document.write("<p>"+day_numeric+
" days have gone by since you quit smoking!</p>"+
"<p>You have saved "+ day_numeric*7+" pounds</p>");
If anyone can tell me a better way to write this, it'd be amazing.
The problem with document.write() is that if you call it after the DOM is ready, it will overwrite the existing DOM. This SO answer has a more extensive explanation to why document.write() rarely is the best choice.
Using .innerHTML should work fine, but you need to select the element you want to add the content do. So something like this:
document.getElementById("idOfSomeElement").innerHTML = "your content";
Live example
What method to use to get the proper element depends on what you have to select on, but if possible, the easiest way is probably to attach an ID to the element you want to add content to, and use the above method.
If you're using pure JavaScript, one of best ways to get this may be:
var paragraph1 = document.createElement("p");
paragraph1.appendChild(document.createTextNode(day_numeric+" days have gone by since you quit smoking!"));
var paragraph2 = document.createElement("p");
paragraph1.appendChild(document.createTextNode("You have saved "+ day_numeric*7+" pounds"));
document.body.appendChild(paragraph1);
document.body.appendChild(paragraph2);
100% standard DOM.
About document.write: good or evil...
I guess some consider document.write as a bad practice because it's the lower-level way of output raw content to the (X)HTML document.
Since (X)HTML is basically a dialect of XML (or at least, based on XML and SGML), the right and expected way of writing a document is creating nodes and appending them to the whole document.
document.write writes the content after the last written element and you lose a lot of control when you want to decide where to place the newly-created element in the document.
For example, would you output a paragraph from a JavaScript function loaded in the from the <head> element? It would be hard as it'll not be rendered in the body necessarily. That's too bad.
It's better to create DOM elements/nodes and append them to the document using appendChild(...).
Check this link for reasons why it is considered bad practice: Why is document.write considered a "bad practice"?
And how are you using innerHTML?
Have you tryed something like
<script>
...
document.getElementById('container-id').innerHTML = "<p>"+day_numeric+" days have gone by since you quit smoking!</p>"+"<p>You have saved "+ day_numeric*7+" pounds</p>";
</script>
This requires an element with the container-id id somewhere in the page, like:
<div id='container-id'></div>

different ways to append html?

I just wanted to know the differences between the methods of adding html in jquery.
both will do samething right?
$('body').append($("<div><img src='somesource' alt='something'></div>"));
and
var div = $("<div>");
var img = $("<img>").attr({"src" : "somesource", "alt" : "something"});
div.append(img);
$('body').append(div);
which is the best practice to follow?
The second is better. Because you often see people doing this:
var alt = 'This is " the title containing a double quote';
$('body').append($('<div><img src="somesource" alt="' + alt + '"></div>'));
and then wonder why something got eaten :-). Whereas when you use the second you have absolutely nothing to worry about:
var alt = 'This is " the title containing a double quote';
var div = $('<div>');
var img = $('<img>').attr({ src : 'somesource', alt : alt });
div.append(img);
$('body').append(div);
UPDATE:
I was too hasty in saying that you have nothing to worry about with the second approach. As others have already pointed out you have to worry about performance.
The second method looks better and there are lesser chances of error. But performance wise, the second method is slower. So if you're going to be doing a lot of appending, I would recommend going with the the first case - albeit, carefully.
Here's a small test case up on JS-Perf comparing the two methods
Normally I would say DOM-scripting is the better option (the second approach); it's more structured, and easier to catch issues than by inserting a mass of HTML prepared as a string.
That said, there are performance concerns. Inserting loads of elements via DOM-scripting, particularly in a loop, can cause significant slowdown and there are cases where inserting as a string is much quicker.
Also, the fewer inserts you do - by whatever means - the fewer repaints/refreshes you force the browser to make. Again, these all require browser attention, so the fewer the better.
I believe you are better off using template libraries for inserting objects. An example of one such library is here: http://api.jquery.com/category/plugins/templates/
Those libraries are build for performance and ease the burden on parsing HTML blobs.
Adding a string of HTML content is about 10 times faster
than using second method
Here is a reference
See also my answer on When do you use DOM-based Generation vs. using strings/innerHTML/JQuery to generate DOM content?
The difference is that you have two variables pointing to the jQuery instances. You might can need them for eventListener-adding or manipulating them lateron in the code.
Also, DOM-based element generation has the advantage of automatically escaping the strings, which is especially useful when designing functions with parameters and absolutely needed for user input.
Therefore, the second method is most often preferred. You can also nest the appending process to make the structure clear (OK, in this example the one-liner would be clear as well):
var div = $("<div>");
var img = $("<img>", {"src":"somesource", "alt":"something"});
$('body').append(
div.append(
img
)
);
I would prefer the second one as the first one could lead to very long lines and if you need to bind events to certain elements you already have a variable that is pointing to it.

Javascript .replace command replace page text?

Can the JavaScript command .replace replace text in any webpage? I want to create a Chrome extension that replaces specific words in any webpage to say something else (example cake instead of pie).
The .replace method is a string operation, so it's not immediately simple to run the operation on HTML documents, which are composed of DOM Node objects.
Use TreeWalker API
The best way to go through every node in a DOM and replace text in it is to use the document.createTreeWalker method to create a TreeWalker object. This is a practice that is used in a number of Chrome extensions!
// create a TreeWalker of all text nodes
var allTextNodes = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT),
// some temp references for performance
tmptxt,
tmpnode,
// compile the RE and cache the replace string, for performance
cakeRE = /cake/g,
replaceValue = "pie";
// iterate through all text nodes
while (allTextNodes.nextNode()) {
tmpnode = allTextNodes.currentNode;
tmptxt = tmpnode.nodeValue;
tmpnode.nodeValue = tmptxt.replace(cakeRE, replaceValue);
}
To replace parts of text with another element or to add an element in the middle of text, use DOM splitText, createElement, and insertBefore methods, example.
See also how to replace multiple strings with multiple other strings.
Don't use innerHTML or innerText or jQuery .html()
// the innerHTML property of any DOM node is a string
document.body.innerHTML = document.body.innerHTML.replace(/cake/g,'pie')
It's generally slower (especially on mobile devices).
It effectively removes and replaces the entire DOM, which is not awesome and could have some side effects: it destroys all event listeners attached in JavaScript code (via addEventListener or .onxxxx properties) thus breaking the functionality partially/completely.
This is, however, a common, quick, and very dirty way to do it.
Ok, so the createTreeWalker method is the RIGHT way of doing this and it's a good way. I unfortunately needed to do this to support IE8 which does not support document.createTreeWalker. Sad Ian is sad.
If you want to do this with a .replace on the page text using a non-standard innerHTML call like a naughty child, you need to be careful because it WILL replace text inside a tag, leading to XSS vulnerabilities and general destruction of your page.
What you need to do is only replace text OUTSIDE of tag, which I matched with:
var search_re = new RegExp("(?:>[^<]*)(" + stringToReplace + ")(?:[^>]*<)", "gi");
gross, isn't it. you may want to mitigate any slowness by replacing some results and then sticking the rest in a setTimeout call like so:
// replace some chunk of stuff, the first section of your page works nicely
// if you happen to have that organization
//
setTimeout(function() { /* replace the rest */ }, 10);
which will return immediately after replacing the first chunk, letting your page continue with its happy life. for your replace calls, you're also going to want to replace large chunks in a temp string
var tmp = element.innerHTML.replace(search_re, whatever);
/* more replace calls, maybe this is in a for loop, i don't know what you're doing */
element.innerHTML = tmp;
so as to minimize reflows (when the page recalculates positioning and re-renders everything). for large pages, this can be slow unless you're careful, hence the optimization pointers. again, don't do this unless you absolutely need to. use the createTreeWalker method zetlen has kindly posted above..
have you tryed something like that?
$('body').html($('body').html().replace('pie','cake'));

conditionals in javascript based on page currently showing

because of some problems with joomla "in-content javascript" I have to give all my js logic to one file, but there are problems with inconsistence of dom elements across my site (it is ajax driven, so there is only one script and various DOMs).
What is the best solution to make some conditionals solving this problem..
Is it checking $(selector).length, or is there any better solution..
And in case of the $(selector).length , is there a way to save this selector to variable (performance issues)
for example some kind of
var selector = ($(selector).length !== 0) ? this : false ;
if(selector) { makeSomething; }
The this is actually pointing to Window object..So is there any way to make it like this without need of reselection?
Thanks
var $obj = $('selector');
if ($obj.length) { makeSomething(); }
Actually, this is only meaningful if you are searching for the existence of a certain element (that might identify a whole page) and running several operations based on that.
If you just want to do something on the elements like
$('selector').append('x');
the condition might be useless, because if the jQuery collection is empty, the methods won't run anyways (as pointed out by #Gary Green).

Javascript - get strings inside a string

var str = '<div part="1">
<div>
...
<p class="so">text</p>
...
</div>
</div><span></span>';
I got a long string stored in var str, I need to extract the the strings inside div part="1". Can you help me please?
you could create a DOM element and set its innerHTML to your string.
Then you can iterate through the childNodes and read the attributes you want ;)
example
var str = "<your><html>";
var node = document.createElement("div");
node.innerHTML = str;
for(var i = 0; i < node.childNodes.length; i++){
console.log(node.childNodes[i].getAttribute("part"));
}
If you're using a library like JQuery, this is trivially easy without having to go through the horrors of parsing HTML with regex.
Simply load the string into a JQuery object; then you'll be able to query it using selectors. It's as simple as this:
var so = $(str).find('.so');
to get the class='so' elememnt.
If you want to get all the text in part='1', then it would be this:
var part1 = $(str).find('[part=1]').text();
Similar results can be achieved with Prototype library, or others. Without any library, you can still do the same thing using the DOM, but it'll be much harder work.
Just to clarify why it's a bad idea to do this sort of thing in regex:
Yes, it can be done. It is possible to scan a block of HTML code with regex and find things within the string.
However, the issue is that HTML is too variable -- it is defined as a non-regular language (bear in mind that the 'reg' in 'regex' is for 'regular').
If you know that your HTML structure is always going to look the same, it's relatively easy. However if it's ever going to be possible that the incoming HTML might contain elements or attributes other than the exact ones you're expecting, suddenly writing the regex becomes extremely difficult, because regex is designed for searching in predictable strings. When you factor in the possibility of being given invalid HTML code to parse, the difficulty factor increases even more.
With a lot of effort and good understanding of the more esoteric parts of regex, it can be done, with a reasonable degree of reliability. But it's never going to be perfect -- there's always going to be the possibility of your regex not working if it's fed with something it doesn't expect.
By contrast, parsing it with the DOM is much much simpler -- as demonstrated, with the right libraries, it can be a single line of code (and very easy to read, unlike the horrific regex you'd need to write). It'll also be much more efficient to run, and gives you the ability to do other search operations on the same chunk of HTML, without having to re-parse it all again.

Categories