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
72 css/VideoPlayer.css
View
@@ -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 {
22 demos/VideoPlayer.html
View
@@ -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
}
}
17 docs/index.html
View
@@ -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.
78 html/videoPlayer_template.html
View
@@ -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>
56 js/VideoPlayer.js
View
@@ -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());
};
};
158 js/VideoPlayer_controllers.js
View
@@ -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.