author | Justin Dolske <dolske@mozilla.com> |
Mon, 23 Mar 2009 16:40:39 -0700 | |
changeset 26477 | ad88f5d62c7c18e838f4d7010d9a70c3527da848 |
parent 26476 | 6ed2d1cbc338b24a3d2bea97a75595288bc65f85 |
child 26478 | 999cd55bd9c046b6205ead0b6c7c17bd5552d731 |
push id | unknown |
push user | unknown |
push date | unknown |
reviewers | enn |
bugs | 481040 |
milestone | 1.9.2a1pre |
--- a/toolkit/content/widgets/videocontrols.css +++ b/toolkit/content/widgets/videocontrols.css @@ -5,12 +5,12 @@ visibility: hidden; opacity: 0.0; } .scrubber { -moz-binding: url("chrome://global/content/bindings/videocontrols.xml#suppressChangeEvent"); } -.throbberOverlay { +.statusOverlay { visibility: hidden; opacity: 0.0; }
--- a/toolkit/content/widgets/videocontrols.xml +++ b/toolkit/content/widgets/videocontrols.xml @@ -47,18 +47,18 @@ <resources> <stylesheet src="chrome://global/content/bindings/videocontrols.css"/> <stylesheet src="chrome://global/skin/media/videocontrols.css"/> </resources> <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> <spacer flex="1"/> <hbox class="controlBar"> <button class="playButton" oncommand="document.getBindingParent(this).Utils.togglePause();"/> <stack class="scrubberStack" flex="1"> <box class="backgroundBar"/> @@ -136,33 +136,35 @@ progressBar : null, bufferBar : null, thumbWidth : 0, randomID : 0, 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 runtime : 0, // duration of active animation fadingIn : false, // are we fading in, or fading out? isVisible : false, // is it at all visible? timer : null, // handle from setInterval() delayTimer : null, // handle from setTimeout() START_DELAY : 0, // ms, delay before fading in RUNTIME_MAX : 200, // ms 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, isVisible : false, timer : null, delayTimer : null, START_DELAY : 750, RUNTIME_MAX : 300, @@ -202,36 +204,50 @@ (this.video.videoWidth == 0 || this.videoHeight == 0)) this.isAudioOnly = true; } // If the first frame hasn't loaded, kick off a throbber fade-in. 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 // and we'll figure out the exact state then.) this.bufferBar.setAttribute("max", 100); if (this.video.networkState == this.video.NETWORK_LOADED) 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() { // Don't fade controls for <audio> elements. var enabled = !this.isAudioOnly; // Allow tests to explicitly suppress the fading of controls. 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; }, handleEvent : function (aEvent) { this.log("Got media event ----> " + aEvent.type); // If the binding is detached (or has been replaced by a // newer instance of the binding), nuke our event-listeners. @@ -258,16 +274,17 @@ this.startFadeIn(this.controlFader); } break; case "loadeddata": this.firstFrameShown = true; break; case "loadstart": this.maxCurrentTimeSeen = 0; + this.statusIcon.setAttribute("type", "throbber"); this.isAudioOnly = (this.video instanceof HTMLAudioElement); break; case "durationchange": var duration = Math.round(this.video.duration * 1000); // in ms this.durationChange(duration); break; case "progress": var loaded = aEvent.loaded; @@ -292,45 +309,53 @@ this.showPosition(currentTime, duration); break; case "emptied": this.bufferBar.value = 0; 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!"); } }, terminateEventListeners : function () { for each (var event in this.videoEvents) this.video.removeEventListener(event, this, false); if (this.controlFader.timer) 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 ---"); }, durationChange : function (duration) { if (isNaN(duration)) duration = this.maxCurrentTimeSeen; this.log("Duration is " + duration + "ms"); @@ -398,22 +423,22 @@ // controls, let them fade-out so the controls don't get stuck on. if (!this.firstFrameShown && !isMouseOver && !(this.video.autoplay && this.video.mozAutoplayEnabled)) return; 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) { // If the fader specifies a start delay, don't immediately fade in... // Unless there's already a fade underway, in which case we want to be // able to immediately reverse it (eg, a seeking event right after seeked). if (fadeIn && fader.START_DELAY && !immediate && !fader.timer) { function delayedFadeStart(self, fader) { @@ -538,17 +563,18 @@ <body> <![CDATA[ var video = this.parentNode; this.Utils.video = video; this.Utils.videocontrols = this; 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"); this.Utils.progressBar = document.getAnonymousElementByAttribute(this, "class", "progressBar"); this.Utils.bufferBar = document.getAnonymousElementByAttribute(this, "class", "bufferBar"); this.Utils.scrubber = document.getAnonymousElementByAttribute(this, "class", "scrubber"); // Get the width of the scrubber thumb.
--- a/toolkit/themes/pinstripe/global/jar.mn +++ b/toolkit/themes/pinstripe/global/jar.mn @@ -174,16 +174,17 @@ classic.jar: + skin/classic/global/notification/info-bar-background.png (notification/info-bar-background.png) + skin/classic/global/notification/warning-bar-background.png (notification/warning-bar-background.png) + skin/classic/global/media/videocontrols.css (media/videocontrols.css) + skin/classic/global/media/pauseButton.png (media/pauseButton.png) + skin/classic/global/media/playButton.png (media/playButton.png) + 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) + skin/classic/global/menu/menu-arrow.gif (menu/menu-arrow.gif) + skin/classic/global/menu/menu-arrow-dis-rtl.gif (menu/menu-arrow-dis-rtl.gif) + skin/classic/global/menu/menu-arrow-hov-rtl.gif (menu/menu-arrow-hov-rtl.gif) + skin/classic/global/menu/menu-arrow-rtl.gif (menu/menu-arrow-rtl.gif) + skin/classic/global/menu/menu-check-dis.gif (menu/menu-check-dis.gif)
new file mode 100644 index 0000000000000000000000000000000000000000..58e37283a73eff086420d0969544fa8bc5dd7924 GIT binary patch literal 433 zc$@*T0Z#sjP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ0004aNkl<ZSi`m0 zQLcj^5Cu@0v;<A+0!(b${V%}o&SEndKon-?`f)#AV&H`G^n&@$v!UF4I-jRcPk);{ z%d)Ui8iU5}X|67wD?D)b8GSxcCLebJ$kEvGTq7Aw(B_zscaBnm9F19;Yc<>qE!pQJ z2}%Jv!-RC}gG1$^1SJHuVAc#RE0mxFpjOPbLT7uZx~D4PV75K9=Hc@Kqd1rs8B9EY zm7;_jIL6rgJ)}YjH}DQq0*O$<4ZOn~fut*CwU|HX<lmKp;^dDxnz!~sL!-8pk%Ew@ z<Y&@=5UAar(SkIn;s!>50*VWAoTA4CIRVIC1>(H)s^2~>NQz-MPgK(re~`H#6sEa( zqM9BXbqE5Ms}51}5Ev``AQw?;OrfBuP>|XQ>Qe~_iBX}#F=zr~B&aDIgL*{M12xay z(3Oa~>4BQ(v*jq=)bv2jvwD<nZhC;`nH;4{7gl39-hwZz9tU&X^Y>7=(i`$?wu`Rx bigWz{uoo^%o)rPO00000NkvXXu0mjfb>P7_
--- a/toolkit/themes/pinstripe/global/media/videocontrols.css +++ b/toolkit/themes/pinstripe/global/media/videocontrols.css @@ -75,18 +75,25 @@ /* Override the default thumb appearance with a custom image. */ -moz-appearance: none; background: url(chrome://global/skin/media/scrubberThumb.png) no-repeat center; border: none; min-width: 11px; 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; +.statusIcon { + margin-bottom: 28px; /* same height as .controlBar, to keep icon centered above it */ + width: 36px; height: 36px; - width: 36px; - margin-bottom: 28px; /* same height as .controlBar, to keep throbber centered above it */ +} + +.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; +}
--- a/toolkit/themes/winstripe/global/jar.mn +++ b/toolkit/themes/winstripe/global/jar.mn @@ -148,16 +148,17 @@ classic.jar: skin/classic/global/icons/wrap.png (icons/wrap.png) skin/classic/global/media/videocontrols.css (media/videocontrols.css) skin/classic/global/media/pauseButton.png (media/pauseButton.png) skin/classic/global/media/playButton.png (media/playButton.png) 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/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) skin/classic/global/splitter/grip-hrz-after.gif (splitter/grip-hrz-after.gif) skin/classic/global/splitter/grip-hrz-before.gif (splitter/grip-hrz-before.gif) skin/classic/global/splitter/grip-vrt-after.gif (splitter/grip-vrt-after.gif) skin/classic/global/splitter/grip-vrt-before.gif (splitter/grip-vrt-before.gif) skin/classic/global/toolbar/chevron.gif (toolbar/chevron.gif) @@ -321,16 +322,17 @@ classic.jar: skin/classic/aero/global/icons/wrap.png (icons/wrap-aero.png) skin/classic/aero/global/media/videocontrols.css (media/videocontrols.css) skin/classic/aero/global/media/pauseButton.png (media/pauseButton.png) skin/classic/aero/global/media/playButton.png (media/playButton.png) skin/classic/aero/global/media/muteButton.png (media/muteButton.png) 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) skin/classic/aero/global/splitter/grip-hrz-after.gif (splitter/grip-hrz-after.gif) skin/classic/aero/global/splitter/grip-hrz-before.gif (splitter/grip-hrz-before.gif) skin/classic/aero/global/splitter/grip-vrt-after.gif (splitter/grip-vrt-after.gif) skin/classic/aero/global/splitter/grip-vrt-before.gif (splitter/grip-vrt-before.gif) skin/classic/aero/global/toolbar/chevron.gif (toolbar/chevron.gif)
new file mode 100644 index 0000000000000000000000000000000000000000..58e37283a73eff086420d0969544fa8bc5dd7924 GIT binary patch literal 433 zc$@*T0Z#sjP)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ0004aNkl<ZSi`m0 zQLcj^5Cu@0v;<A+0!(b${V%}o&SEndKon-?`f)#AV&H`G^n&@$v!UF4I-jRcPk);{ z%d)Ui8iU5}X|67wD?D)b8GSxcCLebJ$kEvGTq7Aw(B_zscaBnm9F19;Yc<>qE!pQJ z2}%Jv!-RC}gG1$^1SJHuVAc#RE0mxFpjOPbLT7uZx~D4PV75K9=Hc@Kqd1rs8B9EY zm7;_jIL6rgJ)}YjH}DQq0*O$<4ZOn~fut*CwU|HX<lmKp;^dDxnz!~sL!-8pk%Ew@ z<Y&@=5UAar(SkIn;s!>50*VWAoTA4CIRVIC1>(H)s^2~>NQz-MPgK(re~`H#6sEa( zqM9BXbqE5Ms}51}5Ev``AQw?;OrfBuP>|XQ>Qe~_iBX}#F=zr~B&aDIgL*{M12xay z(3Oa~>4BQ(v*jq=)bv2jvwD<nZhC;`nH;4{7gl39-hwZz9tU&X^Y>7=(i`$?wu`Rx bigWz{uoo^%o)rPO00000NkvXXu0mjfb>P7_
--- a/toolkit/themes/winstripe/global/media/videocontrols.css +++ b/toolkit/themes/winstripe/global/media/videocontrols.css @@ -82,18 +82,25 @@ /* Override the default thumb appearance with a custom image. */ -moz-appearance: none; background: url(chrome://global/skin/media/scrubberThumb.png) no-repeat center; border: none; min-width: 11px; 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; +.statusIcon { + margin-bottom: 28px; /* same height as .controlBar, to keep icon centered above it */ + width: 36px; height: 36px; - width: 36px; - margin-bottom: 28px; /* same height as .controlBar, to keep throbber centered above it */ +} + +.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; +}