percentPosition: true,
},
- player: {}, // Holds the Plyr instance
- playerInitialised: false,
- playerOptions: { // Settings used for Plyr instantiation (https://github.com/sampotts/plyr#options)
- debug: false,
- loadSprite: false, // Custom SVG sprite is already embedded in the page
- },
- playerType: '', // Set when opening the player: video or audio
- playerDuration: '00’00',
- playerTime: '00’00',
- playerTitle: '',
- playerImage: '',
-
- /****************\
- | Initialisation |
- \****************/
-
- init() {
- // Open player if querystring is already set
- let querystring = new URLSearchParams(location.search);
- let ID = querystring.get('id');
- if (ID) {
- let media = document.querySelector(`#media_${ID}`)
- if (media) {
- this.maskContents = true; // Hide page contents while player loads
- this.initPlayer('#player');
- this.openPlayer(JSON.parse(media.dataset.player), false);
- this.maskContents = false;
- }
- }
- },
-
/***********\
| Filtering |
\***********/
// Remove the filter from the array
this.activeThemeFilters = this.activeThemeFilters.filter(item => item !== filterID);
},
-
- /**************\
- | Media Player |
- \**************/
-
- initPlayer(selector) {
-
- if (this.playerInitialised) {
- return true; // Don't initialise player more than once
- }
-
- // Get custom controls HTML from the <template> tag
- this.playerOptions.controls = document.getElementById('playerControls').innerHTML;
-
- this.player = new Plyr(selector, this.playerOptions);
- window.player = this.player; // Make player object available in console
-
- this.player.on('loadedmetadata', event => {
- // Duration is only available once metadata is loaded
- this.playerDuration = this.formatTime(this.player.duration);
- });
-
- this.player.on('timeupdate', event => {
- // Reformat the time code every time it changes
- this.playerTime = this.formatTime(event.detail.plyr.currentTime);
- });
-
- this.playerInitialised = true;
- },
-
- openPlayer(sourceData, updateQuerystring = true) {
-
- if (updateQuerystring) {
- const location = new URL(window.location.href);
- location.searchParams.set('id', sourceData.ID);
- history.replaceState(null, document.title, location.toString());
- }
-
- this.playerType = sourceData.player.type;
- this.playerTitle = sourceData.title;
- this.playerImage = sourceData.image;
- this.player.source = sourceData.player;
- this.player.play();
- this.playerOpen = true;
- },
-
- closePlayer() {
- this.player.stop();
- this.playerOpen = false;
-
- // Update the page URL to remove querystring
- const location = new URL(window.location.href);
- location.searchParams.delete('id');
- history.replaceState(null, document.title, location.toString());
- },
-
- formatTime(rawSeconds) {
- let minutes = Math.trunc(rawSeconds / 60).toString().padStart(2, '0'),
- seconds = Math.trunc(rawSeconds % 60).toString().padStart(2, '0');
-
- return `${minutes}’${seconds}`;
- },
-
});
@push('before_scripts')
<script src="{{ asset('js/plyr.js') }}"></script>
+ <script>
+ function player() {
+ return {
+ player: {}, // Holds the Plyr instance
+ playerInitialised: false,
+ playerOptions: { // Settings used for Plyr instantiation (https://github.com/sampotts/plyr#options)
+ debug: false,
+ loadSprite: false, // Custom SVG sprite is already embedded in the page
+ },
+ playerType: '', // Set when opening the player: video or audio
+ playerDuration: '00’00',
+ playerTime: '00’00',
+ playerTitle: '',
+ playerImage: '',
+
+ /****************\
+ | Initialisation |
+ \****************/
+
+ init() {
+
+ console.log('initplayer...')
+
+ // Open player if querystring is already set
+ let querystring = new URLSearchParams(location.search);
+ let ID = querystring.get('id');
+ if (ID) {
+ let media = document.querySelector(`#media_${ID}`)
+ if (media) {
+ this.maskContents = true; // Hide page contents while player loads
+ this.initPlayer('#player');
+ this.openPlayer(JSON.parse(media.dataset.player), false);
+ this.maskContents = false;
+ }
+ }
+ },
+
+ /**************\
+ | Media Player |
+ \**************/
+
+ initPlayer(selector) {
+
+ if (this.playerInitialised) {
+ return true; // Don't initialise player more than once
+ }
+
+ // Get custom controls HTML from the <template> tag
+ this.playerOptions.controls = document.getElementById('playerControls').innerHTML;
+
+ this.player = new Plyr(selector, this.playerOptions);
+ window.player = this.player; // Make player object available in console
+
+ this.player.on('loadedmetadata', event => {
+ // Duration is only available once metadata is loaded
+ this.playerDuration = this.formatTime(this.player.duration);
+ });
+
+ this.player.on('timeupdate', event => {
+ // Reformat the time code every time it changes
+ this.playerTime = this.formatTime(event.detail.plyr.currentTime);
+ });
+
+ this.playerInitialised = true;
+ },
+
+ openPlayer(sourceData, updateQuerystring = true) {
+
+ if (updateQuerystring) {
+ const location = new URL(window.location.href);
+ location.searchParams.set('id', sourceData.ID);
+ history.replaceState(null, document.title, location.toString());
+ }
+
+ this.playerType = sourceData.player.type;
+ this.playerTitle = sourceData.title;
+ this.playerImage = sourceData.image;
+ this.player.source = sourceData.player;
+ this.player.play();
+ this.playerOpen = true;
+ },
+
+ closePlayer() {
+ this.player.stop();
+ this.playerOpen = false;
+
+ // Update the page URL to remove querystring
+ const location = new URL(window.location.href);
+ location.searchParams.delete('id');
+ history.replaceState(null, document.title, location.toString());
+ },
+
+ formatTime(rawSeconds) {
+ let minutes = Math.trunc(rawSeconds / 60).toString().padStart(2, '0'),
+ seconds = Math.trunc(rawSeconds % 60).toString().padStart(2, '0');
+
+ return `${minutes}’${seconds}`;
+ },
+ }
+ }
+ </script>
@endpush
-{{-- Embed SVG sprite directly --}}
-<x-media-library.player-icons />
+{{-- Media Player --}}
+<div x-data="player()" @player-open.window="openPlayer($event.detail.sourceData)">
-<div class="overlay player-overlay
+ {{-- Embed SVG sprite directly --}}
+ <x-media-library.player-icons />
+
+ <div class="overlay player-overlay
bg-white text-black
z-20"
- x-show="playerOpen"
- x-transition:enter.opacity.duration.500ms
- x-transition:leave.opacity.duration.200ms
- x-cloak>
-
- <x-close @click.prevent="closePlayer()" />
-
- <div class="w-full" x-init="initPlayer('#player')">
- {{-- Plyr placeholder --}}
- {{--
- Originally this should have been initialised using a simple div (non progressively enhanced method)
- because the type of player (video or audio) is determined when opening the player and setting the source.
- However, this doesn't work correctly, so we need to put a placeholder video tag that we can use to
- initialise the Plyr. The source setter automatically handles switching between video and audio modes.
- Ref: https://github.com/sampotts/plyr#the-source-setter
-
- For the initialisation, I wanted to use the same pattern as for Isotope, ie. x-init="initPlayer($el)" but
- this fires the initialisation multiple times for some reason. It doesn't seem to be AlpineJS firing it
- multiple times but I also don't see why Plyr would behave this way when passing a HTMLElement to it.
- Instead, initialisation is done via ID, called on the wrapping element above: initPlayer('#player')
- --}}
- <video id="player" playsinline controls></video>
- </div>
-
- {{-- Custom player controls: used when initialising the Plyr --}}
- {{-- Ref: https://github.com/sampotts/plyr/blob/master/CONTROLS.md --}}
- <template id="playerControls">
- <div class="plyr__controls">
-
- {{-- Player Image / Poster --}}
- <div x-show="playerType === 'audio'"
- class="rounded-md bg-cover bg-center flex-shrink-0 mr-10"
- :style="`width:200px; height:200px; background-color:#ddd; background-image:url(${playerImage})`"></div>
-
- <div class="w-full">
-
- <h2 x-show="playerType === 'audio'"
- x-text="playerTitle"
- class="font-semibold text-6xl text-left mb-3 max-w-[700px]"></h2>
-
- <div class="plyr__progress mb-1">
- <input data-plyr="seek" type="range" min="0" max="100" step="0.01" value="0" aria-label="Seek">
- <progress class="plyr__progress__buffer" min="0" max="100" value="0">% buffered</progress>
- <span role="tooltip" class="plyr__tooltip">00:00</span>
- </div>
+ x-show="playerOpen"
+ x-transition:enter.opacity.duration.500ms
+ x-transition:leave.opacity.duration.200ms
+ x-cloak>
+
+ <x-close @click.prevent="closePlayer()" />
+
+ <div class="w-full" x-init="initPlayer('#player')">
+ {{-- Plyr placeholder --}}
+ {{--
+ Originally this should have been initialised using a simple div (non progressively enhanced method)
+ because the type of player (video or audio) is determined when opening the player and setting the source.
+ However, this doesn't work correctly, so we need to put a placeholder video tag that we can use to
+ initialise the Plyr. The source setter automatically handles switching between video and audio modes.
+ Ref: https://github.com/sampotts/plyr#the-source-setter
+
+ For the initialisation, I wanted to use the same pattern as for Isotope, ie. x-init="initPlayer($el)" but
+ this fires the initialisation multiple times for some reason. It doesn't seem to be AlpineJS firing it
+ multiple times but I also don't see why Plyr would behave this way when passing a HTMLElement to it.
+ Instead, initialisation is done via ID, called on the wrapping element above: initPlayer('#player')
+ --}}
+ <video id="player" playsinline controls></video>
+ </div>
- <div class="flex justify-between items-center">
-
- {{-- Left side --}}
- <div class="flex items-center">
- {{-- Play / Pause button --}}
- <button type="button" class="plyr__control" aria-label="Play, {title}" data-plyr="play">
- <svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-pause"></use></svg>
- <svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-play"></use></svg>
- <span class="label--pressed plyr__tooltip" role="tooltip">Pause</span>
- <span class="label--not-pressed plyr__tooltip" role="tooltip">Play</span>
- </button>
-
- {{-- Volume Mute --}}
- <button type="button" class="plyr__control" aria-label="Mute" data-plyr="mute">
- <svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-muted"></use></svg>
- <svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-volume"></use></svg>
- <span class="label--pressed plyr__tooltip" role="tooltip">Unmute</span>
- <span class="label--not-pressed plyr__tooltip" role="tooltip">Mute</span>
- </button>
-
- {{-- Volume slider --}}
- <div class="plyr__volume">
- <input data-plyr="volume" type="range" min="0" max="1" step="0.05" value="1" autocomplete="off" aria-label="Volume">
- </div>
+ {{-- Custom player controls: used when initialising the Plyr --}}
+ {{-- Ref: https://github.com/sampotts/plyr/blob/master/CONTROLS.md --}}
+ <template id="playerControls">
+ <div class="plyr__controls">
+
+ {{-- Player Image / Poster --}}
+ <div x-show="playerType === 'audio'"
+ class="rounded-md bg-cover bg-center flex-shrink-0 mr-10"
+ :style="`width:200px; height:200px; background-color:#ddd; background-image:url(${playerImage})`"></div>
+
+ <div class="w-full">
+
+ <h2 x-show="playerType === 'audio'"
+ x-text="playerTitle"
+ class="font-semibold text-6xl text-left mb-3 max-w-[700px]"></h2>
+
+ <div class="plyr__progress mb-1">
+ <input data-plyr="seek" type="range" min="0" max="100" step="0.01" value="0" aria-label="Seek">
+ <progress class="plyr__progress__buffer" min="0" max="100" value="0">% buffered</progress>
+ <span role="tooltip" class="plyr__tooltip">00:00</span>
</div>
- {{-- Right side --}}
- <div class="flex items-center font-secondary text-current">
- {{-- Time codes --}}
- <span class="plyr-timecode" x-html="playerTime"></span>
- <span class="mx-2 opacity-50">/</span>
- <span class="plyr-timecode opacity-50" x-html="playerDuration"></span>
+ <div class="flex justify-between items-center">
+
+ {{-- Left side --}}
+ <div class="flex items-center">
+ {{-- Play / Pause button --}}
+ <button type="button" class="plyr__control" aria-label="Play, {title}" data-plyr="play">
+ <svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-pause"></use></svg>
+ <svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-play"></use></svg>
+ <span class="label--pressed plyr__tooltip" role="tooltip">Pause</span>
+ <span class="label--not-pressed plyr__tooltip" role="tooltip">Play</span>
+ </button>
+
+ {{-- Volume Mute --}}
+ <button type="button" class="plyr__control" aria-label="Mute" data-plyr="mute">
+ <svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-muted"></use></svg>
+ <svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-volume"></use></svg>
+ <span class="label--pressed plyr__tooltip" role="tooltip">Unmute</span>
+ <span class="label--not-pressed plyr__tooltip" role="tooltip">Mute</span>
+ </button>
+
+ {{-- Volume slider --}}
+ <div class="plyr__volume">
+ <input data-plyr="volume" type="range" min="0" max="1" step="0.05" value="1" autocomplete="off" aria-label="Volume">
+ </div>
+ </div>
+
+ {{-- Right side --}}
+ <div class="flex items-center font-secondary text-current">
+ {{-- Time codes --}}
+ <span class="plyr-timecode" x-html="playerTime"></span>
+ <span class="mx-2 opacity-50">/</span>
+ <span class="plyr-timecode opacity-50" x-html="playerDuration"></span>
+ </div>
+
</div>
+ {{-- Fullscreen --}}
+ {{--
+ <button type="button" class="plyr__control" data-plyr="fullscreen">
+ <svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-exit-fullscreen"></use></svg>
+ <svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-enter-fullscreen"></use></svg>
+ <span class="label--pressed plyr__tooltip" role="tooltip">Exit fullscreen</span>
+ <span class="label--not-pressed plyr__tooltip" role="tooltip">Enter fullscreen</span>
+ </button>
+ --}}
</div>
- {{-- Fullscreen --}}
- {{--
- <button type="button" class="plyr__control" data-plyr="fullscreen">
- <svg class="icon--pressed" role="presentation"><use xlink:href="#plyr-exit-fullscreen"></use></svg>
- <svg class="icon--not-pressed" role="presentation"><use xlink:href="#plyr-enter-fullscreen"></use></svg>
- <span class="label--pressed plyr__tooltip" role="tooltip">Exit fullscreen</span>
- <span class="label--not-pressed plyr__tooltip" role="tooltip">Enter fullscreen</span>
- </button>
- --}}
</div>
+ </template>
- </div>
- </template>
-
-</div>
+ </div> {{-- .player-overlay --}}
+</div> {{-- .player-wrapper --}}