From 4b43d4c9e75d9669ea384545dac8ae9943b260e5 Mon Sep 17 00:00:00 2001 From: Tim Hobbs Date: Wed, 5 Mar 2014 05:56:15 -0800 Subject: [PATCH] Video player enhancements BlockUI style backdrop, escape key exits video, click video to toggle playback, dbl-click to toggle fullscreen. --- dashboard-ui/css/mediaplayer.css | 118 ++++++++++++++++++++++++++-- dashboard-ui/scripts/mediaplayer.js | 107 ++++++++++++++++++++----- 2 files changed, 199 insertions(+), 26 deletions(-) diff --git a/dashboard-ui/css/mediaplayer.css b/dashboard-ui/css/mediaplayer.css index e332d06f4..35dd7b44a 100644 --- a/dashboard-ui/css/mediaplayer.css +++ b/dashboard-ui/css/mediaplayer.css @@ -74,10 +74,14 @@ z-index: 99998; background: #000; border: 1px solid #444; + width: 320px; + cursor: pointer; + margin: 20px; position: fixed; top: 50%; left: 50%; - width: 320px; + margin-left: -160px; + margin-top: -90px; } .fullscreenVideo { @@ -93,6 +97,71 @@ margin: 0 !important; } +#videoBackdrop { + z-index: 99990; + position: fixed; + background-color: transparent; + background-color: rgba(0, 0, 0, 0.6); + top: 0; + right: 0; + bottom: 0; + left: 0; +} + +#videoPlayer { + z-index: 99997; + background: #1d1d1d; + position: fixed; + overflow: hidden; + border: 1px solid green; + top: 50%; + left: 50%; + margin-left: -170px; + margin-top: -115px; +} + +#videoPlayer.fullscreenVideo, +.fullscreenVideo .itemVideo { + position: fixed !important; + top: 0 !important; + bottom: 0 !important; + right: 0 !important; + left: 0 !important; + width: 100% !important; + height: 100% !important; + border: 0 !important; + z-index: 999999 !important; + margin: 0 !important; +} + + #videoPlayer #mediaElement { + position: absolute; + top: 0; + left: 0; + } + + #videoPlayer .itemVideo { + position: static; + margin: 0; + margin: 20px 20px 60px; + } + + #videoPlayer .nowPlayingBar { + padding: 0; + border: none !important; + height: 40px; + overflow: hidden; + background-color: #1d1d1d; + position: absolute; + right: 0; + bottom: 10px; + left: 0; + } + + #videoPlayer .nowPlayingBar .barBackground { + display: none; + } + .currentTime { display: inline-block; position: relative; @@ -284,36 +353,71 @@ input[type="range"]::-ms-fill-upper { padding-left: 5px; } -@media (min-width: 640px) { +@media (min-width: 640px) and (min-height: 360px) { .itemVideo:not(.fullscreenVideo) { width: 480px; + margin-left: -240px; + margin-top: -135px; + } + + #videoPlayer { + margin-left: -250px; + margin-top: -160px; } } -@media (min-width: 800px) { +@media (min-width: 800px) and (min-height: 450px) { .itemVideo:not(.fullscreenVideo) { width: 640px; + margin-left: -320px; + margin-top: -180px; + } + + #videoPlayer { + margin-left: -330px; + margin-top: -205px; } } -@media (min-width: 960px) { +@media (min-width: 960px) and (min-height: 540px) { .itemVideo:not(.fullscreenVideo) { width: 720px; + margin-left: -360px; + margin-top: -203px; + } + + #videoPlayer { + margin-left: -370px; + margin-top: -228px; } } -@media (min-width: 1200px) { +@media (min-width: 1200px) and (min-height: 720px) { .itemVideo:not(.fullscreenVideo) { width: 1080px; + margin-left: -540px; + margin-top: -304px; + } + + #videoPlayer { + margin-left: -550px; + margin-top: -329px; } } -@media (min-width: 1440px) { +@media (min-width: 1440px) and (min-height: 720px) { .itemVideo:not(.fullscreenVideo) { width: 1080px; + margin-left: -540px; + margin-top: -304px; + } + + #videoPlayer { + margin-left: -550px; + margin-top: -329px; } .positionSliderContainer { width: 300px; } -} +} \ No newline at end of file diff --git a/dashboard-ui/scripts/mediaplayer.js b/dashboard-ui/scripts/mediaplayer.js index bb3142c4d..7daca7cfd 100644 --- a/dashboard-ui/scripts/mediaplayer.js +++ b/dashboard-ui/scripts/mediaplayer.js @@ -20,6 +20,9 @@ var culturesPromise; var timeout; var idleState = true; + var mediaDomElement; + var isEnhanced = false; + var fullscreenExited; self.playlist = []; var currentPlaylistIndex = 0; @@ -40,10 +43,6 @@ } } - function enterFullScreen() { - $(".itemVideo").removeAttr("style").addClass("fullscreenVideo"); - } - function exitFullScreen() { if (document.exitFullscreen) { document.exitFullscreen(); @@ -52,10 +51,13 @@ } else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); } + + fullscreenExited = true; } function isFullScreen() { - return document.fullscreenEnabled || document.mozFullscreenEnabled || document.webkitIsFullScreen || document.mozFullScreen ? true : false; + return document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement ? true : false; + //return document.fullscreenEnabled || document.mozFullscreenEnabled || document.webkitIsFullScreen || document.mozFullScreen ? true : false; } $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange', function () { @@ -67,8 +69,7 @@ $('.itemVideo').on('mousemove keydown scroll', idleHandler).trigger('mousemove'); } else { $(".mediaButton,.currentTime,.nowPlayingMediaInfo,.sliderContainer,.barBackground", nowPlayingBar).removeClass("highPosition"); - $('.itemVideo').removeClass('fullscreenVideo'); - repositionPlayer(); + exitFullScreenToWindow(); } }); @@ -86,8 +87,6 @@ ApiClient.reportPlaybackStopped(Dashboard.getCurrentUserId(), currentItem.Id, position); } - }).on("resize", function () { - repositionPlayer(); }); function replaceQueryString(url, param, value) { @@ -129,6 +128,9 @@ if (currentItem.MediaType == "Video") { ApiClient.stopActiveEncodings(); + if (isEnhanced) { + resetEnhancements(); + } } } @@ -1116,6 +1118,8 @@ if (item.MediaType === "Video") { mediaElement = playVideo(item, startPosition, user); + + enhancePlayer(mediaElement); } else if (item.MediaType === "Audio") { mediaElement = playAudio(item, startPosition); @@ -1373,7 +1377,6 @@ document.webkitCancelFullScreen(); } else { $('.itemVideo').removeClass('fullscreenVideo'); - repositionPlayer(); } } else { requestFullScreen(document.body); @@ -1575,15 +1578,6 @@ return currentMediaElement; }; - function repositionPlayer() { - var $v = $(".itemVideo"); - // Reset top/left to handle window resizing - $v.css({ "top": "50%", "left": "50%" }); - var w = $v.width(); - var h = $v.height(); - $v.css({ "margin-top": (h / 2) * -1, "margin-left": (w / 2) * -1 }); - }; - function hideFlyout(flyout) { flyout.hide().empty(); @@ -1945,6 +1939,81 @@ }); }; + + function enhancePlayer(video) { + var nowPlayingBar = $("#nowPlayingBar"); + mediaDomElement = $("#mediaElement", nowPlayingBar).detach(); + + $(video) + .on("click", function () { + if (this.paused) { + self.unpause(); + } else { + self.pause(); + } + }) + .on("dblclick", function () { + self.toggleFullscreen(); + }); + + changeHandler("fullscreenchange"); + changeHandler("mozfullscreenchange"); + changeHandler("webkitfullscreenchange"); + changeHandler("msfullscreenchange"); + + $(document).on("keyup.enhancePlayer", function (e) { + if (fullscreenExited) { + fullscreenExited = false; + return; + } + + if (e.keyCode == 27) { + self.stop(); + $(this).unbind("keyup.enhancePlayer"); + } + }); + + + var videoBackdrop = $("
"); + var videoPlayer = $("
") + .append(video) + .append(nowPlayingBar); + $("#footer").append(videoBackdrop.append(videoPlayer)); + + video.play(); + + isEnhanced = true; + fullscreenExited = false; + }; + + function changeHandler(event) { + document.addEventListener(event, function () { + fullscreenExited = isFullScreen() == false; + }); + } + + function resetEnhancements() { + var nowPlayingBar = $("#nowPlayingBar"); + $("#stopButton", nowPlayingBar).before(mediaDomElement); + $("#footer").append(nowPlayingBar); + $("#videoBackdrop").remove(); + }; + + function enterFullScreen() { + var player = $(".itemVideo"); + if (isEnhanced) { + player = $("#videoPlayer") + } + player.addClass("fullscreenVideo"); + }; + + function exitFullScreenToWindow() { + var player = $(".itemVideo"); + if (isEnhanced) { + player = $("#videoPlayer") + } + player.removeClass("fullscreenVideo"); + } } window.MediaPlayer = new mediaPlayer();