javascriptdomgoogle-chrome-extensionevent-listenerdom3

Implementation of a DOM listener


I was thinking there was no DOM listener so I implemented my own 'heavy' listener:

function CvHelper(stackApi) {
  var that = this;

  // check if room is finished loading
  this.init = function() {
    if ($('#loading').length) {
      setTimeout(that.init, 1000);
    } else {
      console.log('Chatroom finished loading');

      that.postListener();
    }
  }
}

(function() {
  var stackApi = new StackApi();
  var cvHelper = new CvHelper(stackApi);
  cvHelper.init();
})();

I think this just sucks. So I did a search on here on SO and this question popped up. However the last comment on the accepted question states that it is deprecated.

$("#someDiv").bind("DOMSubtreeModified", function() {
  alert("tree changed");
});

w3.org/TR/DOM-Level-3-Events/#event-type-DOMSubtreeModified says this event is deprecated, what would we use instead?

Is there a substition for it?
P.S. It only has to work on Chrome, because it is an Chrome extension.


Solution

  • If you take a look at:

    http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-MutationEvent

    It states that, regarding DOMSubtreeModified, "It may be fired after a single modification to the document or, at the implementation's discretion, after multiple changes have occurred."

    Therefore, if you use a different MutationEvent, say DOMNodeInserted, you may get a more deterministic firing of events (You'd just have to add an element to the node in that specific case).

    See below:

    $('body').prepend( $('<div id="cow">Hello</div>') );
    
    $('#cow').bind("DOMNodeInserted",function(){ alert('hi'); } );
    
    $('#cow').prepend( $("<div></div>") );
    

    This was tested in Chrome, btw.

    Hope that helps...

    UPDATE: Alternatively, you could add more than one event type in one function call. For example, adding four event handlers for DOMNodeInserted, DOMNodeRemoved, DOMAttrModified, DOMCharacterDataModified, then all of the handlers call a single handler.

    UPDATE: I wrote a little script that does what I had just written in the previous update:

    $('body').prepend( $('<div id="cow">Hello</div>') );
    
    /**
    * This function registers event handlers which invoke the mutateHandler 
    * handler when any of the MutationEvents are fired on a node: DOMNodeInserted, 
    * DOMNodeRemoved, DOMAttrModified, DOMCharacterDataModified.
    *
    */
    var onMutate = function( mutateHandler ){
    
        var that = this;
        $(this).bind( "DOMNodeInserted", function( event ){ 
            mutateHandler.call( that, event ); 
        });
        $(this).bind( "DOMNodeRemoved", function( event ){ 
            mutateHandler.call( that, event ); 
        });
        $(this).bind( "DOMAttrModified", function( event ){ 
            mutateHandler.call( that, event );
        });
        $(this).bind( "DOMCharacterDataModified", function( event ){ 
            mutateHandler.call( that, event );
        });
    
    };
    
    onMutate.call( $('#cow')[0], function(){
        alert( $(this).attr('id') );
    });
    
    
    $('#cow').prepend( $("<div></div>") );
    $('#cow').addClass( 'my_class' );