Bug 513405 - Add text to video controls to describe the cause of errors. r=dolske

This commit is contained in:
Jared Wein 2011-12-05 14:00:28 -08:00
Родитель c2f20bb2e4
Коммит 4f49dc45fd
5 изменённых файлов: 106 добавлений и 8 удалений

Просмотреть файл

@ -94,3 +94,17 @@ html|span.statActivity[seeking] > html|span.statActivitySeeking {
.controlBar[size="small"] .scrubber {
visibility: hidden;
}
/* Error description formatting */
.errorLabel {
display: none;
}
[error="errorAborted"] > [anonid="errorAborted"],
[error="errorNetwork"] > [anonid="errorNetwork"],
[error="errorDecode"] > [anonid="errorDecode"],
[error="errorSrcNotSupported"] > [anonid="errorSrcNotSupported"],
[error="errorNoSource"] > [anonid="errorNoSource"],
[error="errorGeneric"] > [anonid="errorGeneric"] {
display: inline;
}

Просмотреть файл

@ -198,6 +198,12 @@
<stack flex="1">
<vbox flex="1" class="statusOverlay" hidden="true">
<box class="statusIcon"/>
<label class="errorLabel" anonid="errorAborted">&error.aborted;</label>
<label class="errorLabel" anonid="errorNetwork">&error.network;</label>
<label class="errorLabel" anonid="errorDecode">&error.decode;</label>
<label class="errorLabel" anonid="errorSrcNotSupported">&error.srcNotSupported;</label>
<label class="errorLabel" anonid="errorNoSource">&error.noSource;</label>
<label class="errorLabel" anonid="errorGeneric">&error.generic;</label>
</vbox>
<vbox class="statsOverlay" hidden="true">
@ -412,8 +418,9 @@
this.bufferBar.setAttribute("value", 0);
// Set the current status icon.
if (this.video.error || this.video.networkState == this.video.NETWORK_NO_SOURCE) {
if (this.hasError()) {
this.statusIcon.setAttribute("type", "error");
this.updateErrorText();
this.setupStatusFader(true);
} else {
this.statusIcon.setAttribute("type", "throbber");
@ -452,7 +459,7 @@
// If the video hits an error, suppress controls if it
// hasn't managed to do anything else yet.
if (!this.firstFrameShown && (this.video.error || this.video.networkState == this.video.NETWORK_NO_SOURCE))
if (!this.firstFrameShown && this.hasError())
enabled = false;
return enabled;
@ -514,6 +521,8 @@
break;
case "loadstart":
this.maxCurrentTimeSeen = 0;
this.controlsSpacer.removeAttribute("aria-label");
this.statusOverlay.removeAttribute("error");
this.statusIcon.setAttribute("type", "throbber");
this.isAudioOnly = (this.video instanceof HTMLAudioElement);
this.setPlayButtonState(true);
@ -586,8 +595,9 @@
// 2. The video's networkState is NETWORK_NO_SOURCE. This means we we're
// loading from child source elements, but we were unable to select
// any of the child elements for playback during resource selection.
if (this.video.error || this.video.networkState == this.video.NETWORK_NO_SOURCE) {
if (this.hasError()) {
this.statusIcon.setAttribute("type", "error");
this.updateErrorText();
this.setupStatusFader(true);
// If video hasn't shown anything yet, disable the controls.
if (!this.firstFrameShown)
@ -604,7 +614,7 @@
clearInterval(this.statsInterval);
this.statsInterval = null;
}
for each (var event in this.videoEvents)
for each (let event in this.videoEvents)
this.video.removeEventListener(event, this, false);
this.video.removeEventListener("media-showStatistics", this._handleCustomEventsBound, false);
delete this._handleCustomEventsBound;
@ -613,6 +623,45 @@
this.log("--- videocontrols terminated ---");
},
hasError : function () {
return (this.video.error != null || this.video.networkState == this.video.NETWORK_NO_SOURCE);
},
updateErrorText : function () {
let error;
let v = this.video;
// It is possible to have both v.networkState == NETWORK_NO_SOURCE
// as well as v.error being non-null. In this case, we will show
// the v.error.code instead of the v.networkState error.
if (v.error) {
switch (v.error.code) {
case v.error.MEDIA_ERR_ABORTED:
error = "errorAborted";
break;
case v.error.MEDIA_ERR_NETWORK:
error = "errorNetwork";
break;
case v.error.MEDIA_ERR_DECODE:
error = "errorDecode";
break;
case v.error.MEDIA_ERR_SRC_NOT_SUPPORTED:
error = "errorSrcNotSupported";
break;
default:
error = "errorGeneric";
break;
}
} else if (v.networkState == v.NETWORK_NO_SOURCE) {
error = "errorNoSource";
} else {
return; // No error found.
}
let label = document.getAnonymousElementByAttribute(this.videocontrols, "anonid", error);
this.controlsSpacer.setAttribute("aria-label", label.textContent);
this.statusOverlay.setAttribute("error", error);
},
formatTime : function(aTime) {
// Format the duration as "h:mm:ss" or "m:ss"
aTime = Math.round(aTime / 1000);
@ -1185,13 +1234,13 @@
// Use the handleEvent() callback for all media events.
// The "error" event listener must capture, so that it can trap error events
// from the <source> children, which don't bubble.
for each (var event in this.videoEvents)
for each (let event in this.videoEvents)
this.video.addEventListener(event, this, (event == "error") ? true : false);
var self = this;
this.muteButton.addEventListener("command", function() { self.toggleMute(); }, false);
this.playButton.addEventListener("command", function() { self.togglePause(); }, false);
this.controlsSpacer.addEventListener("click", function(e) { if (e.button == 0) { self.togglePause(); } }, false);
this.controlsSpacer.addEventListener("click", function(e) { if (e.button == 0 && !self.hasError()) { self.togglePause(); } }, false);
this.fullscreenButton.addEventListener("command", function() { self.toggleFullscreen(); }, false );
if (!this.isAudioOnly) {
this.muteButton.addEventListener("mouseover", function(e) { self.onVolumeMouseInOut(e); }, false);

Просмотреть файл

@ -20,6 +20,13 @@
<!ENTITY stats.framesPresented "Frames presented">
<!ENTITY stats.framesPainted "Frames painted">
<!ENTITY error.aborted "Video loading stopped.">
<!ENTITY error.network "Video playback aborted due to a network error.">
<!ENTITY error.decode "Video can't be played because the file is corrupt.">
<!ENTITY error.srcNotSupported "Video format or MIME type is not supported.">
<!ENTITY error.noSource "Video not found.">
<!ENTITY error.generic "Video playback aborted due to an unknown error.">
<!-- LOCALIZATION NOTE (scrubberScale.nameFormat): the #1 string is the current
media position, and the #2 string is the total duration. For example, when at
the 5 minute mark in a 6 hour long video, #1 would be "5:00" and #2 would be

Просмотреть файл

@ -206,7 +206,7 @@ html|td {
padding: 0 2px;
}
html|table {
font-family: Helvetica, Ariel, sans-serif;
font-family: Helvetica, Arial, sans-serif;
font-size: 11px;
color: white;
text-shadow:
@ -245,3 +245,17 @@ html|table {
.statusOverlay[fadeout] {
opacity: 0;
}
/* Error description formatting */
.errorLabel {
font-family: Helvetica, Arial, sans-serif;
font-size: 11px;
color: #bbb;
text-shadow:
-1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000;
padding: 0 10px;
text-align: center;
}

Просмотреть файл

@ -215,7 +215,7 @@ html|td {
padding: 0 2px;
}
html|table {
font-family: Helvetica, Ariel, sans-serif;
font-family: Helvetica, Arial, sans-serif;
font-size: 11px;
color: white;
text-shadow:
@ -254,3 +254,17 @@ html|table {
.statusOverlay[fadeout] {
opacity: 0;
}
/* Error description formatting */
.errorLabel {
font-family: Helvetica, Arial, sans-serif;
font-size: 11px;
color: #bbb;
text-shadow:
-1px -1px 0 #000,
1px -1px 0 #000,
-1px 1px 0 #000,
1px 1px 0 #000;
padding: 0 10px;
text-align: center;
}