JavaScript
In our second HYS we announced our decision to
move away from jQuery and some of you are already releasing updates to your add-ons which is great to see. The following serves as a non-exhaustive reference for any specific framework changes that may affect how you write JavaScript code in your add-ons going forwards.
XF.extendObject
This is a new method which replaces jQuery's default
$.extend()
method. It works basically exactly the same, including the option to do a "deep" clone.
XF.createElementFromString
jQuery supported creating a new element with various properties and attributes entirely from a string, for example:
JavaScript:
const $input = $('<input type="text" readonly class="input" />')
We wanted to have something similar to this so we added a method which works similarly:
JavaScript:
const input = XF.createElementFromString('<input type="text" readonly class="input" />')
We have an entirely new concept too called
XF.createElement
which you can read about in a subsequent post.
Event management
Some of the event management stuff in jQuery is pretty cool so we've replicated it as much as possible. Notably, we support namespaced events in a similar way to jQuery, along with equivalent methods to jQuery named
XF.on()
,
XF.off()
,
XF.trigger()
and
XF.customEvent()
. To handle delegated events we have a new
XF.onDelegated
method. If you previously used jQuery's
one
method so that an event listener is removed after it is first fired, you can now just pass
{ once: true }
into your
XF.on()
calls.
Changes to XF.ajax
While the usage of
XF.ajax()
is mostly unchanged, clearly we no longer use jQuery's
$.ajax()
under the hood, which is a wrapper around
XMLHttpRequest
. We decided to move away from
XMLHttpRequest
in favour of the more modern Fetch API.
XF.ajax
now returns a
Promise
which is similar to what is returned by jQuery, albeit with the promise method names being slightly different. Which were mentioned in the original have you seen post.
The other notable change though is how AJAX requests are aborted if needed. Previously, the object returned by jQuery had an
abort
method that could be called. The Fetch API has a different way of achieving this, which is a little more convoluted so we have created a new
XF.ajaxAbortable
method which makes this a little easier to work with, but it's worth noting that your existing usage of
XF.ajax
where a call may need to be aborted, will need to be changed.
Here's a usage example from
form.js
:
JavaScript:
const {
ajax,
abortController,
} = XF.ajaxAbortable('post', this.options.descUrl, { id: value }, this.onLoad.bind(this))
if (abortController)
{
this.abortController = abortController
}
// ... elsewhere in the code
if (this.abortController)
{
this.abortController.abort()
this.abortController = null
}
XF.proxy
The
XF.proxy
method is typically used when you want to change the context of the
this
variable when calling another function. For example, if you pass a function as a callback when listening to a image
load
event (or similar),
this
in that callback would usually be a reference to the image itself. That's not usually desirable, so
XF.proxy
helps us keep the
this
context consistent.
While, of course,
XF.proxy
still exists and remains unchanged, please consider this deprecated and marked for removal in the future.
Instead, we now recommend and use the native JavaScript approach for this. This looks like:
JavaScript:
XF.on(form, 'reset', this.formReset.bind(this))
Primarily, this should help reduce errors and help navigating code in your IDE.
JavaScript animations and CSS-based transitions
jQuery has a number of animation functions which we felt were worth keeping so we have rewritten them. The home for these new methods is under a new
XF.Animate
namespace and includes various approaches for sliding/fading content.
Here's an example where we fade up an existing container to hide it, replace its contents and then fade it back down to show the new content:
JavaScript:
XF.Animate.fadeUp(containerEl, {
speed: XF.config.speed.fast,
complete ()
{
containerEl.innerHTML = html.innerHTML
XF.Animate.fadeDown(containerEl)
},
})
You may also be familiar with our custom
addClassTransitioned
and
removeClassTransitioned
methods. Previously these were added as jQuery extensions. They have now been moved to a new
XF.Transition
namespace and require an element to be passed in as the first argument.
JavaScript:
XF.Transition.addClassTransitioned(this.errorElement, 'is-active')
Vendor library changes
This section summarises the changes to vendor libraries which may impact your current add-ons.
Select2
Unfortunately, Select2 is still written with jQuery as a dependency so it will no longer be included starting with XenForo 2.3. We only use Select2 for our "token input" system which is used as a tagging input and for multiple user selection (such as conversations). To keep this functionality we are now including a library called
Tagify.
This pretty much has the same functionality you're used to but, ooh, look, avatars for multiple user input:
QR code generation
We include a QR code generation library mostly for aiding the setup of TOTP as a two-factor authentication method. The previous version of this library relied on jQuery but newer versions have been rewritten without any specific dependencies. If you're using QR codes in any of your add-ons, this is just something you'll want to be aware of. The specific version of this library we're now using can be found
here.
Star ratings
Star ratings as you can see in both XenForo Media Gallery and XenForo Resource Manager previously relied on a third party library. A direct replacement didn't really exist so we just converted it ourselves to JavaScript. This is now a new class named
XF.BarRating
which you can find in
rating.js
.