]> _ Git - odl.git/commitdiff
Refactor media player for reuse on other pages. WIP #5022 @3
authorStephen Cameron <stephen@cubedesigners.com>
Thu, 13 Jan 2022 17:54:50 +0000 (18:54 +0100)
committerStephen Cameron <stephen@cubedesigners.com>
Thu, 13 Jan 2022 17:54:50 +0000 (18:54 +0100)
resources/js/media-library.js
resources/views/components/media-library/index.blade.php
resources/views/components/media-library/player.blade.php
resources/views/front/home.blade.php

index 3317a15bbff8873f0fc91250257255a62359df4f..c6a11f8f6be07c34f9e90a83122e8f710009a324 100644 (file)
@@ -12,37 +12,6 @@ export default (options = {}) => ({
         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&rsquo;00',
-    playerTime: '00&rsquo;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 |
     \***********/
@@ -106,67 +75,4 @@ export default (options = {}) => ({
         // 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}&rsquo;${seconds}`;
-    },
-
 });
index 6f39110cb5ddb7dfc46d293e4cde26cb9f9afb63..2da4d502b4599a77d86cb5bc3928573131456f18 100644 (file)
         @foreach ($media as $item)
 
             @php
-                $filters=[];
-                if(!is_array($item['theme'])){
-                    $item['theme']=[$item['theme']];
+                $filters = [];
+                if (!is_array($item['theme'])) {
+                    $item['theme'] = [$item['theme']];
                 }
-                foreach ($item['theme'] as $t){
-                    $filters[]='theme-'.$t;
+                foreach ($item['theme'] as $t) {
+                    $filters[] = 'theme-'.$t;
                 }
-                $theme=$themes[$item['theme'][0]];
+                $theme = $themes[$item['theme'][0]];
                 $player_data = [
                     'ID' => $item['id'],
                     'player' => [
@@ -55,7 +55,7 @@
             @endphp
 
             <div id="media_{{ $item['id'] }}"
-                 @click="openPlayer(JSON.parse($el.dataset.player))"
+                 @click="$dispatch('player-open', { sourceData: JSON.parse($el.dataset.player) })"
                  data-player='{{ json_encode($player_data) }}'
                  class="media-item group cursor-pointer
                         {{-- Width is 25% minus the gutters (2 * 0.625rem that comes from mx-2.5) --}}
index fade53d8e8d6cbd2091f7b7327fb6248da22684a..c9e05ac4e42d396ca5f3db83a1f808431859307b 100644 (file)
 
 @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&rsquo;00',
+                playerTime: '00&rsquo;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}&rsquo;${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 --}}
index 9dd83934592b22781ea5096d192a0f7fc12e76e5..1b502251f9e5efff485455605f3b22d9cde37ad3 100644 (file)
@@ -41,8 +41,8 @@
         {{-- Link blocks --}}
         <div class="grid grid-cols-3 gap-6 text-center lg:text-left" x-data="{ shown: false }"
              x-intersect="shown = true">
-            @if(null!==$home->get('raccourcis'))
-                @foreach($home->get('raccourcis') as $shortcut)
+            @if (null !== $home->get('raccourcis'))
+                @foreach ($home->get('raccourcis') as $shortcut)
                     <x-link :href="$shortcut['link']"
                             class="group relative
                                flex flex-col lg:flex-row items-center
@@ -69,4 +69,6 @@
 
     </div>
 
+    <x-media-library.player/>
+
 @endsection