mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 18:08:58 +00:00
Bug 481040 - video controls should indicate when an error occurs. r=enn
This commit is contained in:
parent
6e3ac6acb8
commit
5d2fec2163
@ -10,7 +10,7 @@
|
||||
-moz-binding: url("chrome://global/content/bindings/videocontrols.xml#suppressChangeEvent");
|
||||
}
|
||||
|
||||
.throbberOverlay {
|
||||
.statusOverlay {
|
||||
visibility: hidden;
|
||||
opacity: 0.0;
|
||||
}
|
||||
|
@ -52,8 +52,8 @@
|
||||
|
||||
<xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<stack flex="1">
|
||||
<vbox class="throbberOverlay">
|
||||
<box class="throbber" flex="1"/>
|
||||
<vbox class="statusOverlay">
|
||||
<box class="statusIcon" flex="1"/>
|
||||
</vbox>
|
||||
|
||||
<vbox>
|
||||
@ -141,8 +141,9 @@
|
||||
videoEvents : ["play", "pause", "ended", "volumechange", "loadeddata",
|
||||
"loadstart", "durationchange", "timeupdate", "progress",
|
||||
"playing", "waiting", "canplaythrough", "seeking",
|
||||
"seeked", "emptied", "loadedmetadata"],
|
||||
"seeked", "emptied", "loadedmetadata", "error"],
|
||||
|
||||
// controlFader holds the fade state for the control bar.
|
||||
controlFader : {
|
||||
name : "controls", // shorthand for debugging
|
||||
element : null, // the element to fade in/out
|
||||
@ -156,8 +157,9 @@
|
||||
RUNTIME_STEP : 30 // ms
|
||||
},
|
||||
|
||||
throbberFader : {
|
||||
name : "throbber",
|
||||
// statusFader holds the fade state for the status overlay (inc. throbber)
|
||||
statusFader : {
|
||||
name : "status",
|
||||
element : null,
|
||||
runtime : 0,
|
||||
fadingIn : false,
|
||||
@ -207,7 +209,7 @@
|
||||
if (this.video.readyState >= this.video.HAVE_CURRENT_DATA)
|
||||
this.firstFrameShown = true;
|
||||
else
|
||||
this.startFadeIn(this.throbberFader);
|
||||
this.startFadeIn(this.statusFader);
|
||||
|
||||
// We can't determine the exact buffering status, but do know if it's
|
||||
// fully loaded. (If it's still loading, it will fire a progress event
|
||||
@ -217,6 +219,15 @@
|
||||
this.bufferBar.setAttribute("value", 100);
|
||||
else
|
||||
this.bufferBar.setAttribute("value", 0);
|
||||
|
||||
// Set the current status icon. If the video is in an error state,
|
||||
// show the status overlay now.
|
||||
if (this.video.error) {
|
||||
this.statusIcon.setAttribute("type", "error");
|
||||
this.startFadeIn(this.statusFader, true);
|
||||
} else {
|
||||
this.statusIcon.setAttribute("type", "throbber");
|
||||
}
|
||||
},
|
||||
|
||||
get dynamicControls() {
|
||||
@ -227,6 +238,11 @@
|
||||
if (this.video.hasAttribute("mozNoDynamicControls"))
|
||||
enabled = false;
|
||||
|
||||
// If the video hits an error, suppress controls if it
|
||||
// hasn't managed to do anything else yet.
|
||||
if (!this.firstFrameShown && this.video.error)
|
||||
enabled = false;
|
||||
|
||||
return enabled;
|
||||
},
|
||||
|
||||
@ -263,6 +279,7 @@
|
||||
break;
|
||||
case "loadstart":
|
||||
this.maxCurrentTimeSeen = 0;
|
||||
this.statusIcon.setAttribute("type", "throbber");
|
||||
this.isAudioOnly = (this.video instanceof HTMLAudioElement);
|
||||
break;
|
||||
case "durationchange":
|
||||
@ -297,17 +314,25 @@
|
||||
break;
|
||||
case "seeking":
|
||||
case "waiting":
|
||||
this.startFadeIn(this.throbberFader);
|
||||
this.statusIcon.setAttribute("type", "throbber");
|
||||
this.startFadeIn(this.statusFader);
|
||||
break;
|
||||
case "seeked":
|
||||
// Normally we'd expect canplaythough to fire, but if we already
|
||||
// have the data cached it shouldn't fire again.
|
||||
if (this.video.readyState == this.video.HAVE_ENOUGH_DATA)
|
||||
this.startFadeOut(this.throbberFader);
|
||||
this.startFadeOut(this.statusFader);
|
||||
break;
|
||||
case "playing":
|
||||
case "canplaythrough":
|
||||
this.startFadeOut(this.throbberFader);
|
||||
this.startFadeOut(this.statusFader);
|
||||
break;
|
||||
case "error":
|
||||
this.statusIcon.setAttribute("type", "error");
|
||||
this.startFadeIn(this.statusFader, true);
|
||||
// If video hasn't shown anything yet, disable the controls.
|
||||
if (!this.firstFrameShown)
|
||||
this.startFadeOut(this.controlFader);
|
||||
break;
|
||||
default:
|
||||
this.log("!!! event " + aEvent.type + " not handled!");
|
||||
@ -322,10 +347,10 @@
|
||||
clearInterval(this.controlFader.timer);
|
||||
if (this.controlFader.delayTimer)
|
||||
clearInterval(this.controlFader.delayTimer);
|
||||
if (this.throbberFader.timer)
|
||||
clearInterval(this.throbberFader.timer);
|
||||
if (this.throbberFader.delayTimer)
|
||||
clearTimeout(this.throbberFader.delayTimer);
|
||||
if (this.statusFader.timer)
|
||||
clearInterval(this.statusFader.timer);
|
||||
if (this.statusFader.delayTimer)
|
||||
clearTimeout(this.statusFader.delayTimer);
|
||||
this.log("--- videocontrols terminated ---");
|
||||
},
|
||||
|
||||
@ -403,12 +428,12 @@
|
||||
this.startFade(this.controlFader, isMouseOver);
|
||||
},
|
||||
|
||||
startFadeIn : function (fader) {
|
||||
this.startFade(fader, true);
|
||||
startFadeIn : function (fader, immediate) {
|
||||
this.startFade(fader, true, immediate);
|
||||
},
|
||||
|
||||
startFadeOut : function (fader) {
|
||||
this.startFade(fader, false);
|
||||
startFadeOut : function (fader, immediate) {
|
||||
this.startFade(fader, false, immediate);
|
||||
},
|
||||
|
||||
startFade : function (fader, fadeIn, immediate) {
|
||||
@ -543,7 +568,8 @@
|
||||
this.Utils.isAudioOnly = (video instanceof HTMLAudioElement);
|
||||
|
||||
this.Utils.controlFader.element = document.getAnonymousElementByAttribute(this, "class", "controlBar");
|
||||
this.Utils.throbberFader.element = document.getAnonymousElementByAttribute(this, "class", "throbberOverlay");
|
||||
this.Utils.statusFader.element = document.getAnonymousElementByAttribute(this, "class", "statusOverlay");
|
||||
this.Utils.statusIcon = document.getAnonymousElementByAttribute(this, "class", "statusIcon");
|
||||
|
||||
this.Utils.playButton = document.getAnonymousElementByAttribute(this, "class", "playButton");
|
||||
this.Utils.muteButton = document.getAnonymousElementByAttribute(this, "class", "muteButton");
|
||||
|
@ -179,6 +179,7 @@ classic.jar:
|
||||
+ skin/classic/global/media/muteButton.png (media/muteButton.png)
|
||||
+ skin/classic/global/media/unmuteButton.png (media/unmuteButton.png)
|
||||
+ skin/classic/global/media/scrubberThumb.png (media/scrubberThumb.png)
|
||||
+ skin/classic/global/media/error.png (media/error.png)
|
||||
+ skin/classic/global/media/throbber.png (media/throbber.png)
|
||||
+ skin/classic/global/menu/menu-arrow-dis.gif (menu/menu-arrow-dis.gif)
|
||||
+ skin/classic/global/menu/menu-arrow-hov.gif (menu/menu-arrow-hov.gif)
|
||||
|
BIN
toolkit/themes/pinstripe/global/media/error.png
Normal file
BIN
toolkit/themes/pinstripe/global/media/error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 433 B |
@ -80,13 +80,20 @@
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.throbberOverlay {
|
||||
.statusOverlay {
|
||||
background-color: rgba(0,0,0,0.55);
|
||||
}
|
||||
|
||||
.throbber {
|
||||
background: url(chrome://global/skin/media/throbber.png) no-repeat center;
|
||||
height: 36px;
|
||||
.statusIcon {
|
||||
margin-bottom: 28px; /* same height as .controlBar, to keep icon centered above it */
|
||||
width: 36px;
|
||||
margin-bottom: 28px; /* same height as .controlBar, to keep throbber centered above it */
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.statusIcon[type="throbber"] {
|
||||
background: url(chrome://global/skin/media/throbber.png) no-repeat center;
|
||||
}
|
||||
|
||||
.statusIcon[type="error"] {
|
||||
background: url(chrome://global/skin/media/error.png) no-repeat center;
|
||||
}
|
||||
|
@ -153,6 +153,7 @@ classic.jar:
|
||||
skin/classic/global/media/unmuteButton.png (media/unmuteButton.png)
|
||||
skin/classic/global/media/scrubberThumb.png (media/scrubberThumb.png)
|
||||
skin/classic/global/media/throbber.png (media/throbber.png)
|
||||
skin/classic/global/media/error.png (media/error.png)
|
||||
skin/classic/global/radio/radio-check.gif (radio/radio-check.gif)
|
||||
skin/classic/global/radio/radio-check-dis.gif (radio/radio-check-dis.gif)
|
||||
skin/classic/global/scrollbar/slider.gif (scrollbar/slider.gif)
|
||||
@ -326,6 +327,7 @@ classic.jar:
|
||||
skin/classic/aero/global/media/unmuteButton.png (media/unmuteButton.png)
|
||||
skin/classic/aero/global/media/scrubberThumb.png (media/scrubberThumb.png)
|
||||
skin/classic/aero/global/media/throbber.png (media/throbber.png)
|
||||
skin/classic/aero/global/media/error.png (media/error.png)
|
||||
skin/classic/aero/global/radio/radio-check.gif (radio/radio-check.gif)
|
||||
skin/classic/aero/global/radio/radio-check-dis.gif (radio/radio-check-dis.gif)
|
||||
skin/classic/aero/global/scrollbar/slider.gif (scrollbar/slider.gif)
|
||||
|
BIN
toolkit/themes/winstripe/global/media/error.png
Normal file
BIN
toolkit/themes/winstripe/global/media/error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 433 B |
@ -87,13 +87,20 @@
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.throbberOverlay {
|
||||
.statusOverlay {
|
||||
background-color: rgba(0,0,0,0.55);
|
||||
}
|
||||
|
||||
.throbber {
|
||||
background: url(chrome://global/skin/media/throbber.png) no-repeat center;
|
||||
height: 36px;
|
||||
.statusIcon {
|
||||
margin-bottom: 28px; /* same height as .controlBar, to keep icon centered above it */
|
||||
width: 36px;
|
||||
margin-bottom: 28px; /* same height as .controlBar, to keep throbber centered above it */
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.statusIcon[type="throbber"] {
|
||||
background: url(chrome://global/skin/media/throbber.png) no-repeat center;
|
||||
}
|
||||
|
||||
.statusIcon[type="error"] {
|
||||
background: url(chrome://global/skin/media/error.png) no-repeat center;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user