-1

I need to write a script that reads an HTML file in which there are multiple images declared. The thing is the call to the image is simple and I need to add several instructions. From this code :

<img src="myImage1.jpg" class="image_document">
<img src="myImage2.jpg" class="image_document">

I have to get this :

<a onclick="bloquedefilementchapitres();" href="articles/myImage1.jpg" class="fancybox" rel="images"><img src="articles/myImage1.jpg" class="image_document"></a>
<a onclick="bloquedefilementchapitres();" href="articles/myImage2.jpg" class="fancybox" rel="images"><img src="articles/myImage2.jpg" class="image_document"></a>

So, I tried to use regex to perform this thinking that every image could be detected by regex. Then, every filename could be stored in an array so that I would be able to use the filename to write the link.

Here is what I did :

var recherche_images,
urls = [], 
str = theHTMLcode,
rex = /<img[^>]+src="?([^"\s]+)"/g;

while (recherche_images = rex.exec(str)) {
    urls.push(recherche_images[1]); 
}

for (var v = 0; v < urls.length; v++) {
    str = str.replace(/<img src=\"/, '<a onclick=\"bloquedefilementchapitres();\" href=\"articles/' + urls[v] + '\" class=\"fancybox\" rel=\"images-' + idunite + '\"><img src=\"articles/');
}
str = str.replace(/image_document\">/g, 'image_document\"></a>');

If the HTML document only contains one image, it works. If two images are declared, the program loops on the first image and ignores the second image.

Is there any way to tell to the replace function to start at a certain point in the string? Is there any better way to perform this?

3 Answers3

0

There are better ways to achieve this as noted in the comments to your question.

Regarding your code:

  • There is an issue with the for loop in your code - v++ is executed twice - one in the for loop increment condition and once in the body.

  • Another issue is the way the .replace() method has been used. Without the \g flag in the regex, the replace() method will just find and replace the first occurrence. Check documentation and this SO question for more details.

    • Check the code below which uses the /g operator in the regex to find all img matches in the string and each match is passed to a function which returns the replacement string.

What you need is something like this:

var recherche_images,
urls = [], 
str = '<img src="myImage1.jpg" class="image_document"><img src="myImage2.jpg" class="image_document">',
rex = /<img[^>]+src="?([^"\s]+)"/g;

while (recherche_images = rex.exec(str)) {
    urls.push(recherche_images[1]); 
    console.log(recherche_images[1]);
}

var idunite = 'test"';
var v = -1;
str = str.replace(/<img src=\"/g, function(mtch) {
    v++;
    return '<a onclick=\"bloquedefilementchapitres();\" href=\"articles/' + urls[v] + '\" class=\"fancybox\" rel=\"images-' + idunite + '\"><img src=\"articles/';
});


str = str.replace(/image_document\">/g, 'image_document\"></a>');
console.log(str);

JSFiddle.

Community
  • 1
  • 1
nhylated
  • 1,575
  • 13
  • 19
  • Hello ! Great ! It works ! Many thanks ! I had edited my code as I saw "v++" was written twice ! You reply shows me a bit of how the replace method works. I had deleted the "/g" option as I wanted the function to use each image filename in the replacement : I didn't know the "/g" option could work iteritically. – Fabien Nguyen Oct 13 '15 at 13:09
0

Pure JS solution:

var x = document.getElementsByClassName('image_document');
for (var i = 0; i < x.length; i++) {
  var obj = x[i];
  var n = document.createElement('a');
  n.href = "articles/" + obj.attributes.src.value;
  obj.src = "articles/" + obj.attributes.src.value;
  n.className = "fancybox";
  n.rel = "images";
  n.innerHTML = obj.outerHTML;
  n.addEventListener('click', bloquedefilementchapitres);
  console.log(n);
  obj.parentNode.replaceChild(n, obj);
}
<img src="myImage1.jpg" class="image_document">
<img src="myImage2.jpg" class="image_document">
hjpotter92
  • 78,589
  • 36
  • 144
  • 183
  • Hello ! Thanks for your reply ! I haven't tested your code but I wonder if the getElementsByClassName would work on a string (as it is in my code) and not on an HTML document. And I realize I'm really nuts at JavaScript when I read your code ! I'm learning a lot ! – Fabien Nguyen Oct 13 '15 at 13:16
  • @FabienNguyen You can use the `HTMLParser` function as defined here: https://developer.mozilla.org/en-US/Add-ons/Code_snippets/HTML_to_DOM#Using_a_hidden_browser_element_to_parse_HTML_to_a_window.27s_DOM – hjpotter92 Oct 14 '15 at 04:30
  • OK ! Thanks ! I'll try it ! – Fabien Nguyen Oct 14 '15 at 07:48
0

It seems like you can do this with a single global replace:

For example if your HTML string is in a variable called s then it would be:

s.replace(/<img src="([^\"]+)" class="image_document">/g, 
          "<a onclick=\"bloquedefilementchapitres();\" href=\"articles/$1\" class=\"fancybox\" rel=\"images\"><img src=\"articles/$1\" class=\"image_document\"></a>");

That seems to work for me ok in the console for a string with one or many img tags. Apologies if I'm missing additional complexity/requirements.

Jeremy Jones
  • 4,561
  • 3
  • 16
  • 26
  • Hello ! Thanks for your reply ! Where do the "$1" variable come from in your code ? Apologies for my ignorance :-) – Fabien Nguyen Oct 13 '15 at 13:13
  • Hi the $1 contains whatever was captured with () in the regular expression. In this case it's the value of the src attribute in the img tag. If there were multiple () within the regular expression then they would be numbered $1 $2 $3 ... and so on. In this case there's only one so it's just $1 in the replacement. – Jeremy Jones Oct 13 '15 at 13:20
  • Thanks for the explanation ! – Fabien Nguyen Oct 14 '15 at 07:40