Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

FLUID-4610: Half-completed transcript UI.

  • Loading branch information...
commit 87ba52e202adfcee382244e3d2ba15422f5559c7 1 parent 6375bf9
Cindy Qi Li authored
View
72 css/VideoPlayer.css
@@ -12,6 +12,14 @@
}
/*
+* Video and Controller area
+*/
+
+.fl-videoPlayer-video-controller-area {
+ float: left;
+}
+
+/*
* Video area
*/
@@ -135,6 +143,30 @@ ul.fl-videoPlayer-captions-languageList .fl-videoPlayer-caption-selected {
}
/*
+ * transcript controls
+ */
+.fl-videoPlayer-theme .fl-videoPlayer-transcripts-button {
+ background: #ffffff url('../images/transcripts-black.png') no-repeat center center;
+}
+.fl-videoPlayer-theme .fl-videoPlayer-transcripts-button:hover {
+ background-color: yellow;
+}
+.fl-videoPlayer-theme .fl-videoPlayer-transcripts-button.fl-videoPlayer-transcript-active {
+ background-color: orange;
+}
+.fl-videoPlayer-theme .fl-videoPlayer-transcripts-button.fl-videoPlayer-transcript-active:hover {
+ background-color: wheat;
+}
+
+ul.fl-videoPlayer-transcripts-languageList,
+ul.fl-videoPlayer-transcripts-languageList li {
+ display: block;
+}
+ul.fl-videoPlayer-transcripts-languageList .fl-videoPlayer-transcript-selected {
+ color: yellow;
+}
+
+/*
* Scrub bar controls
*/
.fl-videoPlayer-scrubberContainer {
@@ -150,6 +182,9 @@ ul.fl-videoPlayer-captions-languageList .fl-videoPlayer-caption-selected {
position: absolute;
}
+.fl-videoPlayer-theme .fl-videoPlayer-transcripts-close-button {
+ background: #ffffff url('../images/close-black.png') no-repeat center center;
+}
/*
* Caption area
@@ -166,6 +201,33 @@ ul.fl-videoPlayer-captions-languageList .fl-videoPlayer-caption-selected {
background-color: black;
opacity: 0.7;
}
+
+/*
+ * Caption area
+ */
+
+.fl-videoPlayer-transcriptArea {
+ float: left;
+ border: 1px solid black;
+ width: 15em;
+}
+
+.fl-videoPlayer-transcripts-language-dropdown {
+ float: left;
+ margin: 1em;
+ width: 75%;
+}
+
+.fl-videoPlayer-transcripts-close-button {
+ float: right;
+ margin: 0.2em;
+}
+
+.fl-videoPlayer-transcript-text {
+ margin-top: 3em;
+ border: 1px solid black;
+}
+
/*
* mods to the coal theme
*/
@@ -302,6 +364,16 @@ ul.fl-videoPlayer-captions-languageList .fl-videoPlayer-caption-selected {
.fl-theme-uio-wb .fl-videoPlayer-captions-button {
background-image: url('../images/captions-white.png');
}
+.fl-theme-uio-bw .fl-videoPlayer-transcripts-button,
+.fl-theme-uio-by .fl-videoPlayer-transcripts-button {
+ background-image: url('../images/transcripts-black.png');
+}
+.fl-theme-uio-yb .fl-videoPlayer-transcripts-button {
+ background-image: url('../images/transcripts-yellow.png');
+}
+.fl-theme-uio-wb .fl-videoPlayer-transcripts-button {
+ background-image: url('../images/transcripts-white.png');
+}
.fl-theme-uio-wb .fl-videoPlayer-caption-captionText,
.fl-theme-uio-yb .fl-videoPlayer-caption-captionText {
View
22 demos/VideoPlayer.html
@@ -112,6 +112,28 @@
conversionServiceUrl: "/videoPlayer/conversion_service/index.php",
maxNumber: 3,
track: undefined
+ },
+ transcripts: {
+ sources: {
+ english: {
+ src: "ReorganizeFuture.transcripts.en.json",
+ type: "JSONcc"
+ },
+ francaise: {
+ src: "ReorganizeFuture.transcripts.fr.json",
+ type: "JSONcc"
+ }
+ },
+ currentTrack: "english",
+
+ // The following options (choices, names, selection) shouldn't be necessary.
+ // This is a temporary workaround for FLUID-4585
+ choices: [],
+ names: [],
+ selection: "english",
+
+ show: false,
+ track: undefined
}
}
View
17 docs/index.html
@@ -412,14 +412,15 @@
Note: The keyboard control works only if the focus is on the video tag in order not to make it too invasive
</em>
<ul>
- <li>Play/Pause: SHIFT + p or SPACEBAR</li>
- <li>Forward/backward: SHIFT + LEFT/RIGHT</li>
- <li>Volume up/down: SHIFT + UP/DOWN</li>
- <li>Captions On/Off: SHIFT + c</li>
- <li>Fullscreen On/Off: SHIFT + f</li>
- </ul>
- <h3>Modifying the keyboard controls</h3>
- <div>TODO!!!!</div>
+ <li>Play/Pause: SHIFT + p or SPACEBAR</li>
+ <li>Forward/backward: SHIFT + LEFT/RIGHT</li>
+ <li>Volume up/down: SHIFT + UP/DOWN</li>
+ <li>Captions On/Off: SHIFT + c</li>
+ <li>Transcripts On/Off: SHIFT + t</li>
+ <li>Fullscreen On/Off: SHIFT + f</li>
+ </ul>
+ <h3>Modifying the keyboard controls</h3>
+ <div>TODO!!!!</div>
<h2>Note on video format and HTML5</h2>
<p>
In order to be sure to be able to read your video on most browser you'll need to provide more than one source. Here is a list of Browsers and their needed video format. In order to make the player work on IOS (iPhone, iPad) it is necessary to put the mp4 video first.
View
78 html/videoPlayer_template.html
@@ -1,33 +1,53 @@
-
-<video class="flc-videoPlayer-video fl-videoPlayer-video"></video>
-
-<div class="flc-videoPlayer-captionArea fl-videoPlayer-captionArea"></div>
-
-<div class="flc-videoPlayer-controller fl-videoPlayer-controller">
-
- <div class="flc-videoPlayer-scrubberContainer fl-videoPlayer-scrubberContainer">
- <div class="flc-videoPlayer-current fl-videoPlayer-time fl-videoPlayer-current"></div>
- <div class="flc-videoPlayer-scrubber fl-videoPlayer-scrubber"></div>
- <div class="flc-videoPlayer-total fl-videoPlayer-time fl-videoPlayer-total"></div>
- </div>
-
- <button type="button" class="flc-videoPlayer-play fl-videoPlayer-button fl-videoPlayer-play"></button>
-
- <div class="flc-videoPlayer-volumeContainer fl-videoPlayer-volumeContainer">
- <button type="button" class="flc-videoPlayer-mute fl-videoPlayer-button fl-videoPlayer-mute"></button>
- <div class="flc-videoPlayer-volumeControl"></div>
- </div>
-
- <div class="flc-videoPlayer-captionControls-container">
- <button type="button" class="flc-videoPlayer-captions-button fl-videoPlayer-button fl-videoPlayer-captions-button"></button>
- <ul class="flc-videoPlayer-captions-languageList fl-videoPlayer-captions-languageList">
- <li class="flc-videoPlayer-captions-language">
- <label for="radioid" class="flc-videoPlayer-captions-languageLabel">label</label>
- <input type="radio" id="radioid" class="flc-videoPlayer-captions-languageButton fl-hidden-accessible" />
- </li>
- </ul>
+<div class="flc-videoPlayer-video-controller-area fl-videoPlayer-video-controller-area">
+ <video class="flc-videoPlayer-video"></video>
+
+ <div class="flc-videoPlayer-captionArea fl-videoPlayer-captionArea"></div>
+
+ <div class="flc-videoPlayer-controller fl-videoPlayer-controller">
+
+ <div class="flc-videoPlayer-scrubberContainer fl-videoPlayer-scrubberContainer">
+ <div class="flc-videoPlayer-current fl-videoPlayer-time fl-videoPlayer-current"></div>
+ <div class="flc-videoPlayer-scrubber fl-videoPlayer-scrubber"></div>
+ <div class="flc-videoPlayer-total fl-videoPlayer-time fl-videoPlayer-total"></div>
+ </div>
+
+ <button type="button" class="flc-videoPlayer-play fl-videoPlayer-button fl-videoPlayer-play"></button>
+
+ <div class="flc-videoPlayer-volumeContainer fl-videoPlayer-volumeContainer">
+ <button type="button" class="flc-videoPlayer-mute fl-videoPlayer-button fl-videoPlayer-mute"></button>
+ <div class="flc-videoPlayer-volumeControl"></div>
+ </div>
+
+ <div class="flc-videoPlayer-captionControls-container">
+ <button type="button" class="flc-videoPlayer-captions-button fl-videoPlayer-button fl-videoPlayer-captions-button"></button>
+ <ul class="flc-videoPlayer-captions-languageList fl-videoPlayer-captions-languageList">
+ <li class="flc-videoPlayer-captions-language">
+ <label for="radioid" class="flc-videoPlayer-captions-languageLabel">label</label>
+ <input type="radio" id="radioid" class="flc-videoPlayer-captions-languageButton fl-hidden-accessible" />
+ </li>
+ </ul>
+ </div>
+
+ <div class="flc-videoPlayer-transcriptControls-container">
+ <button type="button" class="flc-videoPlayer-transcripts-button fl-videoPlayer-button fl-videoPlayer-transcripts-button"></button>
+ <ul class="flc-videoPlayer-transcripts-languageList fl-videoPlayer-transcripts-languageList">
+ <li class="flc-videoPlayer-transcripts-language">
+ <label for="radioid" class="flc-videoPlayer-transcripts-languageLabel">label</label>
+ <input type="radio" id="radioid" class="flc-videoPlayer-transcripts-languageButton fl-hidden-accessible" />
+ </li>
+ </ul>
+ </div>
+
+ <button id="fullscreen" type="button" class="flc-videoPlayer-fullscreen fl-videoPlayer-button fl-videoPlayer-fullscreen"></button>
</div>
+</div>
- <button id="fullscreen" type="button" class="flc-videoPlayer-fullscreen fl-videoPlayer-button fl-videoPlayer-fullscreen"></button>
+<div class="flc-videoPlayer-transcriptArea fl-videoPlayer-transcriptArea">
+ <select class="flc-videoPlayer-transcripts-language-dropdown fl-videoPlayer-transcripts-language-dropdown">
+ <option></option>
+ </select>
+ <button type="button" class="flc-videoPlayer-transcripts-close-button fl-videoPlayer-button fl-videoPlayer-transcripts-close-button"></button>
+
+ <div class="flc-videoPlayer-transcript-text fl-videoPlayer-transcript-text"></div>
</div>
View
56 js/VideoPlayer.js
@@ -65,6 +65,10 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
modifier: $.ui.keyCode.SHIFT,
key: 67
},
+ transcripts: {
+ modifier: $.ui.keyCode.SHIFT,
+ key: 84
+ },
fullscreen: {
modifier: $.ui.keyCode.SHIFT,
key: 70
@@ -206,13 +210,17 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
selectors: {
video: ".flc-videoPlayer-video",
caption: ".flc-videoPlayer-captionArea",
- controllers: ".flc-videoPlayer-controller"
+ controllers: ".flc-videoPlayer-controller",
+ transcripts: ".flc-videoPlayer-transcriptArea",
+ videoControllersContainer: ".flc-videoPlayer-video-controller-area"
},
strings: {
captionsOff: "Captions OFF",
- turnCaptionsOff: "Turn Captions OFF"
+ turnCaptionsOff: "Turn Captions OFF",
+ transcriptsOff: "Transcripts OFF",
+ turnTranscriptsOff: "Turn Transcripts OFF"
},
- selectorsToIgnore: ["caption"],
+ selectorsToIgnore: ["caption", "videoControllersContainer", "transcripts"],
keyBindings: defaultKeys,
produceTree: "fluid.videoPlayer.produceTree",
controls: "custom",
@@ -222,6 +230,7 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
currentTime: 0,
totalTime: 0,
displayCaptions: true,
+ displayTranscripts: true,
fullscreen: false,
volume: 60,
muted: false,
@@ -238,6 +247,14 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
sources: null,
conversionServiceUrl: "/videoPlayer/conversion_service/index.php",
track: undefined
+ },
+ transcripts: {
+ selection: "none",
+ choices: [],
+ names: [],
+ show: false,
+ sources: null,
+ track: undefined
}
},
templates: {
@@ -273,6 +290,15 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
});
}
}, {
+ modifier: that.options.keyBindings.transcripts.modifier,
+ key: that.options.keyBindings.transcripts.key,
+ activateHandler: function () {
+ that.applier.fireChangeRequest({
+ path: "states.displayTranscripts",
+ value: !that.model.states.displayTranscripts
+ });
+ }
+ }, {
modifier: that.options.keyBindings.volumePlus.modifier,
key: that.options.keyBindings.volumePlus.key,
activateHandler: that.incrVolume
@@ -304,8 +330,10 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
that.play();
});
video.bind("loadedmetadata", function () {
+ var videoControllersContainer = that.locate("videoControllersContainer");
//that shouldn't be usefull but the video is too big if it's not used
- that.container.css("width", video[0].videoWidth);
+ videoControllersContainer.css("width", video[0].videoWidth);
+ that.locate("transcripts").css("height", videoControllersContainer.height());
bindKeyboardControl(that);
});
};
@@ -353,21 +381,37 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
that.options.model.captions.choices.push("none");
that.options.model.captions.names.push(that.options.strings.captionsOff);
+ // build the 'choices' from the transcript list provided
+ fluid.each(that.options.model.transcripts.sources, function (value, key) {
+ that.options.model.transcripts.choices.push(key);
+ that.options.model.transcripts.names.push(key);
+ });
+ // add the 'turn transcripts off' option
+ that.options.model.transcripts.choices.push("none");
+ that.options.model.transcripts.names.push(that.options.strings.transcriptsOff);
+
that.fullscreen = function () {
var video = that.locate("video");
+ var videoControllersContainer = that.locate("videoControllersContainer");
if (that.model.states.fullscreen === true) {
- that.container.css({
+ video.css({
// TODO: This doesn't actually do full-screen, it simply tries to maximise
// to the current window size. (FLUID-4570)
width: window.innerWidth + "px",
height: window.innerHeight - 20 + "px"
});
+
+ // Adjust the height of video + controllers area & transcripts area
+ videoControllersContainer.css({width: window.innerWidth + "px"});
} else {
- that.container.css({
+ video.css({
width: video[0].videoWidth,
height: video[0].videoHeight
});
+
+ videoControllersContainer.css({width: video[0].videoWidth});
}
+ that.locate("transcripts").css("height", videoControllersContainer.height());
};
};
View
158 js/VideoPlayer_controllers.js
@@ -22,6 +22,7 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
/**
* controllers is a video controller containing a play button, a time scrubber,
* a volume controller, a button to put captions on/off
+ * , a button to put transcripts on/off
*
* @param {Object} container the container which this component is rooted
* @param {Object} options configuration options for the component
@@ -70,6 +71,14 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
applier: "{controllers}.applier"
}
},
+ transcriptControls: {
+ type: "fluid.videoPlayer.controllers.transcriptControls",
+ container: "{controllers}.dom.transcriptControlsContainer",
+ options: {
+ model: "{controllers}.model",
+ applier: "{controllers}.applier"
+ }
+ },
playButton: {
type: "fluid.videoPlayer.controllers.toggleButton",
container: "{controllers}.container",
@@ -126,6 +135,7 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
scrubberContainer: ".flc-videoPlayer-scrubberContainer",
volumeContainer: ".flc-videoPlayer-volumeContainer",
captionControlsContainer: ".flc-videoPlayer-captionControls-container",
+ transcriptControlsContainer: ".flc-videoPlayer-transcriptControls-container",
fullscreen: ".flc-videoPlayer-fullscreen"
},
@@ -133,7 +143,8 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
fullscreenOn: "fl-videoPlayer-state-fullscreenOn",
fullscreenOff: "fl-videoPlayer-state-fullscreenOff",
fullscreenIcon: "ui-icon-extlink",
- captionIcon: "ui-icon-comment"
+ captionIcon: "ui-icon-comment",
+ transcriptIcon: "ui-icon-comment"
}
});
@@ -566,8 +577,151 @@ https://github.com/fluid-project/infusion/raw/master/Infusion-LICENSE.txt
};
/*****************************************************************************
+ Transcript controls
+ Toggle button plus language selection pull-down
+ *****************************************************************************/
+ fluid.defaults("fluid.videoPlayer.controllers.transcriptControls", {
+ gradeNames: ["fluid.rendererComponent", "autoInit"],
+ renderOnInit: true,
+ rendererOptions: {
+ autoBind: true
+ },
+ finalInitFunction: "fluid.videoPlayer.controllers.transcriptControls.finalInit",
+ produceTree: "fluid.videoPlayer.controllers.transcriptControls.produceTree",
+ events: {
+ onReady: null
+ },
+ model: {
+ // TODO: the 'transcripts' is to mimic the videoPlayer model layout
+ // Ideally, the transcriptControls should operate without requiring that knowledge.
+ transcripts: {
+ selection: "none",
+ choices: [],
+ names: [],
+ show: false,
+ sources: null,
+ conversionServiceUrl: "/videoPlayer/conversion_service/index.php",
+ maxNumber: 3,
+ track: undefined
+ }
+ },
+ selectors: {
+ button: ".flc-videoPlayer-transcripts-button",
+ languageList: ".flc-videoPlayer-transcripts-languageList",
+ languageRow: ".flc-videoPlayer-transcripts-language",
+ languageButton: ".flc-videoPlayer-transcripts-languageButton",
+ languageLabel: ".flc-videoPlayer-transcripts-languageLabel",
+ langaugeDropdown: ".flc-videoPlayer-transcripts-language-dropdown",
+ closeButton: ".flc-videoPlayer-transcripts-close-button"
+ },
+ repeatingSelectors: ["languageRow"],
+ selectorsToIgnore: ["languageList"],
+ styles: {
+ selected: "fl-videoPlayer-transcript-selected"
+ },
+ // TODO: Strings should be moved out into a single top-level bundle (FLUID-4590)
+ strings: {
+ transcriptsOff: "Transcripts OFF",
+ turnTranscriptsOff: "Turn Transcripts OFF"
+ },
+ components: {
+ transcriptButton: {
+ type: "fluid.videoPlayer.controllers.toggleButton",
+ container: "{transcriptControls}.container",
+ options: {
+ selectors: {
+ button: ".flc-videoPlayer-transcripts-button"
+ },
+ styles: {
+ pressed: "fl-videoPlayer-transcript-active"
+ },
+ // TODO: Strings should be moved out into a single top-level bundle (FLUID-4590)
+ strings: {
+ press: "Transcripts",
+ release: "Transcripts"
+ }
+ }
+ }
+ }
+ });
+
+ // TODO: FLUID-4589 Restructure the transcript model to reduce the code logic here
+ fluid.videoPlayer.controllers.transcriptControls.setUpTranscriptControls = function (that) {
+ that.transcriptsOffOption = $(that.locate("languageLabel")[that.model.transcripts.choices.indexOf("none")]);
+ that.locate("languageList").hide();
+ that.transcriptsOffOption.text(that.model.transcripts.selection === "none" ? that.options.strings.transcriptsOff : that.options.strings.turnTranscriptsOff);
+ $(that.locate("languageLabel")[that.model.transcripts.choices.indexOf(that.model.transcripts.selection)]).addClass(that.options.styles.selected);
+ };
+
+ fluid.videoPlayer.controllers.transcriptControls.bindTranscriptDOMEvents = function (that) {
+ that.transcriptButton.events.onPress.addListener(function (evt) {
+ that.locate("languageList").toggle();
+ // prevent the default onPress handler from toggling the button state:
+ // it should only toggle if the user turns transcripts on or off
+ return false;
+ });
+ };
+
+ // TODO: FLUID-4589 Restructure the transcript model to reduce the code logic here
+ fluid.videoPlayer.controllers.transcriptControls.bindTranscriptModel = function (that) {
+ that.applier.modelChanged.addListener("transcripts.selection", function (model, oldModel, changeRequest) {
+ var oldSel = oldModel.transcripts.selection;
+ var newSel = model.transcripts.selection;
+ if (oldSel === newSel) {
+ return true;
+ }
+
+ // TODO: can we do this in CSS?
+ var labels = that.locate("languageLabel");
+ $(labels[model.transcripts.choices.indexOf(oldSel)]).removeClass(that.options.styles.selected);
+ $(labels[model.transcripts.choices.indexOf(newSel)]).addClass(that.options.styles.selected);
+
+ // TODO: Can we move the responsibility to requestStateChange elsewhere?
+ if ((oldSel === "none") || (newSel === "none")) {
+ that.transcriptButton.requestStateChange();
+ that.transcriptsOffOption.text(newSel === "none" ? that.options.strings.transcriptsOff : that.options.strings.turnTranscriptsOff);
+ }
+
+ return true;
+ }, "transcriptControls");
+ };
+
+ fluid.videoPlayer.controllers.transcriptControls.finalInit = function (that) {
+ fluid.videoPlayer.controllers.transcriptControls.setUpTranscriptControls(that);
+ fluid.videoPlayer.controllers.transcriptControls.bindTranscriptDOMEvents(that);
+ fluid.videoPlayer.controllers.transcriptControls.bindTranscriptModel(that);
+ that.events.onReady.fire(that);
+ };
+
+ fluid.videoPlayer.controllers.transcriptControls.produceTree = function (that) {
+ return {
+ button: {
+ // TODO: Note that until FLUID-4573 is fixed, this binding doesn't actually do anything
+ value: "${transcripts.show}"
+ },
+ expander: {
+ type: "fluid.renderer.selection.inputs",
+ rowID: "languageRow",
+ labelID: "languageLabel",
+ inputID: "languageButton",
+ selectID: "transcriptLanguages",
+ tree: {
+ selection: "${transcripts.selection}",
+ optionlist: "${transcripts.choices}",
+ optionnames: "${transcripts.names}"
+ }
+ },
+ langaugeDropdown: {
+ selection: "${transcripts.selection}",
+ optionlist: "${transcripts.choices}",
+ optionnames: "${transcripts.names}"
+ }
+ };
+ };
+
+ /*****************************************************************************
Toggle button subcomponent
- Used for Play, Mute, Fullscreen, Captions
+ Used for Play, Mute, Fullscreen, Captions, Transcripts
*****************************************************************************/
fluid.defaults("fluid.videoPlayer.controllers.toggleButton", {
gradeNames: ["fluid.viewComponent", "autoInit"],
Please sign in to comment.
Something went wrong with that request. Please try again.