XF 2.1 How best to extend core XenForo Javascript event handlers multiple times?

Sidane

Active member
I've run into an issue with extending a core XenForo Javascript event handler multiple times which hopefully someone can offer some guidance on.

I have two add-ons which are extending the element handler XF.QuickReply. Specifically the #afterSubmit method (see js/xf/message.js around line #1206). I've run into an issue where another third-party add-on is also overriding the same method and wiping out my changes.

This is a contrived example of what's happening.

My first add-on JS:

JavaScript:
var Sidane = window.Sidane || {};

!function($, window, document, _undefined)
{
  "use strict";

  XF.Element.extend("quick-reply", {
    __backup: {
      "afterSubmit": "_afterSubmitExtension1"
    },

    afterSubmit: function(e, data)
    {
      this._afterSubmitExtension1(e, data);

      console.log("executing extension 1 after submit");
    }
  });
}
(jQuery, window, document);

My second add-on JS:

JavaScript:
var Sidane = window.Sidane || {};

!function($, window, document, _undefined)
{
  "use strict";

  XF.Element.extend("quick-reply", {
    __backup: {
      "afterSubmit": "_afterSubmitExtension2"
    },

    afterSubmit: function(e, data)
    {
      this._afterSubmitExtension2(e, data);

      console.log("executing extension 2 after submit");
    }
  });
}
(jQuery, window, document);

Note that I'm using the XF.Element.extend("quick-reply".... here as described in this thread. That appears to be the correct way to override existing XenForo handlers.

The issue I have comes when a third party add-on is extending quick-reply using the other approach described in that thread (i.e. XF.extend(XF.QuickReply....).

Example:

JavaScript:
var ThirdPartyAddon = window.ThirdPartyAddon || {}

!function($, window, document, _undefined)
{
  "use strict";

  ThirdPartyAddon.QuickReply = XF.extend(XF.QuickReply, {
      __backup: {
          'afterSubmit': '_afterSubmitThirdPartyAddon'
      },

      afterSubmit: function(e, data)
      {
          this._afterSubmitThirdPartyAddon(e, data);

          console.log("third party add-on after submit")
      }
  });

  XF.Element.register('quick-reply', 'ThirdPartyAddon.QuickReply');
}
(jQuery, window, document);

This third party add-on is effectively replacing the quick-reply element handler with its own extended implementation based off the core XF element handler. And because this Javascript is loaded after my add-on Javascript in the document source, my add-on changes are lost.

HTML:
<head>
  <script src="/js/xf/message.js"></script> <!-- original core JS that defines XF.QuickReply -->
  <script src="/js/sidane/extension1.js"></script> <!-- my first add-on JS that extends XF.QuickReply -->
  <script src="/js/sidane/extension2.js"></script> <!-- my second add-on JS that extends XF.QuickReply -->
  <script src="/js/third-party-addon/message.js"></script> <!-- third party add-on JS that overwrites my add-ons JS -->
</head>

If this third party add-on used the XF.Element.extend("quick-reply".... approach I believe all three add-ons would work correctly in tandem. I've verified that in my dev environment by modifying the third party add-on JS to use XF.Element.extend.

A work around I can see is to ensure that my add-on Javascript is loaded after the third party add-on Javascript. That way I am extending the third party addon's event handler. But this introduces additional complexity to my add-ons and is a bit hacky as I need to ensure template modifications which load my add-on JS occur as late as possible in the template compilation. Even then there is no guarantee a further third party add-on I use in future won't load Javascript later in the document that blows away my changes again.

So two questions:

1) Is my add-on approach to extending the core XF quick-reply element handler correct?

2) Is the best solution to this problem to have the third party add-on author modify their JS so it can work in tandem with other add-on JS that extends the same element handler?

I hope that all makes sense. Happy to clarify anything if necessary.
 
  • Like
Reactions: Xon
Yeah, you're doing it correctly. I'd get in touch with the add-on author and ask them to change it - it's possible they misunderstood how to do it (I'll admit that I did the same thing before I realised I was doing it wrong).
 
Yeah, you're doing it correctly. I'd get in touch with the add-on author and ask them to change it - it's possible they misunderstood how to do it (I'll admit that I did the same thing before I realised I was doing it wrong).

Thanks, will do.
 
@Sidane I think this sort of thing (with examples) would make for a useful tutorial, or even something to include into the developer documentation
 
Top Bottom