1

I want to make some refinement to some code from a previous question:

// the new base url
var base = ' https://www.example.co.uk/gp/wine/order?ie=UTF8&asin=';
var links  = document.getElementsByTagName('a');

for(var i = 0;i < links.length;i++){
    // check each link for the 'asin' value
    var result = /asin=([\d\w]+)/.exec(links[i].getAttribute('href'));
    if(result){
        // make a new url using the 'base' and the 'asin' value
        links[i].setAttribute('href', base+result[1]);
    }
}

Now, instead of it acting on all links, can I get it to only look at links that are from images?

Here is an HTML snippet to show what I mean:

<a href="/shop/product?ie=UTF8&amp;asin=Z00FDLN878&amp;tab=UK_Default" target="_blank"><img width="125" height="125" border="0" src="http://ecx.images-amazon.com/images/I/01W9a7gwosL.jpg" alt="43453"></a>

That's an image link - I do want it to act on that.

Impossible?

My gut instinct is that this isn't actually possible in code - because document.getElementsByTagName('a') can't see the difference between a text link and an image link.

Community
  • 1
  • 1
Elle
  • 375
  • 1
  • 2
  • 12

7 Answers7

2

Use querySelectorAll to pre-select only the right kinds of nodes. EG:

// the new base url
var base        = 'https://www.example.co.uk/gp/wine/order?ie=UTF8&asin=';
var linkImgs    = document.querySelectorAll ("a > img");

for (var J = linkImgs.length - 1;  J >= 0;  --J) {
    var imgLink = linkImgs[J].parentNode;

    //--- Check each link for the 'asin' value
    var result  = /asin=([\d\w]+)/.exec (imgLink.getAttribute ('href') );
    if( result) {
        // make a new url using the 'base' and the 'asin' value
        imgLink.setAttribute ('href', base+result[1]);
    }
}
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • **This is amazing - thank you**. Just out of curiosity, how can I make it the **inverse**? (In other words, so that it only applies the code to text links and not image links). I wonder if I can just put a `!` somewhere ... – Elle Nov 28 '13 at 14:53
  • 1
    Alas, it's not that easy since CSS does not have a `has` selector. It's easy with jQuery though. You would use `$("a:not(:has(img))")`. – Brock Adams Nov 28 '13 at 21:24
  • How, exactly, would I use that, please ? (Perhaps I should make a new question) – Elle Dec 05 '13 at 14:59
  • 1
    Yes, please make a new question for the new requirement. It's not hard, but it's a bit much to answer in comments. – Brock Adams Dec 05 '13 at 20:58
  • Thanks Brock, I've created it at http://stackoverflow.com/questions/20619331/how-can-i-refine-this-javascript-code-so-it-ignores-links-from-images – Elle Dec 16 '13 at 19:36
  • If `document.querySelectorAll ("a > img")` finds the links that are image links, can I use `document.querySelectorAll ("a < img")` to find the inverse ? – Elle Mar 25 '14 at 14:52
1

You could use regex to check for the link inside the HTML of the link:

for(var i = 0;i < links.length;i++) {

    // check each link for the 'asin' value
    var result = /asin=([\d\w]+)/.exec(links[i].getAttribute('href'));

    // check each link for an img tag
    var hasimage = /<img [^>]+>/.test(links[i].innerHTML);

    if(result && hasimage){
        // make a new url using the 'base' and the 'asin' value
        links[i].setAttribute('href', base+result[1]);
    }

}

Also, using regular expressions to search for HTML probably isn't the best bet, but if you control what's being generated, then this is probably the quickest way without a 3rd party html parser.

Nahydrin
  • 13,197
  • 12
  • 59
  • 101
  • Brian, do you think I could use this technique to do http://stackoverflow.com/questions/20619331/how-can-i-refine-this-javascript-code-so-it-ignores-links-from-images ? (The difference between that question and this, is I now want to **ignore** image links) – Elle Mar 25 '14 at 14:24
1

You can filter the links based on whether or not they contain an image.

var links  = document.getElementsByTagName('a');

links = [].filter.call(links, function(item) {
   // test to see if child node is an image
   return item.childNodes[0].nodeName === 'IMG'; 
});

for(var i = 0;i < links.length;i++){
    // do what you gotta do
}
Evan Davis
  • 35,493
  • 6
  • 50
  • 57
  • 4
    This assumes that the is the first node inside the link. It very often won't be. A textnode will usually have that honor. – Brock Adams Nov 28 '13 at 00:12
1

You can just test for an IMG child and only process the link if there is one there.

Example on JSFiddle

// the new base url
var base = ' https://www.example.co.uk/gp/wine/order?ie=UTF8&asin=';
var links  = document.getElementsByTagName('a');

for(var i = 0;i < links.length;i++){
    var linkElement = links[i];
    //get the first child of the a element
    var firstChild = linkElement.children[0];
    //if there is a child and it's an IMG then process this link
    if (typeof(firstChild) !== "undefined" && firstChild.tagName=="IMG") { 
      // check each link for the 'asin' value
      var result = /asin=([\d\w]+)/.exec(links[i].getAttribute('href'));
      if(result){
          // make a new url using the 'base' and the 'asin' value
          links[i].setAttribute('href', base+result[1]);
      }}
}
Paul D'Ambra
  • 7,629
  • 3
  • 51
  • 96
0
// the new base url
var base = ' https://www.example.co.uk/gp/wine/order?ie=UTF8&asin=';
var links  = document.getElementsByTagName('img');
var hrefs = links.parent;

for(var i = 0;i < hrefs.length;i++){
    // check each link for the 'asin' value
    var result = /asin=([\d\w]+)/.exec(hrefs[i].getAttribute('href'));
    if(result){
        // make a new url using the 'base' and the 'asin' value
        hrefs[i].setAttribute('href', base+result[1]);
    }
}
DevlshOne
  • 8,357
  • 1
  • 29
  • 37
0

There is a links collection, and you can can just check if the link has an image child node:

var link, links = document.links;
var re = /asin=([\d\w]+)/;
for (var i=0, iLen=links.length; i<iLen; i++) {
  link = links[i]

  if (link.getElementsByTagName('img').length && re.test(link.href)) {
    link.href = base + result[1];
  }
}
RobG
  • 142,382
  • 31
  • 172
  • 209
-1

My initial response would be to look into query Select All and then assign a class name to grab on all of the a tags that would be affected by whatever your trying to do. When I get to my laptop I'll edit this with an example.

  • Even if this were a real answer, that sounds overly complicated. – Evan Davis Nov 27 '13 at 23:47
  • You add a class to the a elements and call them with queryselectall is overly complicated? I don't get your logic there, it's one of the easiest ways to get a specific element. But since I'll not get a chance anytime soon to defend this with a code example I'll bow out now. Sorry for wasting people's time. – Otis Eugene Anderson Nov 27 '13 at 23:52
  • Well you are talking about selecting all the tags, adding a class, and then reselecting by class. All the other solutions only select once, making your solution needlessly complex. – Evan Davis Nov 28 '13 at 00:32
  • If that's what you got from me recommending queryselectall as a potential solution then I must have worded something horribly wrong. I was thinking something more simplistic like select all the a elements then filter out any with an image child and proceed from there. The only reason class was mentioned was to apply it in the html to give a more definitive target for the query, agreed the class part is not needed however it cuts out alot of fluff to filter through. Wish I was not mobile and could work up a fiddle to show better what I'm talking about. – Otis Eugene Anderson Nov 28 '13 at 03:09
  • Actually just takea look at Brocks answer that is where I was going with this. – Otis Eugene Anderson Nov 28 '13 at 03:17