arvgta / ajaxify

Ajaxify - An Ajax Plugin
https://4nf.org/
275 stars 123 forks source link

Prevent multiple occurrences of event handlers #218

Closed arvgta closed 3 years ago

arvgta commented 3 years ago

EDIT: Not necessary to adopt this approach because there were no timing problems after all...


Old code:

let iFn = function (a, b, c = false) { 
    if ((this === document || this === window) && a=="DOMContentLoaded") setTimeout(b); else this.ael(a,b,c);
};  // if "DOMContentLoaded" - execute function, else - add event listener

EventTarget.prototype.ael = EventTarget.prototype.addEventListener; // store original method
EventTarget.prototype.addEventListener = iFn; // start intercepting event listener addition

...works fine but can cause timing issues because of the setTimeout(b) bit, that executes the handler on the fly, instead of waiting for the DOMContentLoaded event itself.


Therefore, I have attempted to replace the setTimeout(b) bit with a snippet, that attempts to inject:

into all calls of addEventListener with type DOMContentLoaded.

In this new scenario, the DOMContentLoadedevent is fired programmatically by Ajaxify itself beforehand.

New code: (in this file, which is active in the testcase below)

let iFn = function (a, b, c = false) { 
    if ((this === document || this === window) && a=="DOMContentLoaded") {
        if(typeof c == "boolean") c = { capture: c, once: true };
        else c.once = true;
    }
    this.ael(a,b,c);
};
EventTarget.prototype.ael = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = iFn;

...which works fine, but for some reason, the pass right after initial load does not work - as can be seen here at the moment:

and

(The DOMContentLoaded event is fired successfully, but the handler is not called in that case only)


How to reproduce the bug in more detail:

  1. Enter www.oeko-fakt.de
  2. Open the Chrome console
  3. You should see the message: "DCL triggered" followed by "Ajaxify loaded..." (as expected on initial load - no problem)
  4. Navigate to another page - "DCL triggered" is not shown in the console (not as expected)
  5. Navigate to further pages - "DCL triggered" is shown in the console (as expected)

So the bug is on step 4) above

Please note also:


(Link for my own purposes: ) Erase any salient handlers

arvgta commented 3 years ago

The bug was identified: the firing of the event was happening before the registration of the handler had finished. Solved by adding a setTimeout() with minimal delay (0 milliseconds) to the firing of the event.

Now seems to work!

arvgta commented 3 years ago

Just for the sake of completeness - this approach has been discarded in the course of some testing...