Working version featuring Youtube video.

- tested with a single 49 Europeans file on Firefox and Chrome
- still an issue with Chrome playing sound even though everything is set to muted. --> Workaround: mute the video by choosing it in the sound track selection and then un-choose it again.
- issue with Youtube player when youtube is configured to use HTML5 player instead of Flash
This commit is contained in:
Jens Rommel committed 2013-01-10 18:07:19 +01:00
1 parent e6b42f162c
commit bb3168ad58
16 files changed
+567 -371

No files matched your search

@@ -1,4 +1,4 @@
eclipse.preferences.version=1
entryPointModules=
filesCopiedToWebInfLib=gwt-servlet.jar
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBWy13YXIgLiAtbG9jYWxXb3JrZXJzIDMgLXN0cmljdCAtbG9nTGV2ZWwgVFJBQ0VdXT48L2V4dHJhLWFyZ3M+PHZtLWFyZ3M+PCFbQ0RBVEFbLVhteDEwMjRtXV0+PC92bS1hcmdzPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5BZG1pbkNvbnNvbGU8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuTGVhZGVyYm9hcmRFZGl0aW5nPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlJhY2VCb2FyZDwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5TcGVjdGF0b3I8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVXNlck1hbmFnZW1lbnQ8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuVmlkZW9Qb3B1cDwvZW50cnktcG9pbnQtbW9kdWxlPjwvZ3d0LWNvbXBpbGUtc2V0dGluZ3M+
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+UFJFVFRZPC9vdXRwdXQtc3R5bGU+PGV4dHJhLWFyZ3M+PCFbQ0RBVEFbLXdhciAuIC1sb2NhbFdvcmtlcnMgMyAtc3RyaWN0IC1sb2dMZXZlbCBUUkFDRV1dPjwvZXh0cmEtYXJncz48dm0tYXJncz48IVtDREFUQVstWG14MTAyNG1dXT48L3ZtLWFyZ3M+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLkFkbWluQ29uc29sZTwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5MZWFkZXJib2FyZDwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5MZWFkZXJib2FyZEVkaXRpbmc8L2VudHJ5LXBvaW50LW1vZHVsZT48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5zYXAuc2FpbGluZy5nd3QudWkuUmFjZUJvYXJkPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLlNwZWN0YXRvcjwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5Vc2VyTWFuYWdlbWVudDwvZW50cnktcG9pbnQtbW9kdWxlPjxlbnRyeS1wb2ludC1tb2R1bGU+Y29tLnNhcC5zYWlsaW5nLmd3dC51aS5WaWRlb1BvcHVwPC9lbnRyeS1wb2ludC1tb2R1bGU+PGVudHJ5LXBvaW50LW1vZHVsZT5jb20uc2FwLnNhaWxpbmcuZ3d0LnVpLllvdXR1YmVQb3B1cDwvZW50cnktcG9pbnQtbW9kdWxlPjwvZ3d0LWNvbXBpbGUtc2V0dGluZ3M+
@@ -0,0 +1,18 @@
html {
overflow: auto;
}
html,body,div,iframe {
margin: 0px;
padding: 0px;
height: 100%;
border: none;
}
video {
display: block;
width: 100%;
border: none;
overflow-y: auto;
overflow-x: hidden;
}
@@ -4,6 +4,11 @@
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>SAP Sailing Video</title>
<script type="text/javascript" language="javascript" src="com.sap.sailing.gwt.ui.VideoPopup/com.sap.sailing.gwt.ui.VideoPopup.nocache.js"></script>
<style type="text/css">
html {overflow: auto;}
html, body, div, iframe {margin: 0px; padding: 0px; height: 100%; border: none;}
iframe {display: block; width: 100%; border: none; overflow-y: auto; overflow-x: hidden;}
</style>
</head>
<body>
@@ -4,6 +4,11 @@
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>SAP Sailing Video</title>
<script type="text/javascript" language="javascript" src="com.sap.sailing.gwt.ui.YoutubePopup/com.sap.sailing.gwt.ui.YoutubePopup.nocache.js"></script>
<style type="text/css">
html {overflow: auto;}
html, body, div, iframe {margin: 0px; padding: 0px; height: 100%; border: none;}
iframe {display: block; width: 100%; border: none; overflow-y: auto; overflow-x: hidden;}
</style>
</head>
<body>
@@ -29,6 +29,11 @@ bin.includes = META-INF/,\
Spectator.css,\
fontface.css,\
webfonts/,\
com.sap.sailing.gwt.ui.VideoPopup/,\
VideoPopup.html,\
VideoPopup.css,\
com.sap.sailing.gwt.ui.YoutubePopup/,\
YoutubePopup.html,\
TvView.html,\
com.sap.sailing.gwt.ui.TvView/
output.. = WEB-INF/classes/
@@ -5,7 +5,7 @@ import com.google.gwt.dom.client.MediaElement;
import com.google.gwt.media.client.Audio;
import com.sap.sailing.gwt.ui.shared.media.MediaTrack;
public class AudioControl extends AbstractMediaPlayer {
public class AudioPlayer extends AbstractMediaPlayer {
/**
* isReady and the ..Cache fields are required because setting the audio element's play state
@@ -19,7 +19,7 @@ public class AudioControl extends AbstractMediaPlayer {
private final Audio audio;
public AudioControl(MediaTrack mediaTrack) {
public AudioPlayer(MediaTrack mediaTrack) {
super(mediaTrack);
audio = Audio.createIfSupported();
if (audio != null) {
@@ -38,7 +38,7 @@ public class AudioControl extends AbstractMediaPlayer {
var that = this;
audioElement.addEventListener('canplay',
function() {
that.@com.sap.sailing.gwt.ui.raceboard.AudioControl::initPlayState()();
that.@com.sap.sailing.gwt.ui.raceboard.AudioPlayer::initPlayState()();
});
}-*/;
@@ -47,9 +47,9 @@ public class MediaSelectionDialog implements CloseHandler<PopupPanel> {
Panel grid = new VerticalPanel();
if (!audioTracks.isEmpty()) {
grid.add(createAudioHeader());
grid.add((RadioButton) createAudioItem(null, selectedAudioTrack));
grid.add((RadioButton) createAudioButton(null, selectedAudioTrack));
for (MediaTrack audioTrack : audioTracks) {
grid.add(createAudioItem(audioTrack, selectedAudioTrack));
grid.add(createAudioButton(audioTrack, selectedAudioTrack));
}
}
if (!videoTracks.isEmpty()) {
@@ -82,6 +82,13 @@ public class MediaSelectionDialog implements CloseHandler<PopupPanel> {
return videoCheckBox;
}
public void selectVideo(MediaTrack videoTrack) {
CheckBox videoCheckBox = videoCheckBoxes.get(videoTrack);
if (videoCheckBox != null) {
videoCheckBox.setValue(true);
}
}
public void unselectVideo(MediaTrack videoTrack) {
CheckBox videoCheckBox = videoCheckBoxes.get(videoTrack);
if (videoCheckBox != null) {
@@ -94,13 +101,13 @@ public class MediaSelectionDialog implements CloseHandler<PopupPanel> {
return audioHeader;
}
private Widget createAudioItem(final MediaTrack audioTrack, MediaTrack selectedAudioTrack) {
String title = audioTrack != null ? audioTrack.title: "Mute - play no sound";
String tooltip = audioTrack != null ? audioTrack.toString() : "Play no sound.";
RadioButton audioItem = new RadioButton("group-name", title);
audioItem.setTitle(tooltip);
audioItem.setValue(audioTrack == selectedAudioTrack);
audioItem.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
private Widget createAudioButton(final MediaTrack audioTrack, MediaTrack selectedAudioTrack) {
String title = audioTrack != null ? audioTrack.title: "Sound off";
String tooltip = audioTrack != null ? audioTrack.toString() : "Turn off all sound channels.";
RadioButton audioButton = new RadioButton("group-name", title);
audioButton.setTitle(tooltip);
audioButton.setValue(audioTrack == selectedAudioTrack);
audioButton.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
@Override
public void onValueChange(ValueChangeEvent<Boolean> changeEvent) {
@@ -109,7 +116,7 @@ public class MediaSelectionDialog implements CloseHandler<PopupPanel> {
}
}
});
return audioItem;
return audioButton;
}
private Widget createAudioHeader() {
@@ -33,7 +33,7 @@ import com.sap.sailing.gwt.ui.client.TimeListener;
import com.sap.sailing.gwt.ui.client.Timer.PlayModes;
import com.sap.sailing.gwt.ui.client.Timer.PlayStates;
import com.sap.sailing.gwt.ui.raceboard.MediaSelectionDialog.MediaSelectionListener;
import com.sap.sailing.gwt.ui.raceboard.VideoControl.VideoCloseListener;
import com.sap.sailing.gwt.ui.raceboard.PopupWindowPlayer.PopupCloseListener;
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
import com.sap.sailing.gwt.ui.shared.media.MediaTrack;
@@ -47,7 +47,7 @@ public class MediaSelector implements RaceTimesInfoProviderListener, PlayStateLi
private final AudioElement mediaCanPlayTester;
private MediaPlayer activeAudioPlayer;
private final Map<MediaTrack, VideoControl> videoPlayers = new HashMap<MediaTrack, VideoControl>();
private final Map<MediaTrack, MediaPlayer> videoPlayers = new HashMap<MediaTrack, MediaPlayer>();
private final Set<MediaTrack> audioTracks = new HashSet<MediaTrack>();
private final Set<MediaTrack> videoTracks = new HashSet<MediaTrack>();
private final ErrorReporter errorReporter;
@@ -113,11 +113,15 @@ public class MediaSelector implements RaceTimesInfoProviderListener, PlayStateLi
private boolean canPlay(MediaTrack mediaTrack) {
if (mediaCanPlayTester != null) {
String canPlay = mediaCanPlayTester.canPlayType(mediaTrack.typeToString());
if (mediaCanPlayTester != null) {
return MediaElement.CAN_PLAY_PROBABLY.equals(canPlay) || MediaElement.CAN_PLAY_MAYBE.equals(canPlay);
if (mediaTrack.isYoutube()) {
return true;
} else {
return false;
String canPlay = mediaCanPlayTester.canPlayType(mediaTrack.typeToString());
if (mediaCanPlayTester != null) {
return MediaElement.CAN_PLAY_PROBABLY.equals(canPlay) || MediaElement.CAN_PLAY_MAYBE.equals(canPlay);
} else {
return false;
}
}
} else {
return false;
@@ -183,7 +187,7 @@ public class MediaSelector implements RaceTimesInfoProviderListener, PlayStateLi
if (activeAudioPlayer != null) {
activeAudioPlayer.setPlaybackSpeed(this.currentPlaybackSpeed);
}
for (VideoControl videoPlayer : videoPlayers.values()) {
for (MediaPlayer videoPlayer : videoPlayers.values()) {
videoPlayer.setPlaybackSpeed(this.currentPlaybackSpeed);
}
}
@@ -258,7 +262,7 @@ public class MediaSelector implements RaceTimesInfoProviderListener, PlayStateLi
@Override
public void audioChanged(MediaTrack audioTrack) {
if (activeAudioPlayer != null) {
if (activeAudioPlayer != null) { // --> then reset active audio player
if (activeAudioPlayer.getMediaTrack() == audioTrack) {
return; //nothing changed
@@ -266,12 +270,16 @@ public class MediaSelector implements RaceTimesInfoProviderListener, PlayStateLi
if (videoPlayers.containsKey(activeAudioPlayer.getMediaTrack())) { //pre-change audioPlayer is one of the videoPlayers
activeAudioPlayer.setMuted(true);
} else {//pre-change audioPlayer is a dedicated audio-only player
} else { //pre-change audioPlayer is a dedicated audio-only player
activeAudioPlayer.destroy();
}
activeAudioPlayer = null;
}
VideoControl playingVideo = videoPlayers.get(audioTrack);
if ((audioTrack != null) && audioTrack.isYoutube()) { // --> Youtube videos can't be played for audio-only. So add a video player first.
videoSelected(audioTrack);
mediaSelectionDialog.selectVideo(audioTrack);
}
MediaPlayer playingVideo = videoPlayers.get(audioTrack);
if (playingVideo != null) {
activeAudioPlayer = playingVideo;
activeAudioPlayer.setMuted(false);
@@ -285,23 +293,29 @@ public class MediaSelector implements RaceTimesInfoProviderListener, PlayStateLi
@Override
public void videoSelected(final MediaTrack videoTrack) {
VideoControl playingVideo = videoPlayers.get(videoTrack);
MediaPlayer playingVideo = videoPlayers.get(videoTrack);
if (playingVideo == null) {
final VideoControl videoControl = new VideoControl(videoTrack, new VideoCloseListener() {
PopupCloseListener popCloseListener = new PopupCloseListener() {
@Override
public void onVideoClosed() {
public void popupClosed() {
videoDeselected(videoTrack);
}
});
videoPlayers.put(videoTrack, videoControl);
};
final PopupWindowPlayer popupPlayer;
if (videoTrack.isYoutube()) {
popupPlayer = new YoutubeWindowPlayer(videoTrack, popCloseListener);
} else {
popupPlayer = new VideoWindowPlayer(videoTrack, popCloseListener);
}
videoPlayers.put(videoTrack, popupPlayer);
if ((activeAudioPlayer != null) && (activeAudioPlayer.getMediaTrack() == videoTrack)) { //selected video track has been playing as audio-only
activeAudioPlayer.pause();
activeAudioPlayer = videoControl;
videoControl.setMuted(false);
activeAudioPlayer = popupPlayer;
popupPlayer.setMuted(false);
} else {
videoControl.setMuted(true);
popupPlayer.setMuted(true);
}
synchPlayState(videoControl);
synchPlayState(popupPlayer);
} else {
//nothing changed
}
@@ -313,10 +327,14 @@ public class MediaSelector implements RaceTimesInfoProviderListener, PlayStateLi
@Override
public void videoDeselected(MediaTrack videoTrack) {
mediaSelectionDialog.unselectVideo(videoTrack);
VideoControl removedVideoPlayer = videoPlayers.remove(videoTrack);
MediaPlayer removedVideoPlayer = videoPlayers.remove(videoTrack);
removedVideoPlayer.destroy();
if (removedVideoPlayer == activeAudioPlayer) { //in case this video has been the sound source, replace the video player with a dedicated audio player
assignNewAudioPlayer(removedVideoPlayer.getMediaTrack());
if (removedVideoPlayer.getMediaTrack().isYoutube()) {
assignNewAudioPlayer(null);
} else {
assignNewAudioPlayer(removedVideoPlayer.getMediaTrack());
}
}
updateToggleButton();
@@ -329,7 +347,7 @@ public class MediaSelector implements RaceTimesInfoProviderListener, PlayStateLi
private void assignNewAudioPlayer(MediaTrack audioTrack) {
if (audioTrack != null) {
activeAudioPlayer = new AudioControl(audioTrack);
activeAudioPlayer = new AudioPlayer(audioTrack);
synchPlayState(activeAudioPlayer);
} else {
@@ -373,7 +391,7 @@ public class MediaSelector implements RaceTimesInfoProviderListener, PlayStateLi
activeAudioPlayer.destroy();
activeAudioPlayer = null;
}
for (VideoControl videoControl : videoPlayers.values()) {
for (MediaPlayer videoControl : videoPlayers.values()) {
videoControl.destroy();
}
videoPlayers.clear();
@@ -1,150 +1,149 @@
package com.sap.sailing.gwt.ui.raceboard;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Window;
import com.sap.sailing.gwt.ui.shared.media.MediaTrack;
public class VideoControl extends AbstractMediaPlayer {
interface VideoCloseListener {
void onVideoClosed();
}
private final JavaScriptObject playerWindow;
private final VideoCloseListener videoCloseListener;
public VideoControl(MediaTrack mediaTrack, VideoCloseListener videoCloseListener) {
super(mediaTrack);
this.videoCloseListener = videoCloseListener;
String videoUrl = getMediaTrack().url;
String title = getMediaTrack().title;
String videoPlayerUrl = "/gwt/VideoPopup.html?url=" + URL.encodeQueryString(videoUrl) + "&title=" + URL.encodeQueryString(title);
String codesvr = Window.Location.getParameter("gwt.codesvr");
if (codesvr != null) {
videoPlayerUrl = videoPlayerUrl + "&gwt.codesvr=" + codesvr;
}
playerWindow = openWindow(videoPlayerUrl);
registerNativeStuff();
}
native JavaScriptObject openWindow(String url) /*-{
return $wnd.open(url, '_blank', "resizable=yes, scrollbars=no, toolbar=no, menubar=no, status=no, location=no, directories=no, personalbar=no, width=340, height=200");
}-*/;
@Override
public native void destroy() /*-{
var playerWindow = this.@com.sap.sailing.gwt.ui.raceboard.VideoControl::playerWindow;
if (!playerWindow.closed) {
playerWindow.close();
}
}-*/;
native JavaScriptObject registerNativeStuff() /*-{
var that = this;
var window = that.@com.sap.sailing.gwt.ui.raceboard.VideoControl::playerWindow;
window.onbeforeunload = function() {
that.@com.sap.sailing.gwt.ui.raceboard.VideoControl::onClosingPopup()();
}
window.parent.deferredPlayState = {
isDeferredPlaying: false,
isDeferredMuted: true,
deferredMediaTime: 0,
playbackSpeed: 1
};
}-*/;
private void onClosingPopup() {
pause();
if (videoCloseListener != null) {
videoCloseListener.onVideoClosed();
}
}
@Override
public native void play() /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.VideoControl::playerWindow;
if (!window.parent.videoPlayer) {
window.parent.deferredPlayState.isDeferredPlaying = true;
} else {
window.parent.videoPlayer.play();
}
}-*/;
@Override
public native void pause() /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.VideoControl::playerWindow;
if (!window.parent.videoPlayer) {
window.parent.deferredPlayState.isDeferredPlaying = false;
} else {
window.parent.videoPlayer.pause();
}
}-*/;
@Override
public native void setTime(double mediaTime) /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.VideoControl::playerWindow;
if (!window.parent.videoPlayer) {
window.parent.deferredPlayState.deferredMediaTime = mediaTime;
} else {
window.parent.videoPlayer.setTime(mediaTime);
}
}-*/;
@Override
public native void setMuted(boolean muted) /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.VideoControl::playerWindow;
if (!window.parent.videoPlayer) {
window.parent.deferredPlayState.isDeferredMuted = muted;
} else {
window.parent.videoPlayer.setMuted(muted);
}
}-*/;
@Override
public native boolean isPaused() /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.VideoControl::playerWindow;
if (!window.parent.videoPlayer) {
return !window.parent.deferredPlayState.isDeferredPlaying;
} else {
return window.parent.videoPlayer.isPaused();
}
}-*/;
@Override
public native double getDuration() /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.VideoControl::playerWindow;
if (!window.parent.videoPlayer) {
return NaN;
} else {
return window.parent.videoPlayer.getDuration();
}
}-*/;
@Override
public native double getTime() /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.VideoControl::playerWindow;
if (!window.parent.videoPlayer) {
return window.parent.deferredPlayState.deferredMediaTime;
} else {
return window.parent.videoPlayer.getTime();
}
}-*/;
@Override
public native void setPlaybackSpeed(double playbackSpeed) /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.VideoControl::playerWindow;
if (!window.parent.videoPlayer) {
window.parent.deferredPlayState.deferredPlaybackSpeed = playbackSpeed;
} else {
window.parent.videoPlayer.setPlaybackSpeed(playbackSpeed);
}
}-*/;
}
package com.sap.sailing.gwt.ui.raceboard;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.Window;
import com.sap.sailing.gwt.ui.shared.media.MediaTrack;
public abstract class PopupWindowPlayer extends AbstractMediaPlayer {
interface PopupCloseListener {
void popupClosed();
}
private final JavaScriptObject playerWindow;
private final PopupCloseListener popupCloseListener;
protected PopupWindowPlayer(MediaTrack mediaTrack, PopupCloseListener popupCloseListener) {
super(mediaTrack);
this.popupCloseListener = popupCloseListener;
String playerWindowUrl = getPlayerWindowUrl();
String codesvr = Window.Location.getParameter("gwt.codesvr");
if (codesvr != null) {
playerWindowUrl = playerWindowUrl + "&gwt.codesvr=" + codesvr;
}
playerWindow = openWindow(playerWindowUrl);
registerNativeStuff();
}
protected abstract String getPlayerWindowUrl();
native JavaScriptObject openWindow(String url) /*-{
return $wnd.open(url, '_blank', "resizable=yes, scrollbars=no, toolbar=no, menubar=no, status=no, location=no, directories=no, personalbar=no, width=660, height=380");
}-*/;
@Override
public native void destroy() /*-{
var playerWindow = this.@com.sap.sailing.gwt.ui.raceboard.PopupWindowPlayer::playerWindow;
if (!playerWindow.closed) {
playerWindow.close();
}
}-*/;
native JavaScriptObject registerNativeStuff() /*-{
var that = this;
var window = that.@com.sap.sailing.gwt.ui.raceboard.PopupWindowPlayer::playerWindow;
window.onbeforeunload = function() {
that.@com.sap.sailing.gwt.ui.raceboard.PopupWindowPlayer::onClosingPopup()();
}
window.parent.deferredPlayState = {
isDeferredPlaying: false,
isDeferredMuted: true,
deferredMediaTime: 0,
playbackSpeed: 1
};
}-*/;
private void onClosingPopup() {
pause();
if (popupCloseListener != null) {
popupCloseListener.popupClosed();
}
}
@Override
public native void play() /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.PopupWindowPlayer::playerWindow;
if (!window.parent.videoPlayer) {
window.parent.deferredPlayState.isDeferredPlaying = true;
} else {
window.parent.videoPlayer.play();
}
}-*/;
@Override
public native void pause() /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.PopupWindowPlayer::playerWindow;
if (!window.parent.videoPlayer) {
window.parent.deferredPlayState.isDeferredPlaying = false;
} else {
window.parent.videoPlayer.pause();
}
}-*/;
@Override
public native void setTime(double mediaTime) /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.PopupWindowPlayer::playerWindow;
if (!window.parent.videoPlayer) {
window.parent.deferredPlayState.deferredMediaTime = mediaTime;
} else {
window.parent.videoPlayer.setTime(mediaTime);
}
}-*/;
@Override
public native void setMuted(boolean muted) /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.PopupWindowPlayer::playerWindow;
if (!window.parent.videoPlayer) {
window.parent.deferredPlayState.isDeferredMuted = muted;
} else {
window.parent.videoPlayer.setMuted(muted);
}
}-*/;
@Override
public native boolean isPaused() /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.PopupWindowPlayer::playerWindow;
if (!window.parent.videoPlayer) {
return !window.parent.deferredPlayState.isDeferredPlaying;
} else {
return window.parent.videoPlayer.isPaused();
}
}-*/;
@Override
public native double getDuration() /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.PopupWindowPlayer::playerWindow;
if (!window.parent.videoPlayer) {
return NaN;
} else {
return window.parent.videoPlayer.getDuration();
}
}-*/;
@Override
public native double getTime() /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.PopupWindowPlayer::playerWindow;
if (!window.parent.videoPlayer) {
return window.parent.deferredPlayState.deferredMediaTime;
} else {
return window.parent.videoPlayer.getTime();
}
}-*/;
@Override
public native void setPlaybackSpeed(double playbackSpeed) /*-{
var window = this.@com.sap.sailing.gwt.ui.raceboard.PopupWindowPlayer::playerWindow;
if (!window.parent.videoPlayer) {
window.parent.deferredPlayState.deferredPlaybackSpeed = playbackSpeed;
} else {
window.parent.videoPlayer.setPlaybackSpeed(playbackSpeed);
}
}-*/;
}
@@ -0,0 +1,22 @@
package com.sap.sailing.gwt.ui.raceboard;
import com.google.gwt.http.client.URL;
import com.sap.sailing.gwt.ui.shared.media.MediaTrack;
public class VideoWindowPlayer extends PopupWindowPlayer {
public VideoWindowPlayer(MediaTrack mediaTrack, PopupCloseListener popCloseListener) {
super(mediaTrack, popCloseListener);
}
@Override
protected String getPlayerWindowUrl() {
String videoUrl = getMediaTrack().url;
String title = getMediaTrack().title;
String videoPlayerUrl = "/gwt/VideoPopup.html?url=" + URL.encodeQueryString(videoUrl) + "&title=" + URL.encodeQueryString(title);
return videoPlayerUrl;
}
}
@@ -0,0 +1,22 @@
package com.sap.sailing.gwt.ui.raceboard;
import com.google.gwt.http.client.URL;
import com.sap.sailing.gwt.ui.shared.media.MediaTrack;
public class YoutubeWindowPlayer extends PopupWindowPlayer {
public YoutubeWindowPlayer(MediaTrack mediaTrack, PopupCloseListener popupCloseListener) {
super(mediaTrack, popupCloseListener);
}
@Override
protected String getPlayerWindowUrl() {
String youtubeId = getMediaTrack().url;
String title = getMediaTrack().title;
String youtubePlayerUrl = "/gwt/YoutubePopup.html?id=" + URL.encodeQueryString(youtubeId) + "&title=" + URL.encodeQueryString(title);
return youtubePlayerUrl;
}
}
@@ -13,7 +13,7 @@ public class MediaTrack implements IsSerializable {
public enum MimeType {
mp4(MediaType.video, MediaSubType.mp4), ogv(MediaType.video, MediaSubType.ogg), qt(MediaType.video, MediaSubType.quicktime), mp3(MediaType.audio, MediaSubType.mpeg), ogg(MediaType.audio, MediaSubType.ogg), aac(MediaType.audio, MediaSubType.aac), webm(MediaType.video, MediaSubType.webm);
mp4(MediaType.video, MediaSubType.mp4), ogv(MediaType.video, MediaSubType.ogg), qt(MediaType.video, MediaSubType.quicktime), mp3(MediaType.audio, MediaSubType.mpeg), ogg(MediaType.audio, MediaSubType.ogg), aac(MediaType.audio, MediaSubType.aac), webm(MediaType.video, MediaSubType.webm), youtube(MediaType.video, MediaSubType.youtube);
public final MediaType mediaType;
public final MediaSubType mediaSubType;
@@ -34,7 +34,7 @@ public class MediaTrack implements IsSerializable {
}
public enum MediaSubType {
ogg, mp4, mpeg, x_aiff, quicktime, aac, webm;
ogg, mp4, mpeg, x_aiff, quicktime, aac, webm, youtube;
public String toString() {
return name().replace('_', '-');
@@ -77,5 +77,9 @@ public class MediaTrack implements IsSerializable {
public String typeToString() {
return mimeType == null ? "undefined" : mimeType.toString();
}
public boolean isYoutube() {
return (mimeType != null) && MediaSubType.youtube.equals(mimeType.mediaSubType);
}
}
@@ -0,0 +1,97 @@
package com.sap.sailing.gwt.ui.video;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Window;
public abstract class AbstractPopupWindow implements EntryPoint {
@Override
public void onModuleLoad() {
initializePlayer();
}
protected abstract void initializePlayer();
native void addCallbackMethods() /*-{
var that = this;
$wnd.videoPlayer = {
play : function() {
that.@com.sap.sailing.gwt.ui.video.AbstractPopupWindow::play()();
},
pause : function() {
that.@com.sap.sailing.gwt.ui.video.AbstractPopupWindow::pause()();
},
setTime : function(time) {
that.@com.sap.sailing.gwt.ui.video.AbstractPopupWindow::setTime(D)(time);
},
setMuted : function(muted) {
that.@com.sap.sailing.gwt.ui.video.AbstractPopupWindow::setMuted(Z)(muted);
},
isPaused : function() {
return that.@com.sap.sailing.gwt.ui.video.AbstractPopupWindow::isPaused()();
},
getDuration : function() {
return that.@com.sap.sailing.gwt.ui.video.AbstractPopupWindow::getDuration()();
},
getTime : function() {
return that.@com.sap.sailing.gwt.ui.video.AbstractPopupWindow::getTime()();
},
setPlaybackSpeed : function(newPlaySpeedFactor) {
that.@com.sap.sailing.gwt.ui.video.AbstractPopupWindow::setPlaybackSpeed(D)(newPlaySpeedFactor);
}
};
}-*/;
public abstract void play();
public abstract void pause();
public abstract void setTime(double time);
public abstract void setMuted(boolean muted);
public abstract boolean isPaused();
public abstract double getDuration();
public abstract double getTime();
public abstract void setPlaybackSpeed(double newPlaySpeedFactor);
public void initPlayState(double deferredMediaTime, boolean isDeferredMuted, double deferredPlaybackSpeed,
boolean isDeferredPlaying) {
addCallbackMethods();
setTime(deferredMediaTime);
setMuted(isDeferredMuted);
setPlaybackSpeed(deferredPlaybackSpeed);
if (isDeferredPlaying) {
play();
} else {
pause();
}
}
protected void adjustWindowSize() {
int windowWidth = Window.getClientWidth();
int videoWidth = getVideoWidth();
int widthDelta = videoWidth - windowWidth;
int windowHeight = Window.getClientHeight();
int videoHeight = getVideoHeight();
int heightDelta = videoHeight - windowHeight;
Window.resizeBy(widthDelta, heightDelta);
}
protected abstract boolean hasVideoSizes();
protected abstract int getVideoWidth();
protected abstract int getVideoHeight();
protected abstract void setVideoSize(int width, int height);
}
@@ -1,27 +1,21 @@
package com.sap.sailing.gwt.ui.video;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.dom.client.MediaElement;
import com.google.gwt.dom.client.VideoElement;
import com.google.gwt.event.dom.client.ContextMenuEvent;
import com.google.gwt.event.dom.client.ContextMenuHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.media.client.Video;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootLayoutPanel;
public class VideoPopupWindow implements EntryPoint, ResizeHandler, ContextMenuHandler {
public class VideoPopupWindow extends AbstractPopupWindow implements ContextMenuHandler {
private Video video;
private boolean isDebug;
@Override
public void onModuleLoad() {
Window.addResizeHandler(this);
protected void initializePlayer() {
RootLayoutPanel mainPanel = RootLayoutPanel.get();
@@ -69,135 +63,48 @@ public class VideoPopupWindow implements EntryPoint, ResizeHandler, ContextMenuH
});
}-*/;
native void addCallbackMethods() /*-{
var that = this;
$wnd.videoPlayer = {
play : function() {
that.@com.sap.sailing.gwt.ui.video.VideoPopupWindow::play()();
},
pause : function() {
that.@com.sap.sailing.gwt.ui.video.VideoPopupWindow::pause()();
},
setTime : function(time) {
that.@com.sap.sailing.gwt.ui.video.VideoPopupWindow::setTime(D)(time);
},
setMuted : function(muted) {
that.@com.sap.sailing.gwt.ui.video.VideoPopupWindow::setMuted(Z)(muted);
},
isPaused : function() {
return that.@com.sap.sailing.gwt.ui.video.VideoPopupWindow::isPaused()();
},
getDuration : function() {
return that.@com.sap.sailing.gwt.ui.video.VideoPopupWindow::getDuration()();
},
getTime : function() {
return that.@com.sap.sailing.gwt.ui.video.VideoPopupWindow::getTime()();
},
setPlaybackSpeed : function(newPlaySpeedFactor) {
that.@com.sap.sailing.gwt.ui.video.VideoPopupWindow::setPlaybackSpeed(D)(newPlaySpeedFactor);
}
};
}-*/;
public void play() {
video.play();
}
public void pause() {
video.pause();
}
public void setTime(double time) {
video.setCurrentTime(time);
}
public void setMuted(boolean muted) {
video.setMuted(muted);
}
public boolean isPaused() {
return video.isPaused();
}
public double getDuration() {
return video.getDuration();
}
public double getTime() {
return video.getCurrentTime();
}
public void setPlaybackSpeed(double newPlaySpeedFactor) {
video.setPlaybackRate(newPlaySpeedFactor);
}
public void loadedmetadata() {
adjustWindowSize();
}
public void initPlayState(double deferredMediaTime, boolean isDeferredMuted, double deferredPlaybackSpeed,
boolean isDeferredPlaying) {
addCallbackMethods();
setTime(deferredMediaTime);
setMuted(isDeferredMuted);
setPlaybackSpeed(deferredPlaybackSpeed);
if (isDeferredPlaying) {
play();
} else {
pause();
}
}
private void adjustWindowSize() {
int clientWidth = Window.getClientWidth();
int videoWidth = video.getVideoWidth();
int widthDelta = videoWidth - clientWidth;
int clientHeight = Window.getClientHeight();
int videoHeight = video.getVideoHeight();
int heightDelta = videoHeight - clientHeight;
Window.resizeBy(widthDelta, heightDelta);
@Override
public void play() {
video.play();
}
@Override
public void onResize(final ResizeEvent event) {
if (video != null) {
new Timer() {
@Override
public void run() {
int videoWidth = video.getVideoWidth();
if (videoWidth > 0) {
int clientWidth = Window.getClientWidth();
double widthResizeRatio = ((double) clientWidth) / videoWidth;
public void pause() {
video.pause();
}
int videoHeight = video.getVideoHeight();
if (videoHeight > 0) {
int clientHeight = Window.getClientHeight();
double heightResizeRatio = ((double) clientHeight) / videoHeight;
@Override
public void setTime(double time) {
video.setCurrentTime(time);
}
double resizeRatio = Math.min(widthResizeRatio, heightResizeRatio);
@Override
public void setMuted(boolean muted) {
video.setMuted(muted);
}
if (Math.abs(1.0 - resizeRatio) > 0.001) {
@Override
public boolean isPaused() {
return video.isPaused();
}
int newVideoWidth = (int) Math.round(resizeRatio * videoWidth);
int newVideoHeight = (int) Math.round(resizeRatio * videoHeight);
video.setPixelSize(newVideoWidth, newVideoHeight);
@Override
public double getDuration() {
return video.getDuration();
}
int widthDelta = newVideoWidth - clientWidth;
int heightDelta = newVideoHeight - clientHeight;
@Override
public double getTime() {
return video.getCurrentTime();
}
Window.resizeBy(widthDelta, heightDelta);
}
}
}
}
}.schedule(100);
}
@Override
public void setPlaybackSpeed(double newPlaySpeedFactor) {
video.setPlaybackRate(newPlaySpeedFactor);
}
/**
@@ -210,5 +117,25 @@ public class VideoPopupWindow implements EntryPoint, ResizeHandler, ContextMenuH
event.stopPropagation();
}
}
@Override
protected boolean hasVideoSizes() {
return video != null;
}
@Override
protected int getVideoWidth() {
return video.getVideoWidth();
}
@Override
protected int getVideoHeight() {
return video.getVideoHeight();
}
@Override
protected void setVideoSize(int width, int height) {
video.setPixelSize(width, height);
}
}
@@ -1,76 +1,141 @@
package com.sap.sailing.gwt.ui.video;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.RootPanel;
public class YoutubePopupWindow implements EntryPoint {
public class YoutubePopupWindow extends AbstractPopupWindow {
private static final String VIDEO_CONTAINER_ID = "videoContainer";
private JavaScriptObject youtubePlayer;
private static final String VIDEO_CONTAINER_ID = "videoContainer";
@Override
public void onModuleLoad() {
String title = Window.Location.getParameter("title");
Window.setTitle(title);
RootLayoutPanel.get().getElement().setId(VIDEO_CONTAINER_ID);
private JavaScriptObject youtubePlayer;
String videoUrl = Window.Location.getParameter("id");
if (videoUrl != null) {
loadYoutube(videoUrl, VIDEO_CONTAINER_ID);
}
@Override
protected void initializePlayer() {
String title = Window.Location.getParameter("title");
Window.setTitle(title);
RootLayoutPanel.get().getElement().setId(VIDEO_CONTAINER_ID);
String videoUrl = Window.Location.getParameter("id");
if (videoUrl != null) {
loadYoutube(videoUrl, VIDEO_CONTAINER_ID);
}
}
// Inspired by https://developers.google.com/youtube/iframe_api_reference#Examples
// See also: https://developers.google.com/youtube/js_api_reference
// Code Playground: https://code.google.com/apis/ajax/playground/?exp=youtube#chromeless_player
private native void loadYoutube(String videoUrl, String videoContainerId) /*-{
//inspired by https://developers.google.com/youtube/iframe_api_reference#Examples
private native void loadYoutube(String videoUrl, String videoContainerId) /*-{
var that = this;
var that = this;
var tag = $doc.createElement('script');
// This is a protocol-relative URL as described here: http://paulirish.com/2010/the-protocol-relative-url/
var tag = $doc.createElement('script');
tag.src = "//www.youtube.com/iframe_api";
var firstScriptTag = $doc.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// This is a protocol-relative URL as described here:
// http://paulirish.com/2010/the-protocol-relative-url/
// If you're testing a local page accessed via a file:/// URL, please set tag.src to
// "https://www.youtube.com/iframe_api" instead.
tag.src = "//www.youtube.com/iframe_api";
var firstScriptTag = $doc.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// This function creates an <iframe> containing a YouTube player after the API code downloads.
var player;
$wnd.onYouTubeIframeAPIReady = function() {
var player = new $wnd.YT.Player(videoContainerId, {
videoId : videoUrl,
height: '480', //see https://developers.google.com/youtube/iframe_api_reference?hl=en#Playback_quality
width: '853',
events: { //https://developers.google.com/youtube/iframe_api_reference?hl=en#Events
'onReady': function(event) {
var deferredPlayState = $wnd.deferredPlayState
if (deferredPlayState && !$wnd.videoPlayer) {
that.@com.sap.sailing.gwt.ui.video.YoutubePopupWindow::initPlayState(DZDZ)(deferredPlayState.deferredMediaTime, deferredPlayState.isDeferredMuted, deferredPlayState.deferredPlaybackSpeed, deferredPlayState.isDeferredPlaying);
}
}
},
playerVars : {
'autoplay' : 0,
'controls' : 0
}
});
// player.addEventListener("onStateChange", "handleStateChange");
that.@com.sap.sailing.gwt.ui.video.YoutubePopupWindow::setYoutubePlayer(Lcom/google/gwt/core/client/JavaScriptObject;)(player);
}
// This function creates an <iframe> containing a YouTube player after the API code downloads.
var player;
$wnd.onYouTubeIframeAPIReady = function() {
var player = new $wnd.YT.Player(videoContainerId, {
videoId : videoUrl,
playerVars : {
'autoplay' : 0,
'controls' : 0
}
});
that.@com.sap.sailing.gwt.ui.video.YoutubePopupWindow::setYoutubePlayer(Lcom/google/gwt/core/client/JavaScriptObject;)(player);
}
}-*/;
}-*/;
public void setYoutubePlayer(JavaScriptObject youtubePlayer) {
this.youtubePlayer = youtubePlayer;
adjustWindowSize();
}
public void setYoutubePlayer(JavaScriptObject youtubePlayer) {
this.youtubePlayer = youtubePlayer;
}
@Override
public void initPlayState(double deferredMediaTime, boolean isDeferredMuted, double deferredPlaybackSpeed, boolean isDeferredPlaying) {
adjustWindowSize();
super.initPlayState(deferredMediaTime, isDeferredMuted, deferredPlaybackSpeed, isDeferredPlaying);
}
private void adjustWindowSize() {
RootPanel videoContainer = RootPanel.get(VIDEO_CONTAINER_ID);
int clientWidth = Window.getClientWidth();
int videoWidth = videoContainer.getOffsetWidth();
int widthDelta = videoWidth - clientWidth;
int clientHeight = Window.getClientHeight();
int videoHeight = videoContainer.getOffsetHeight();
int heightDelta = videoHeight - clientHeight;
Window.resizeBy(widthDelta, heightDelta);
}
public native void play() /*-{
var player = this.@com.sap.sailing.gwt.ui.video.YoutubePopupWindow::youtubePlayer;
player.playVideo();
}-*/;
public native void pause() /*-{
var player = this.@com.sap.sailing.gwt.ui.video.YoutubePopupWindow::youtubePlayer;
player.pauseVideo();
}-*/;
public native void setTime(double time) /*-{
var player = this.@com.sap.sailing.gwt.ui.video.YoutubePopupWindow::youtubePlayer;
var allowSeekAhead = true;
player.seekTo(time, allowSeekAhead);
}-*/;
public native void setMuted(boolean muted) /*-{
var player = this.@com.sap.sailing.gwt.ui.video.YoutubePopupWindow::youtubePlayer;
if (muted) {
player.mute();
} else {
player.unMute()
}
}-*/;
public native boolean isPaused() /*-{
var player = this.@com.sap.sailing.gwt.ui.video.YoutubePopupWindow::youtubePlayer;
return player.getPlayerState() == $wnd.YT.PlayerState.PAUSED;
}-*/;
public native double getDuration() /*-{
var player = this.@com.sap.sailing.gwt.ui.video.YoutubePopupWindow::youtubePlayer;
return player.getDuration();
}-*/;
public native double getTime() /*-{
var player = this.@com.sap.sailing.gwt.ui.video.YoutubePopupWindow::youtubePlayer;
return player.getCurrentTime();
}-*/;
public native void setPlaybackSpeed(double newPlaySpeedFactor) /*-{
var player = this.@com.sap.sailing.gwt.ui.video.YoutubePopupWindow::youtubePlayer;
player.setPlaybackRate(newPlaySpeedFactor);
}-*/;
@Override
protected boolean hasVideoSizes() {
return youtubePlayer != null;
}
@Override
protected int getVideoWidth() {
return RootPanel.get(VIDEO_CONTAINER_ID).getOffsetWidth();
}
@Override
protected int getVideoHeight() {
return RootPanel.get(VIDEO_CONTAINER_ID).getOffsetHeight();
}
@Override
protected void setVideoSize(int width, int height) {
RootPanel.get(VIDEO_CONTAINER_ID).setPixelSize(width, height);
}
}
@@ -1,7 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.4.0//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.4.0/distro-source/core/src/gwt-module.dtd">
<module>
<inherits name="com.google.gwt.user.User" />
<stylesheet src="../reset.css" />
<stylesheet src="../VideoPopup.css" />
<inherits name="com.google.gwt.user.User" />
<entry-point class="com.sap.sailing.gwt.ui.video.VideoPopupWindow" />
<extend-property name="locale" values="de"/>
<source path='video'/>