0

Context:

I'm trying to write some JavaScript that is being injected into a certain webpage. Think something to the likes of Grease Monkey / Tamper Monkey scripts. (Except I've created a chrome extension) The current webpage is an internal application, that is rendered via GWT. I don't have access to the code.

It's basically a news feed type system, I'm wanting to enable the use of markdown in the feed posts when the extension is enabled/installed.

Problem:

The page seems to render in multiple phases.

  1. All the external scrips get attached
  2. After about 10 - 15 seconds, the rest of the DOM objects get dynamically created via JavaScript.

The problem with this is, my script needs to wait for any given page to be finished before I can try any do whatever I need to.

Thus I've tried this (as well as a few other variations in the vein):

$(document).bind('DOMSubtreeModified',function() {
    // maketh with the hax
});

The obvious problem is that this fires on each and every DOM modify event, which to me seems a bit crazy. Also on each event, say my selector is this $('.post-item > div[id^=feed-post]') will re-log items that have been logged before.

I then tried to kick off a timer of sorts, and have it reset on each DOM modify event. Effectively what'll happen is, the timer will keep clearing, then only once the last event is done, the timer will complete and execute my code.. this seems like the worst way to handle this, I'd ideally not like to have any additional delay post page being rendered fully.

var domTimer = timer();

$(document).bind('DOMSubtreeModified',function() {
    domTimer.reset();    
});

domTimer.promise()
    .then(function(status) {
        console.log( status );

        if ($('.post-item > div[id^=feed-post]').length > 0) {
            console.log($('.post-item > div[id^=feed-post]'));
            $('.post-item > div[id^=feed-post]').html('testing');
        }
});

Structure of the element (for reference)

    <div class="post-item">
        <div id="feed-post">
            <div class="photo"></div> 
            <div class="post-inner"> 
                <div class="details-container">
                    <div class="last-updated"></div> 
                    <div class="post-group"></div>
                </div> 
            </div> 
            <div class="message-container">I want to markdown enable this</div> 
        </div>
    </div>

Question:

I'm looking for suggestions to monitor the DOM for any (specific) NEW items that get added.

Rohan Büchner
  • 5,333
  • 4
  • 62
  • 106
  • 2
    Sounds like you're looking for a [Mutation Observer](https://developer.mozilla.org/en/docs/Web/API/MutationObserver). Be aware they only work in modern browsers. Check the compatibility list in the bottom of the link. – Rory McCrossan Apr 11 '16 at 06:45
  • @RoryMcCrossan, this is basically for myself and a few work friends, so we'll refrain from using older browsers. But thanks for the suggestion :) – Rohan Büchner Apr 11 '16 at 06:53
  • Possible duplicate of [Is there a jQuery DOM change listener?](http://stackoverflow.com/questions/2844565/is-there-a-jquery-dom-change-listener) – Haibara Ai Apr 11 '16 at 06:58
  • @HaibaraAi, that answer is outdated. I've tinkered with the Mutation Observer as suggested by Rory McCrossan, and it seems to do the trick. Thanks for the additional perspective though. – Rohan Büchner Apr 11 '16 at 08:24

1 Answers1

0

As suggested by @Rory McCrossan, and indirectly via the link provided by @Haibara Ai, I needed to make use of the Mutation Observer.

In my case I'm making use of something to this effect.

MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

var init = function() {

 // select the target node
 var target = document.querySelector('.some-selector');

 // create an observer instance
 var observer = new MutationObserver(function(mutations, observer) {
    mutations.forEach(function(mutation) {

       if(mutation.target.className == 'feed' ) {
          if(mutation.addedNodes[0] && mutation.addedNodes[0].className == 'post-item') {
             console.log(mutation.addedNodes[0]);
          }    
       }

    });    
 });

 // configuration of the observer:
 var config = { childList: true, subtree: true };

 // pass in the target node, as well as the observer options
 observer.observe(document, config);
};
Community
  • 1
  • 1
Rohan Büchner
  • 5,333
  • 4
  • 62
  • 106