0

I want to position some divs on top of all ads on Amazon.com like this:

This is for a project of mine. The above picture was achieved through getting the coordinates of the ads using getBoundingClientRect and creating divs, setting top and left based on these coordinates, and appending the divs to document.body. However, since they have absolute position and are children of document.body, they do not move with the ads. For example, if I resize the window, this happens

Also, in product pages, this happens without doing anything.

I have also tried appending the divs to the parents of the iframes/ads, but I can never seem to make them appear outside of their parent. I have tried suggestions from various links, such as making position:absolute, setting bottom or top, making the parents position:relative but nothing has worked. There has been one instance of the div appearing outside of the parent but it was in some random position above it like this.

I seriously don't know how to accomplish this. Ideally, the div would be a sibling of the iframe or something like that, so I don't have to deal with the divs not moving when the window resizes. I just can't seem to get anything work, though.

    // Here is the code for appending to parent of iframes.
    // The divs just end up overlaying the ad.
    function setStyle(element, styleProperties) {
        for (var property in styleProperties) {
            element.style[property] = styleProperties[property];
        }
    }

    // Regex for getting all the parents of all the iframes
    var placements = document.querySelectorAll('div[id^=\'ape_\'][id$=\'placement\']');

    for (var i = 0; i < placements.length; ++i) {
        var placement = placements[i];

        var iframe = placement.getElementsByTagName('iframe')[0];
        var debugDiv = document.createElement('div');
        debugDiv.id = iframe.id + '_debug_div';
        setStyle(debugDiv, {
            'backgroundColor': '#ff0000',
            'height': '30px',
            'display': 'block',
            'position': 'absolute',
            'top': '-30px',
            'zIndex': '16777270',
        });
        alert(placement.id)
        placement.style.position = 'relative'
        placement.appendChild(debugDiv);
    }

edit:

Here's the getBoundingClientRect code:

function setStyle(element, styleProperties) {
    for (var property in styleProperties) {
        element.style[property] = styleProperties[property];
    }
}

function createDiv(iframeId, top, left, width) {
    var div = document.createElement('div');
    div.id = iframeId + '_debug_div';
    setStyle(div, {
        'backgroundColor': '#ccffff',
        'backgroundColor': '#ff0000',
        'height': '30px',
        'width': width.toString() + 'px',
        'display': 'block',
        'position': 'absolute',
        'top': (top - 30).toString() + 'px',
        'left': left.toString() + 'px',
        'zIndex': '16777270'
    });

    return div;
}

var placements = document.querySelectorAll('div[id^=\'ape_\'][id$=\'placement\']');

for (var i = 0; i < placements.length; ++i) {
    var placement = placements[i];

    var iframe = placement.getElementsByTagName('iframe')[0];
    var iframeRect = iframe.getBoundingClientRect();
    iframeWidth = iframeRect.right - iframeRect.left;
    var debugDiv = createDiv(iframe.id, iframeRect.top, iframeRect.left, iframeWidth);
    document.body.appendChild(debugDiv);
};

This doesn't work properly when the window is resized. It also does not work properly on product pages for some ads.

aynber
  • 22,380
  • 8
  • 50
  • 63
heyitsme
  • 23
  • 6
  • Could you please also post/link to your code using getClientBoundingRect? It seems like probably the best approach to start with, and I could help get it to work with the window resizing. – Geza Kerecsenyi Aug 10 '19 at 20:03
  • @GezaKerecsenyi Hi, thanks for getting back to me. I've added the getClientBoundingRect code. – heyitsme Aug 10 '19 at 20:23

2 Answers2

0

I think, that you want to select the image of the ad.

const adImages = document.querySelectorAll('your ad images');
for (var i = 0; i < adImages.length; ++i) {
  adImages[i].parent.insertAdjacentHTML('afterbegin', 'your html');
}

You basicaly set the first child of that parent element on the top.

Poselsky
  • 65
  • 1
  • 7
  • This is actually what I'm doing in the first code snippet above. "placement" is the parent of the iframe (the ad). – heyitsme Aug 10 '19 at 20:44
0

Try using the resize eventlistener, with a DOM MutationObserver:

var observeDOM = (function(){
  var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

  return function( obj, callback ){
    if( !obj || !obj.nodeType === 1 ) return; // validation

    if( MutationObserver ){
      // define a new observer
      var obs = new MutationObserver(function(mutations, observer){
          callback(mutations);
      })
      // have the observer observe foo for changes in children
      obs.observe( obj, { childList:true, subtree:true });
    }

    else if( window.addEventListener ){
      obj.addEventListener('DOMNodeInserted', callback, false);
      obj.addEventListener('DOMNodeRemoved', callback, false);
    }
  }
})();

window.onchange = function(){
  observeDOM(document.body, () => {
    window.addEventListener('resize', () => {
      var placements = document.querySelectorAll('div[id^=\'ape_\'] [id$=\'placement\']');

      for (var i = 0; i < placements.length; ++i) {
        var placement = placements[i];

        var iframe = placement.getElementsByTagName('iframe')[0];
        var iframeRect = iframe.getBoundingClientRect();
        iframeWidth = iframeRect.right - iframeRect.left;
        var debugDiv = createDiv(iframe.id, iframeRect.top, iframeRect.left, iframeWidth);
        document.body.appendChild(debugDiv);
      }
    });
  });
}

It's a start. I think the issue with the misplaced bars on the product pages may be fixed by using the onload listener too, although I can't reproduce those issues for whatever reason. If it's not matching some ads altogether, that's likely due to your query selector, but I can't help fix that unfortunately.

The code for the DOM observer is from here - it should detect changes more accurately than onchange, especially for things like flex, where elements can get reordered in the DOM on mobile view. You may also want to wrap this in document.addEventListener("DOMContentLoaded", ... to wait until everything's loaded (at the sacrifice of IE8), or just use jQuery's $(document).ready() (which is compatible with IE8) - however, if you're not already using jQuery, don't import it just for this one function!

Also, you may want to do something about the padding on the body, which may be the cause of the misalignment in some cases. You should probably get it using window.getComputedStyles, and compensate for it. Once again, however, I can't reproduce these errors.

Geza Kerecsenyi
  • 1,127
  • 10
  • 27
  • Hey thanks for this. The resize event + window.scrollX/scrollY seems to make this work for the most part. [This](https://i.imgur.com/jeQc47p.png) still happens if I run the code before this particular ad ever enters my viewport, however. I think rather than the resize event, an event for the change in an element's position would fix this. – heyitsme Aug 10 '19 at 21:59
  • @heyitsme maybe now? I've basically just thrown together all of the event listeners I can think of, hoping that at least one of them matches the given event. – Geza Kerecsenyi Aug 10 '19 at 22:06