Bug 649490 - Switch the volume slider on the media controls to be horizontal and always visible. r=Gijs
--HG-- extra : rebase_source : 90a0865e71b87dbaddf44c4805f78f709e5d80de
@ -65,7 +65,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=483573
|
||||
var audioElm = getAccessible("audio");
|
||||
var playBtn = audioElm.firstChild;
|
||||
var scrubber = playBtn.nextSibling.nextSibling.nextSibling;
|
||||
var muteBtn = audioElm.lastChild;
|
||||
var muteBtn = audioElm.lastChild.previousSibling;
|
||||
|
||||
var actions = [
|
||||
{
|
||||
|
@ -49,7 +49,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=483573
|
||||
role: ROLE_PUSHBUTTON,
|
||||
name: "Mute",
|
||||
children: []
|
||||
}
|
||||
},
|
||||
{ // slider of volume bar
|
||||
role: ROLE_SLIDER,
|
||||
children: []
|
||||
},
|
||||
]
|
||||
};
|
||||
testAccessibleTree("audio", accTree);
|
||||
|
@ -54,7 +54,7 @@
|
||||
* is hidden by videocontrols.xml, and that alters the position of the
|
||||
* play button. This workaround moves it back to center.
|
||||
*/
|
||||
.controlBar.audio .playButton {
|
||||
.controlBar.audio-only .playButton {
|
||||
transform: translateX(28px);
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@
|
||||
* is hidden by videocontrols.xml, and that alters the position of the
|
||||
* play button. This workaround moves it back to center.
|
||||
*/
|
||||
.controlBar.audio .playButton {
|
||||
.controlBar.audio-only .playButton {
|
||||
transform: translateX(28px);
|
||||
}
|
||||
|
||||
|
@ -30,14 +30,15 @@ const muteButtonWidth = 33;
|
||||
const muteButtonHeight = 28;
|
||||
const durationWidth = 34;
|
||||
const fullscreenButtonWidth = document.mozFullScreenEnabled ? 28 : 0;
|
||||
const scrubberWidth = videoWidth - playButtonWidth - muteButtonWidth - durationWidth - fullscreenButtonWidth;
|
||||
const volumeSliderWidth = 32;
|
||||
const scrubberWidth = videoWidth - playButtonWidth - durationWidth - muteButtonWidth - volumeSliderWidth - fullscreenButtonWidth;
|
||||
const scrubberHeight = 28;
|
||||
|
||||
// Play button is on the bottom-left
|
||||
const playButtonCenterX = 0 + Math.round(playButtonWidth / 2);
|
||||
const playButtonCenterY = videoHeight - Math.round(playButtonHeight / 2);
|
||||
// Mute button is on the bottom-right before the full screen button
|
||||
const muteButtonCenterX = videoWidth - Math.round(muteButtonWidth / 2) - fullscreenButtonWidth;
|
||||
// Mute button is on the bottom-right before the full screen button and volume slider
|
||||
const muteButtonCenterX = videoWidth - Math.round(muteButtonWidth / 2) - volumeSliderWidth - fullscreenButtonWidth;
|
||||
const muteButtonCenterY = videoHeight - Math.round(muteButtonHeight / 2);
|
||||
// Scrubber bar is between the play and mute buttons. We don't need it's
|
||||
// X center, just the offset of its box.
|
||||
|
@ -92,7 +92,8 @@ html|span.statActivity[seeking] > html|span.statActivitySeeking {
|
||||
.controlBar[size="hidden"],
|
||||
.controlBar[size="small"] .durationBox,
|
||||
.controlBar[size="small"] .durationLabel,
|
||||
.controlBar[size="small"] .positionLabel {
|
||||
.controlBar[size="small"] .positionLabel,
|
||||
.controlBar[size="small"] .volumeStack {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
|
@ -287,9 +287,10 @@
|
||||
<button class="muteButton"
|
||||
mutelabel="&muteButton.muteLabel;"
|
||||
unmutelabel="&muteButton.unmuteLabel;"/>
|
||||
<stack class="volumeStack" hidden="true" fadeout="true">
|
||||
<box class="volumeBackgroundBar"/>
|
||||
<scale class="volumeControl" orient="vertical" dir="reverse" movetoclick="true"/>
|
||||
<stack class="volumeStack">
|
||||
<box class="volumeBackground"/>
|
||||
<box class="volumeForeground" anonid="volumeForeground"/>
|
||||
<scale class="volumeControl" movetoclick="true"/>
|
||||
</stack>
|
||||
<button class="fullscreenButton"
|
||||
enterfullscreenlabel="&fullscreenButton.enterfullscreenlabel;"
|
||||
@ -313,7 +314,6 @@
|
||||
controlBar : null,
|
||||
playButton : null,
|
||||
muteButton : null,
|
||||
volumeStack : null,
|
||||
volumeControl : null,
|
||||
durationLabel : null,
|
||||
positionLabel : null,
|
||||
@ -342,6 +342,13 @@
|
||||
get isAudioOnly() { return this._isAudioOnly; },
|
||||
set isAudioOnly(val) {
|
||||
this._isAudioOnly = val;
|
||||
if (this._isAudioOnly) {
|
||||
this.controlBar.setAttribute("audio-only", true);
|
||||
} else {
|
||||
this.controlBar.removeAttribute("audio-only");
|
||||
}
|
||||
this.adjustControlSize();
|
||||
|
||||
if (!this.isTopLevelSyntheticDocument)
|
||||
return;
|
||||
if (this._isAudioOnly) {
|
||||
@ -462,6 +469,7 @@
|
||||
this._playButtonWidth = this.playButton.clientWidth;
|
||||
this._durationLabelWidth = this.durationLabel.clientWidth;
|
||||
this._muteButtonWidth = this.muteButton.clientWidth;
|
||||
this._volumeControlWidth = this.volumeControl.clientWidth;
|
||||
this._fullscreenButtonWidth = this.fullscreenButton.clientWidth;
|
||||
this._controlBarHeight = this.controlBar.clientHeight;
|
||||
this.controlBar.hidden = true;
|
||||
@ -554,9 +562,11 @@
|
||||
this.setupStatusFader();
|
||||
break;
|
||||
case "volumechange":
|
||||
var volume = this.video.muted ? 0 : Math.round(this.video.volume * 100);
|
||||
var volume = this.video.muted ? 0 : this.video.volume;
|
||||
var volumePercentage = Math.round(volume * 100);
|
||||
this.setMuteButtonState(this.video.muted);
|
||||
this.volumeControl.value = volume;
|
||||
this.volumeControl.value = volumePercentage;
|
||||
this.volumeForeground.style.paddingRight = (1 - volume) * this._volumeControlWidth + "px";
|
||||
break;
|
||||
case "loadedmetadata":
|
||||
this.adjustControlSize();
|
||||
@ -854,21 +864,6 @@
|
||||
this.bufferBar.value = endTime;
|
||||
},
|
||||
|
||||
onVolumeMouseInOut : function (event) {
|
||||
let doc = this.video.ownerDocument;
|
||||
let win = doc.defaultView;
|
||||
if (this.isVideoWithoutAudioTrack() ||
|
||||
(this.isAudioOnly && this.isTopLevelSyntheticDocument)) {
|
||||
return;
|
||||
}
|
||||
// Ignore events caused by transitions between mute button and volumeStack,
|
||||
// or between nodes inside these two elements.
|
||||
if (this.isEventWithin(event, this.muteButton, this.volumeStack))
|
||||
return;
|
||||
var isMouseOver = (event.type == "mouseover");
|
||||
this.startFade(this.volumeStack, isMouseOver);
|
||||
},
|
||||
|
||||
_controlsHiddenByTimeout : false,
|
||||
_showControlsTimeout : 0,
|
||||
SHOW_CONTROLS_TIMEOUT_MS: 500,
|
||||
@ -1360,15 +1355,14 @@
|
||||
_playButtonWidth : 0,
|
||||
_durationLabelWidth : 0,
|
||||
_muteButtonWidth : 0,
|
||||
_volumeControlWidth : 0,
|
||||
_fullscreenButtonWidth : 0,
|
||||
_controlBarHeight : 0,
|
||||
_overlayPlayButtonHeight : 64,
|
||||
_overlayPlayButtonWidth : 64,
|
||||
_volumeStackMarginEnd : 8,
|
||||
adjustControlSize : function adjustControlSize() {
|
||||
let doc = this.video.ownerDocument;
|
||||
let isAudioOnly = this.isAudioOnly;
|
||||
if (isAudioOnly && !this.isTopLevelSyntheticDocument)
|
||||
return;
|
||||
|
||||
// The scrubber has |flex=1|, therefore |minScrubberWidth|
|
||||
// was generated by empirical testing.
|
||||
@ -1377,7 +1371,15 @@
|
||||
minScrubberWidth +
|
||||
this._durationLabelWidth +
|
||||
this._muteButtonWidth +
|
||||
this._volumeControlWidth +
|
||||
this._fullscreenButtonWidth;
|
||||
|
||||
let isAudioOnly = this.isAudioOnly;
|
||||
if (isAudioOnly) {
|
||||
// When the fullscreen button is hidden we add margin-end to the volume stack.
|
||||
minWidthAllControls -= this._fullscreenButtonWidth - this._volumeStackMarginEnd;
|
||||
}
|
||||
|
||||
let minHeightForControlBar = this._controlBarHeight;
|
||||
let minWidthOnlyPlayPause = this._playButtonWidth + this._muteButtonWidth;
|
||||
|
||||
@ -1400,14 +1402,12 @@
|
||||
init : function (binding) {
|
||||
this.video = binding.parentNode;
|
||||
this.videocontrols = binding;
|
||||
this.isAudioOnly = (this.video instanceof HTMLAudioElement);
|
||||
|
||||
this.statusIcon = document.getAnonymousElementByAttribute(binding, "class", "statusIcon");
|
||||
this.controlBar = document.getAnonymousElementByAttribute(binding, "class", "controlBar");
|
||||
this.playButton = document.getAnonymousElementByAttribute(binding, "class", "playButton");
|
||||
this.muteButton = document.getAnonymousElementByAttribute(binding, "class", "muteButton");
|
||||
this.volumeControl = document.getAnonymousElementByAttribute(binding, "class", "volumeControl");
|
||||
this.volumeStack = document.getAnonymousElementByAttribute(binding, "class", "volumeStack");
|
||||
this.progressBar = document.getAnonymousElementByAttribute(binding, "class", "progressBar");
|
||||
this.bufferBar = document.getAnonymousElementByAttribute(binding, "class", "bufferBar");
|
||||
this.scrubber = document.getAnonymousElementByAttribute(binding, "class", "scrubber");
|
||||
@ -1419,6 +1419,7 @@
|
||||
this.controlsSpacer = document.getAnonymousElementByAttribute(binding, "class", "controlsSpacer");
|
||||
this.clickToPlay = document.getAnonymousElementByAttribute(binding, "class", "clickToPlay");
|
||||
this.fullscreenButton = document.getAnonymousElementByAttribute(binding, "class", "fullscreenButton");
|
||||
this.volumeForeground = document.getAnonymousElementByAttribute(binding, "anonid", "volumeForeground");
|
||||
|
||||
this.statsTable = document.getAnonymousElementByAttribute(binding, "class", "statsTable");
|
||||
this.stats.filename = document.getAnonymousElementByAttribute(binding, "class", "statFilename");
|
||||
@ -1432,6 +1433,7 @@
|
||||
this.stats.framesPresented = document.getAnonymousElementByAttribute(binding, "class", "statFramesPresented");
|
||||
this.stats.framesPainted = document.getAnonymousElementByAttribute(binding, "class", "statFramesPainted");
|
||||
|
||||
this.isAudioOnly = (this.video instanceof HTMLAudioElement);
|
||||
this.setupInitialState();
|
||||
this.setupNewLoadState();
|
||||
|
||||
@ -1459,15 +1461,6 @@
|
||||
addListener(this.controlsSpacer, "click", this.clickToPlayClickHandler);
|
||||
addListener(this.controlsSpacer, "dblclick", this.toggleFullscreen);
|
||||
|
||||
if (this.isAudioOnly) {
|
||||
this.controlBar.classList.add("audio");
|
||||
} else {
|
||||
addListener(this.muteButton, "mouseover", this.onVolumeMouseInOut);
|
||||
addListener(this.muteButton, "mouseout", this.onVolumeMouseInOut);
|
||||
addListener(this.volumeStack, "mouseover", this.onVolumeMouseInOut);
|
||||
addListener(this.volumeStack, "mouseout", this.onVolumeMouseInOut);
|
||||
}
|
||||
|
||||
addListener(this.videocontrols, "resizevideocontrols", this.adjustControlSize);
|
||||
addListener(this.videocontrols, "transitionend", this.onTransitionEnd);
|
||||
addListener(this.video.ownerDocument, "mozfullscreenchange", this.onFullscreenChange);
|
||||
@ -1539,11 +1532,12 @@
|
||||
<button class="muteButton"
|
||||
mutelabel="&muteButton.muteLabel;"
|
||||
unmutelabel="&muteButton.unmuteLabel;"/>
|
||||
<stack class="volumeStack" hidden="true" fadeout="true">
|
||||
<box class="volumeBackgroundBar"/>
|
||||
<scale class="volumeControl" orient="vertical" dir="reverse" movetoclick="true"/>
|
||||
<stack class="volumeStack">
|
||||
<box class="volumeBackground"/>
|
||||
<box class="volumeForeground" anonid="volumeForeground"/>
|
||||
<scale class="volumeControl" movetoclick="true"/>
|
||||
</stack>
|
||||
</hbox>
|
||||
</hbox>
|
||||
<stack class="scrubberStack" flex="1">
|
||||
<box class="backgroundBar"/>
|
||||
<progressmeter class="bufferBar"/>
|
||||
|
@ -174,8 +174,8 @@ toolkit.jar:
|
||||
skin/classic/global/media/error.png (media/error.png)
|
||||
skin/classic/global/media/throbber.png (media/throbber.png)
|
||||
skin/classic/global/media/stalled.png (media/stalled.png)
|
||||
skin/classic/global/media/volumeThumb.png (media/volumeThumb.png)
|
||||
skin/classic/global/media/volumeThumb@2x.png (media/volumeThumb@2x.png)
|
||||
skin/classic/global/media/volume-empty.png (media/volume-empty.png)
|
||||
skin/classic/global/media/volume-full.png (media/volume-full.png)
|
||||
skin/classic/global/media/clicktoplay-bgtexture.png (media/clicktoplay-bgtexture.png)
|
||||
skin/classic/global/media/videoClickToPlayButton.svg (media/videoClickToPlayButton.svg)
|
||||
skin/classic/global/menu/menu-arrow.png (menu/menu-arrow.png)
|
||||
|
@ -59,6 +59,10 @@
|
||||
background-image: url(chrome://global/skin/media/noAudio.png);
|
||||
}
|
||||
|
||||
.muteButton[noAudio] + .volumeStack {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.fullscreenButton {
|
||||
background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 16, 16, 0);
|
||||
}
|
||||
@ -67,36 +71,35 @@
|
||||
background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 32, 16, 16);
|
||||
}
|
||||
|
||||
.volumeStack {
|
||||
width: 28px;
|
||||
height: 70px;
|
||||
background-color: rgba(35,31,32,.74);
|
||||
/* use negative margin to place stack over the mute button to its left. */
|
||||
margin: -70px 3px 28px -31px;
|
||||
overflow: hidden; /* crop it when sliding down, don't grow the control bar */
|
||||
position: relative; /* Trick to work around negative margin interfering with dragging the thumb. */
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.volumeControl {
|
||||
min-height: 64px;
|
||||
width: 32px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.volumeBackground,
|
||||
.volumeForeground {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.volumeBackground {
|
||||
background-image: url(chrome://global/skin/media/volume-empty.png);
|
||||
}
|
||||
|
||||
.volumeForeground {
|
||||
background-image: url(chrome://global/skin/media/volume-full.png);
|
||||
background-clip: content-box;
|
||||
}
|
||||
|
||||
.controlBar[audio-only] > .volumeStack {
|
||||
/* This value is duplicated in the videocontrols.xml adjustControlSize function. */
|
||||
-moz-margin-end: 8px;
|
||||
}
|
||||
|
||||
/* .scale-thumb is an element inside the <scale> implementation. */
|
||||
.volumeControl .scale-thumb {
|
||||
/* Override the default thumb appearance with a custom image. */
|
||||
-moz-appearance: none;
|
||||
background: url(chrome://global/skin/media/volumeThumb.png) no-repeat center;
|
||||
border: none;
|
||||
min-width: 20px;
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
.volumeBackgroundBar {
|
||||
/* margin left/right: make bar 8px wide (control width = 28, minus 2 * 10 margin) */
|
||||
margin: 0 10px;
|
||||
background-color: rgba(255,255,255,.75);
|
||||
border-radius: 2.5px;
|
||||
min-width: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.durationBox {
|
||||
@ -337,10 +340,6 @@ html|table {
|
||||
background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton@2x.png"), 0, 64, 32, 32);
|
||||
background-size: 16px 16px;
|
||||
}
|
||||
.volumeControl .scale-thumb {
|
||||
background-image: url(chrome://global/skin/media/volumeThumb@2x.png);
|
||||
background-size: 20px 10px;
|
||||
}
|
||||
.timeThumb {
|
||||
background-image: url(chrome://global/skin/media/scrubberThumb@2x.png);
|
||||
background-size: 33px 28px;
|
||||
|
BIN
toolkit/themes/osx/global/media/volume-empty.png
Normal file
After Width: | Height: | Size: 295 B |
BIN
toolkit/themes/osx/global/media/volume-full.png
Normal file
After Width: | Height: | Size: 297 B |
Before Width: | Height: | Size: 163 B |
Before Width: | Height: | Size: 281 B |
@ -163,7 +163,8 @@ toolkit.jar:
|
||||
skin/classic/global/media/scrubberThumbWide.png (media/scrubberThumbWide.png)
|
||||
skin/classic/global/media/throbber.png (media/throbber.png)
|
||||
skin/classic/global/media/stalled.png (media/stalled.png)
|
||||
skin/classic/global/media/volumeThumb.png (media/volumeThumb.png)
|
||||
skin/classic/global/media/volume-empty.png (media/volume-empty.png)
|
||||
skin/classic/global/media/volume-full.png (media/volume-full.png)
|
||||
skin/classic/global/media/error.png (media/error.png)
|
||||
skin/classic/global/media/clicktoplay-bgtexture.png (media/clicktoplay-bgtexture.png)
|
||||
skin/classic/global/media/videoClickToPlayButton.svg (media/videoClickToPlayButton.svg)
|
||||
@ -344,7 +345,8 @@ toolkit.jar:
|
||||
skin/classic/aero/global/media/scrubberThumbWide.png (media/scrubberThumbWide.png)
|
||||
skin/classic/aero/global/media/throbber.png (media/throbber.png)
|
||||
skin/classic/aero/global/media/stalled.png (media/stalled.png)
|
||||
skin/classic/aero/global/media/volumeThumb.png (media/volumeThumb.png)
|
||||
skin/classic/aero/global/media/volume-empty.png (media/volume-empty.png)
|
||||
skin/classic/aero/global/media/volume-full.png (media/volume-full.png)
|
||||
skin/classic/aero/global/media/error.png (media/error.png)
|
||||
skin/classic/aero/global/media/clicktoplay-bgtexture.png (media/clicktoplay-bgtexture.png)
|
||||
skin/classic/aero/global/media/videoClickToPlayButton.svg (media/videoClickToPlayButton.svg)
|
||||
|
@ -59,6 +59,10 @@
|
||||
background-image: url(chrome://global/skin/media/noAudio.png);
|
||||
}
|
||||
|
||||
.muteButton[noAudio] + .volumeStack {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.fullscreenButton {
|
||||
background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 16, 16, 0);
|
||||
}
|
||||
@ -67,36 +71,35 @@
|
||||
background-image: -moz-image-rect(url("chrome://global/skin/media/fullscreenButton.png"), 0, 32, 16, 16);
|
||||
}
|
||||
|
||||
.volumeStack {
|
||||
width: 28px;
|
||||
height: 70px;
|
||||
background-color: rgba(35,31,32,.74);
|
||||
/* use negative margin to place stack over the mute button to its left. */
|
||||
margin: -70px 3px 28px -31px;
|
||||
overflow: hidden; /* crop it when sliding down, don't grow the control bar */
|
||||
position: relative; /* Trick to work around negative margin interfering with dragging the thumb. */
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.volumeControl {
|
||||
min-height: 64px;
|
||||
width: 32px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.volumeBackground,
|
||||
.volumeForeground {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.volumeBackground {
|
||||
background-image: url(chrome://global/skin/media/volume-empty.png);
|
||||
}
|
||||
|
||||
.volumeForeground {
|
||||
background-image: url(chrome://global/skin/media/volume-full.png);
|
||||
background-clip: content-box;
|
||||
}
|
||||
|
||||
.controlBar[audio-only] > .volumeStack {
|
||||
/* This value is duplicated in the videocontrols.xml adjustControlSize function. */
|
||||
-moz-margin-end: 8px;
|
||||
}
|
||||
|
||||
/* .scale-thumb is an element inside the <scale> implementation. */
|
||||
.volumeControl .scale-thumb {
|
||||
/* Override the default thumb appearance with a custom image. */
|
||||
-moz-appearance: none;
|
||||
background: url(chrome://global/skin/media/volumeThumb.png) no-repeat center;
|
||||
border: none;
|
||||
min-width: 20px;
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
.volumeBackgroundBar {
|
||||
/* margin left/right: make bar 8px wide (control width = 28, minus 2 * 10 margin) */
|
||||
margin: 0 10px;
|
||||
background-color: rgba(255,255,255,.75);
|
||||
border-radius: 2.5px;
|
||||
min-width: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.durationBox {
|
||||
@ -170,7 +173,8 @@
|
||||
}
|
||||
|
||||
/* .scale-thumb is an element inside the <scale> implementation. */
|
||||
.scrubber .scale-thumb {
|
||||
.scrubber .scale-thumb,
|
||||
.volumeControl .scale-thumb {
|
||||
/* Override the default thumb appearance with a custom image. */
|
||||
-moz-appearance: none;
|
||||
background: transparent;
|
||||
|
BIN
toolkit/themes/windows/global/media/volume-empty.png
Normal file
After Width: | Height: | Size: 295 B |
BIN
toolkit/themes/windows/global/media/volume-full.png
Normal file
After Width: | Height: | Size: 297 B |
Before Width: | Height: | Size: 163 B |