зеркало из https://github.com/mozilla/gecko-dev.git
Bug 887934 - Add closed caption button to video control. r=jaws
MozReview-Commit-ID: JykXcNBkSLr --HG-- extra : transplant_source : %0C%0F%7C%86%89f%BC%FEU%ECI%3F%A6%AD%25%0Fq%C2%B6%18
This commit is contained in:
Родитель
9e12cef183
Коммит
98f56e3561
|
@ -215,6 +215,7 @@
|
|||
<stack flex="1">
|
||||
<spacer class="controlsSpacer" flex="1"/>
|
||||
<box class="clickToPlay" hidden="true" flex="1"/>
|
||||
<vbox class="textTrackList" hidden="true" offlabel="&closedCaption.off;"></vbox>
|
||||
</stack>
|
||||
<hbox class="controlBar" hidden="true">
|
||||
<button class="playButton"
|
||||
|
@ -238,6 +239,7 @@
|
|||
<box class="volumeForeground" anonid="volumeForeground"/>
|
||||
<scale class="volumeControl" movetoclick="true"/>
|
||||
</stack>
|
||||
<button class="closedCaptionButton"/>
|
||||
<button class="fullscreenButton"
|
||||
enterfullscreenlabel="&fullscreenButton.enterfullscreenlabel;"
|
||||
exitfullscreenlabel="&fullscreenButton.exitfullscreenlabel;"/>
|
||||
|
@ -272,7 +274,9 @@
|
|||
clickToPlay : null,
|
||||
controlsOverlay : null,
|
||||
fullscreenButton : null,
|
||||
currentTextTrackIndex: 0,
|
||||
|
||||
textTracksCount: 0,
|
||||
randomID : 0,
|
||||
videoEvents : ["play", "pause", "ended", "volumechange", "loadeddata",
|
||||
"loadstart", "timeupdate", "progress",
|
||||
|
@ -407,6 +411,7 @@
|
|||
this._durationLabelWidth = this.durationLabel.clientWidth;
|
||||
this._muteButtonWidth = this.muteButton.clientWidth;
|
||||
this._volumeControlWidth = this.volumeControl.clientWidth;
|
||||
this._closedCaptionButtonWidth = this.closedCaptionButton.clientWidth;
|
||||
this._fullscreenButtonWidth = this.fullscreenButton.clientWidth;
|
||||
this._controlBarHeight = this.controlBar.clientHeight;
|
||||
this.controlBar.hidden = true;
|
||||
|
@ -897,6 +902,7 @@
|
|||
return;
|
||||
|
||||
this.startFadeOut(this.controlBar, false);
|
||||
this.textTrackList.setAttribute("hidden", "true");
|
||||
clearTimeout(this._showControlsTimeout);
|
||||
Utils._controlsHiddenByTimeout = false;
|
||||
}
|
||||
|
@ -1206,6 +1212,182 @@
|
|||
event.preventDefault(); // Prevent page scrolling
|
||||
},
|
||||
|
||||
get videoSubtitles() {
|
||||
return Array.prototype.filter.call(this.video.textTracks, function (tt) {
|
||||
return tt.kind === "subtitles";
|
||||
});
|
||||
},
|
||||
|
||||
isClosedCaptionOn : function () {
|
||||
for (let tt of this.videoSubtitles) {
|
||||
if (tt.mode === "showing") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
setClosedCaptionButtonState : function () {
|
||||
if (!this.videoSubtitles.length) {
|
||||
this.closedCaptionButton.setAttribute("hidden", "true");
|
||||
return;
|
||||
}
|
||||
|
||||
this.closedCaptionButton.removeAttribute("hidden");
|
||||
|
||||
if (this.isClosedCaptionOn()) {
|
||||
this.closedCaptionButton.setAttribute("enabled", "true");
|
||||
} else {
|
||||
this.closedCaptionButton.removeAttribute("enabled");
|
||||
}
|
||||
|
||||
let ttItems = this.textTrackList.childNodes;
|
||||
|
||||
for (let tti of ttItems) {
|
||||
const idx = +tti.getAttribute("index");
|
||||
|
||||
if (idx == this.currentTextTrackIndex) {
|
||||
tti.setAttribute("on", "true");
|
||||
} else {
|
||||
tti.removeAttribute("on");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
addNewTextTrack : function (tt) {
|
||||
if (tt.kind !== "subtitles") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tt.index && tt.index < this.textTracksCount) {
|
||||
return;
|
||||
}
|
||||
|
||||
tt.index = this.textTracksCount++;
|
||||
|
||||
const label = tt.label || "";
|
||||
const ttText = document.createTextNode(label);
|
||||
const ttBtn = document.createElement("button");
|
||||
|
||||
ttBtn.classList.add("textTrackItem");
|
||||
ttBtn.setAttribute("index", tt.index);
|
||||
|
||||
ttBtn.addEventListener("click", function (event) {
|
||||
event.stopPropagation();
|
||||
|
||||
this.changeTextTrack(tt.index);
|
||||
}.bind(this));
|
||||
|
||||
ttBtn.appendChild(ttText);
|
||||
|
||||
this.textTrackList.appendChild(ttBtn);
|
||||
|
||||
if (tt.mode === "showing" && tt.index) {
|
||||
this.changeTextTrack(tt.index);
|
||||
}
|
||||
},
|
||||
|
||||
changeTextTrack : function (index) {
|
||||
for (let tt of this.videoSubtitles) {
|
||||
if (tt.index === index) {
|
||||
tt.mode = "showing";
|
||||
|
||||
this.currentTextTrackIndex = tt.index;
|
||||
} else {
|
||||
tt.mode = "disabled";
|
||||
}
|
||||
}
|
||||
|
||||
// should fallback to off
|
||||
if (this.currentTextTrackIndex !== index) {
|
||||
this.currentTextTrackIndex = 0;
|
||||
}
|
||||
|
||||
this.textTrackList.setAttribute("hidden", "true");
|
||||
this.setClosedCaptionButtonState();
|
||||
},
|
||||
|
||||
onControlBarTransitioned : function () {
|
||||
this.textTrackList.setAttribute("hidden", "true");
|
||||
},
|
||||
|
||||
toggleClosedCaption : function () {
|
||||
if (this.videoSubtitles.length === 1) {
|
||||
const lastTTIdx = this.videoSubtitles[0].index;
|
||||
|
||||
return this.changeTextTrack(this.isClosedCaptionOn() ? 0 : lastTTIdx);
|
||||
}
|
||||
|
||||
if (this.textTrackList.hasAttribute("hidden")) {
|
||||
this.textTrackList.removeAttribute("hidden");
|
||||
} else {
|
||||
this.textTrackList.setAttribute("hidden", "true");
|
||||
}
|
||||
|
||||
let maxButtonWidth = 0;
|
||||
|
||||
for (let tti of this.textTrackList.childNodes) {
|
||||
if (tti.clientWidth > maxButtonWidth) {
|
||||
maxButtonWidth = tti.clientWidth;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxButtonWidth > this.video.clientWidth) {
|
||||
maxButtonWidth = this.video.clientWidth;
|
||||
}
|
||||
|
||||
for (let tti of this.textTrackList.childNodes) {
|
||||
tti.style.width = maxButtonWidth + "px";
|
||||
}
|
||||
},
|
||||
|
||||
onTextTrackAdd : function (trackEvent) {
|
||||
this.addNewTextTrack(trackEvent.track);
|
||||
this.setClosedCaptionButtonState();
|
||||
},
|
||||
|
||||
onTextTrackRemove : function (trackEvent) {
|
||||
const toRemoveIndex = trackEvent.track.index;
|
||||
const ttItems = this.textTrackList.childNodes;
|
||||
|
||||
if (!ttItems) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let tti of ttItems) {
|
||||
const idx = +tti.getAttribute("index");
|
||||
|
||||
if (idx === toRemoveIndex) {
|
||||
tti.remove();
|
||||
this.textTracksCount--;
|
||||
}
|
||||
|
||||
if (idx === this.currentTextTrackIndex) {
|
||||
this.currentTextTrackIndex = 0;
|
||||
|
||||
this.video.dispatchEvent(new CustomEvent("texttrackchange"));
|
||||
}
|
||||
}
|
||||
|
||||
this.setClosedCaptionButtonState();
|
||||
},
|
||||
|
||||
initTextTracks : function () {
|
||||
const offLabel = this.textTrackList.getAttribute("offlabel");
|
||||
|
||||
this.addNewTextTrack({
|
||||
label: offLabel,
|
||||
kind: "subtitles"
|
||||
});
|
||||
|
||||
for (let tt of this.videoSubtitles) {
|
||||
this.addNewTextTrack(tt);
|
||||
}
|
||||
|
||||
this.setClosedCaptionButtonState();
|
||||
},
|
||||
|
||||
isEventWithin : function (event, parent1, parent2) {
|
||||
function isDescendant (node) {
|
||||
while (node) {
|
||||
|
@ -1233,6 +1415,7 @@
|
|||
_durationLabelWidth : 0,
|
||||
_muteButtonWidth : 0,
|
||||
_volumeControlWidth : 0,
|
||||
_closedCaptionButtonWidth : 0,
|
||||
_fullscreenButtonWidth : 0,
|
||||
_controlBarHeight : 0,
|
||||
_overlayPlayButtonHeight : 64,
|
||||
|
@ -1249,6 +1432,7 @@
|
|||
this._durationLabelWidth +
|
||||
this._muteButtonWidth +
|
||||
this._volumeControlWidth +
|
||||
this._closedCaptionButtonWidth +
|
||||
this._fullscreenButtonWidth;
|
||||
|
||||
let isFullscreenUnavailable = this.controlBar.hasAttribute("fullscreen-unavailable");
|
||||
|
@ -1326,10 +1510,13 @@
|
|||
this.clickToPlay = document.getAnonymousElementByAttribute(binding, "class", "clickToPlay");
|
||||
this.fullscreenButton = document.getAnonymousElementByAttribute(binding, "class", "fullscreenButton");
|
||||
this.volumeForeground = document.getAnonymousElementByAttribute(binding, "anonid", "volumeForeground");
|
||||
this.closedCaptionButton = document.getAnonymousElementByAttribute(binding, "class", "closedCaptionButton");
|
||||
this.textTrackList = document.getAnonymousElementByAttribute(binding, "class", "textTrackList");
|
||||
|
||||
this.isAudioOnly = (this.video instanceof HTMLAudioElement);
|
||||
this.setupInitialState();
|
||||
this.setupNewLoadState();
|
||||
this.initTextTracks();
|
||||
|
||||
// Use the handleEvent() callback for all media events.
|
||||
// Only the "error" event listener must capture, so that it can trap error
|
||||
|
@ -1343,7 +1530,6 @@
|
|||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
this.controlListeners = [];
|
||||
|
||||
// Helper function to add an event listener to the given element
|
||||
|
@ -1354,6 +1540,7 @@
|
|||
}
|
||||
|
||||
addListener(this.muteButton, "command", this.toggleMute);
|
||||
addListener(this.closedCaptionButton, "command", this.toggleClosedCaption);
|
||||
addListener(this.playButton, "click", this.clickToPlayClickHandler);
|
||||
addListener(this.fullscreenButton, "command", this.toggleFullscreen);
|
||||
addListener(this.clickToPlay, "click", this.clickToPlayClickHandler);
|
||||
|
@ -1362,8 +1549,12 @@
|
|||
|
||||
addListener(this.videocontrols, "resizevideocontrols", this.adjustControlSize);
|
||||
addListener(this.videocontrols, "transitionend", this.onTransitionEnd);
|
||||
addListener(this.video.ownerDocument, "mozfullscreenchange", this.onFullscreenChange);
|
||||
addListener(this.videocontrols, "transitionend", this.onControlBarTransitioned);
|
||||
addListener(this.video.ownerDocument, "fullscreenchange", this.onFullscreenChange);
|
||||
addListener(this.video, "keypress", this.keyHandler);
|
||||
addListener(this.video.textTracks, "addtrack", this.onTextTrackAdd);
|
||||
addListener(this.video.textTracks, "removetrack", this.onTextTrackRemove);
|
||||
|
||||
addListener(this.videocontrols, "dragstart", function(event) {
|
||||
event.preventDefault(); //prevent dragging of controls image (bug 517114)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<!ENTITY fullscreenButton.enterfullscreenlabel "Full Screen">
|
||||
<!ENTITY fullscreenButton.exitfullscreenlabel "Exit Full Screen">
|
||||
<!ENTITY castingButton.castingLabel "Cast to Screen">
|
||||
<!ENTITY closedCaption.off "Off">
|
||||
|
||||
<!ENTITY stats.media "Media">
|
||||
<!ENTITY stats.size "Size">
|
||||
|
|
|
@ -147,6 +147,8 @@ toolkit.jar:
|
|||
skin/classic/global/media/unmuteButton@2x.png (media/unmuteButton@2x.png)
|
||||
skin/classic/global/media/noAudio.png (media/noAudio.png)
|
||||
skin/classic/global/media/noAudio@2x.png (media/noAudio@2x.png)
|
||||
skin/classic/global/media/closeCaptionButton.png (media/closeCaptionButton.png)
|
||||
skin/classic/global/media/closeCaptionButton@2x.png (media/closeCaptionButton@2x.png)
|
||||
skin/classic/global/media/fullscreenButton.png (media/fullscreenButton.png)
|
||||
skin/classic/global/media/fullscreenButton@2x.png (media/fullscreenButton@2x.png)
|
||||
skin/classic/global/media/scrubberThumb.png (media/scrubberThumb.png)
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 583 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.3 KiB |
|
@ -12,6 +12,7 @@
|
|||
|
||||
.playButton,
|
||||
.muteButton,
|
||||
.closedCaptionButton,
|
||||
.fullscreenButton {
|
||||
background-color: transparent;
|
||||
background-repeat: no-repeat;
|
||||
|
@ -27,12 +28,14 @@
|
|||
|
||||
.playButton:hover,
|
||||
.muteButton:hover,
|
||||
.closedCaptionButton:hover,
|
||||
.fullscreenButton:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.playButton:hover:active,
|
||||
.muteButton:hover:active,
|
||||
.closedCaptionButton:hover:active,
|
||||
.fullscreenButton:hover:active {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
@ -63,6 +66,18 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.closedCaptionButton {
|
||||
background-image: url(chrome://global/skin/media/closeCaptionButton.png);
|
||||
}
|
||||
|
||||
.closedCaptionButton[enabled] {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.closedCaptionButton[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.fullscreenButton {
|
||||
background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 16, 16, 0);
|
||||
}
|
||||
|
@ -92,6 +107,41 @@
|
|||
background-clip: content-box;
|
||||
}
|
||||
|
||||
.textTrackList {
|
||||
display: -moz-box;
|
||||
-moz-appearance: none;
|
||||
-moz-box-pack: end;
|
||||
-moz-box-align: end;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.textTrackList[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.textTrackList > html|*.textTrackItem {
|
||||
-moz-appearance: none;
|
||||
-moz-box-align: start;
|
||||
text-align: start;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 2px 10px;
|
||||
-moz-margin-end: 10px;
|
||||
border: none;
|
||||
color: rgba(255,255,255,.5);
|
||||
background-color: rgba(35,31,32,.74);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.textTrackList > html|*.textTrackItem[on] {
|
||||
color: white;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.textTrackList > html|*.textTrackItem:hover {
|
||||
background-color: rgba(0,0,0,.55);
|
||||
}
|
||||
|
||||
.controlBar[fullscreen-unavailable] > .volumeStack {
|
||||
/* This value is duplicated in the videocontrols.xml adjustControlSize function. */
|
||||
margin-inline-end: 8px;
|
||||
|
@ -340,6 +390,10 @@ html|table {
|
|||
background-image: url(chrome://global/skin/media/noAudio@2x.png);
|
||||
background-size: 33px 28px;
|
||||
}
|
||||
.closeCaptionButton {
|
||||
background-image: url(chrome://global/skin/media/closeCaptionButton@2x.png);
|
||||
background-size: 28px 28px;
|
||||
}
|
||||
.fullscreenButton {
|
||||
background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton@2x.png"), 0, 32, 32, 0);
|
||||
background-size: 16px 16px;
|
||||
|
|
|
@ -101,6 +101,8 @@
|
|||
skin/classic/global/media/muteButton.png (../../windows/global/media/muteButton.png)
|
||||
skin/classic/global/media/unmuteButton.png (../../windows/global/media/unmuteButton.png)
|
||||
skin/classic/global/media/noAudio.png (../../windows/global/media/noAudio.png)
|
||||
skin/classic/global/media/closeCaptionButton.png (../../windows/global/media/closeCaptionButton.png)
|
||||
skin/classic/global/media/closeCaptionButton@2x.png (../../windows/global/media/closeCaptionButton@2x.png)
|
||||
skin/classic/global/media/fullscreenButton.png (../../windows/global/media/fullscreenButton.png)
|
||||
skin/classic/global/media/scrubberThumb.png (../../windows/global/media/scrubberThumb.png)
|
||||
skin/classic/global/media/scrubberThumbWide.png (../../windows/global/media/scrubberThumbWide.png)
|
||||
|
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 583 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.3 KiB |
|
@ -12,6 +12,7 @@
|
|||
|
||||
.playButton,
|
||||
.muteButton,
|
||||
.closedCaptionButton,
|
||||
.fullscreenButton {
|
||||
background-color: transparent;
|
||||
background-repeat: no-repeat;
|
||||
|
@ -27,12 +28,14 @@
|
|||
|
||||
.playButton:hover,
|
||||
.muteButton:hover,
|
||||
.closedCaptionButton:hover,
|
||||
.fullscreenButton:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.playButton:hover:active,
|
||||
.muteButton:hover:active,
|
||||
.closedCaptionButton:hover:active,
|
||||
.fullscreenButton:hover:active {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
@ -63,6 +66,18 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
.closedCaptionButton {
|
||||
background-image: url(chrome://global/skin/media/closeCaptionButton.png);
|
||||
}
|
||||
|
||||
.closedCaptionButton[enabled] {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.closedCaptionButton[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.fullscreenButton {
|
||||
background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 16, 16, 0);
|
||||
}
|
||||
|
@ -92,6 +107,41 @@
|
|||
background-clip: content-box;
|
||||
}
|
||||
|
||||
.textTrackList {
|
||||
display: -moz-box;
|
||||
-moz-appearance: none;
|
||||
-moz-box-pack: end;
|
||||
-moz-box-align: end;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.textTrackList[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.textTrackList > html|*.textTrackItem {
|
||||
-moz-appearance: none;
|
||||
-moz-box-align: start;
|
||||
text-align: start;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 2px 10px;
|
||||
-moz-margin-end: 10px;
|
||||
border: none;
|
||||
color: rgba(255,255,255,.5);
|
||||
background-color: rgba(35,31,32,.74);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.textTrackList > html|*.textTrackItem[on] {
|
||||
color: white;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
.textTrackList > html|*.textTrackItem:hover {
|
||||
background-color: rgba(0,0,0,.55);
|
||||
}
|
||||
|
||||
.controlBar[fullscreen-unavailable] > .volumeStack {
|
||||
/* This value is duplicated in the videocontrols.xml adjustControlSize function. */
|
||||
margin-inline-end: 8px;
|
||||
|
|
Загрузка…
Ссылка в новой задаче