зеркало из https://github.com/mozilla/gecko-dev.git
Bug 513405 - Add text to video controls to describe the cause of errors. r=dolske
This commit is contained in:
Родитель
c2f20bb2e4
Коммит
4f49dc45fd
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче