Steps to reproduce
- Install mediaelement and big_pipe
- Create a video media entity with a file upload (field type is not a factor)
- Set the "MediaElement.js Video" display formatter
- Create a new media entity, upload a video, and go to the entity view for the simple media entity itself.
Problem/Motivation
When big pipe is enabled all the video media elements appear to have been loaded correctly, but will not play. This is related to
π
Big Pipe calls attachBehaviors twice
Closed: works as designed
, but still an issue even with all proper uses of the once() library.
Currently the once selector is using:
$(once('mediaelement', '.mediaelementjs', context))
The target is essentially something like<video class="mediaelementjs">
(simplified of course). The actual mediaelement library then creates wrapper html around that original tag, and, copies the classes from it.
We then end up with something like:
<div id="mep_0" class="mejs__container mejs__container-keyboard-inactive mediaelementjs media-player--inline mejs__video" tabindex="0" role="application" aria-label="Video Player" style="min-width: 319px;">
<div class="mejs__inner">
<div class="mejs__mediaelement">
<mediaelementwrapper id="mejs_someid">
<video width="640" height="480" preload="none" data-media-id="1234" data-mejsembed="1234" class="mediaelementjs media-player--inline" data-once="mediaelement" id="id1234" src="any_source">
What's happening then is big pipe is re-executing the behaviors. The 'data-once' has been applied to the <video>
, but it hasn't been applied to the new <div class="mejs_container">
, and since that also has the class of mediaelementjs, it is selected again with once and the player is applied again with additional wrapper HTML.
Proposed resolution
We need to ensure our selector doesn't select any other element other than the original. Since the original elements are always <video>
and <audio>
, and the generated code will never be another html media element, the simplest solution would be to use:
once('mediaElementPlayerInit', 'audio.mediaelementjs,video.mediaelementjs', context)
The benefit of this approach is that it will make more sense alongside the following code which is to optionally use this player for all audio and video elements globally.
$(once('mediaElementPlayerInit', 'audio,video', context))
Related changes included
- I've changed the once identifier to
mediaElementPlayerInit
which I think is a little descriptive.
- I've changed the function call for the
.each()
methods to include the automatically provided arguments of (i, e)
, which are the index and element respectively. This makes the actual call to mediaelement not have to rely on this
which is often a lot less error prone for future updates.
$(e).mediaelementplayer(settings.mediaelement);