зеркало из https://github.com/mozilla/pjs.git
Bug 475318 - video controls should display numeric position and duration. r=enn, ui-r=boriss
This commit is contained in:
Родитель
a7ef654ea9
Коммит
c226a39601
|
@ -10,6 +10,9 @@
|
|||
<body>
|
||||
<p id="display"></p>
|
||||
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
|
||||
<div id="content">
|
||||
<video width="320" height="240" id="video" src="video.ogg" controls mozNoDynamicControls></video>
|
||||
</div>
|
||||
|
@ -46,9 +49,9 @@ const playButtonWidth = 28;
|
|||
const playButtonHeight = 28;
|
||||
const muteButtonWidth = 33;
|
||||
const muteButtonHeight = 28;
|
||||
const scrubberWidth = videoWidth - playButtonWidth - muteButtonWidth;
|
||||
const durationWidth = 34;
|
||||
const scrubberWidth = videoWidth - playButtonWidth - muteButtonWidth - durationWidth;
|
||||
const scrubberHeight = 28;
|
||||
const thumbWidth = 11;
|
||||
|
||||
// Play button is on the bottom-left
|
||||
const playButtonCenterX = 0 + Math.round(playButtonWidth / 2);
|
||||
|
@ -176,7 +179,7 @@ function runTest(event) {
|
|||
// Bug 477434 -- sometimes we get 0.098999 here instead of 0!
|
||||
// is(video.currentTime, 0.0, "checking playback position");
|
||||
|
||||
var beginDragX = scrubberOffsetX + (thumbWidth / 2);
|
||||
var beginDragX = scrubberOffsetX;
|
||||
var endDragX = scrubberOffsetX + (scrubberWidth / 2);
|
||||
synthesizeMouse(video, beginDragX, scrubberCenterY, { type: "mousedown", button: 0 });
|
||||
synthesizeMouse(video, endDragX, scrubberCenterY, { type: "mousemove", button: 0 });
|
||||
|
|
|
@ -3,3 +3,7 @@
|
|||
.scrubber {
|
||||
-moz-binding: url("chrome://global/content/bindings/videocontrols.xml#suppressChangeEvent");
|
||||
}
|
||||
|
||||
.scrubber .scale-thumb {
|
||||
-moz-binding: url("chrome://global/content/bindings/videocontrols.xml#timeThumb");
|
||||
}
|
||||
|
|
|
@ -6,9 +6,82 @@
|
|||
xmlns:xbl="http://www.mozilla.org/xbl"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
|
||||
<binding id="timeThumb"
|
||||
extends="chrome://global/content/bindings/scale.xml#scalethumb">
|
||||
<xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<xbl:children/>
|
||||
<hbox class="timeThumb" xbl:inherits="showhours">
|
||||
<label class="timeLabel"/>
|
||||
</hbox>
|
||||
</xbl:content>
|
||||
<implementation>
|
||||
|
||||
<field name="timeLabel">null</field>
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
this.timeLabel = document.getAnonymousElementByAttribute(this, "class", "timeLabel");
|
||||
this.timeLabel.setAttribute("value", "0:00");
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
<property name="showHours">
|
||||
<getter>
|
||||
<![CDATA[
|
||||
return this.getAttribute("showhours") == "true";
|
||||
]]>
|
||||
</getter>
|
||||
<setter>
|
||||
<![CDATA[
|
||||
this.setAttribute("showhours", val);
|
||||
// If the duration becomes known while we're still showing the value
|
||||
// for time=0, immediately update the value to show or hide the hours.
|
||||
// It's less intrusive to do it now than when the user clicks play and
|
||||
// is looking right next to the thumb.
|
||||
var displayedTime = this.timeLabel.getAttribute("value");
|
||||
if (val && displayedTime == "0:00")
|
||||
this.timeLabel.setAttribute("value", "0:00:00");
|
||||
else if (!val && displayedTime == "0:00:00")
|
||||
this.timeLabel.setAttribute("value", "0:00");
|
||||
]]>
|
||||
</setter>
|
||||
</property>
|
||||
|
||||
<method name="setTime">
|
||||
<parameter name="time"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
var timeString;
|
||||
var hours = Math.floor(time / 3600000);
|
||||
var mins = Math.floor(time % 3600000 / 60000);
|
||||
var secs = Math.floor(time % 60000 / 1000);
|
||||
if (secs < 10)
|
||||
secs = "0" + secs;
|
||||
if (hours || this.showHours) {
|
||||
if (mins < 10)
|
||||
mins = "0" + mins;
|
||||
timeString = hours + ":" + mins + ":" + secs;
|
||||
} else {
|
||||
timeString = mins + ":" + secs;
|
||||
}
|
||||
|
||||
this.timeLabel.setAttribute("value", timeString);
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
<binding id="suppressChangeEvent"
|
||||
extends="chrome://global/content/bindings/scale.xml#scale">
|
||||
<implementation>
|
||||
|
||||
<field name="thumb">null</field>
|
||||
<constructor>
|
||||
<![CDATA[
|
||||
this.thumb = document.getAnonymousElementByAttribute(this, "class", "scale-thumb");
|
||||
]]>
|
||||
</constructor>
|
||||
|
||||
<method name="valueChanged">
|
||||
<parameter name="which"/>
|
||||
<parameter name="newValue"/>
|
||||
|
@ -20,6 +93,9 @@
|
|||
// just calls the videocontrol's seekToPosition() method directly.
|
||||
switch (which) {
|
||||
case "curpos":
|
||||
// Update the time shown in the thumb.
|
||||
this.thumb.setTime(newValue);
|
||||
|
||||
// The value of userChanged is true when changing the position with the mouse,
|
||||
// but not when pressing an arrow key. However, the base binding sets
|
||||
// ._userChanged in its keypress handlers, so we just need to check both.
|
||||
|
@ -66,6 +142,9 @@
|
|||
<progressmeter class="progressBar" max="10000"/>
|
||||
<scale class="scrubber" movetoclick="true"/>
|
||||
</stack>
|
||||
<vbox class="durationBox">
|
||||
<label class="durationLabel"/>
|
||||
</vbox>
|
||||
<button class="muteButton" oncommand="document.getBindingParent(this).Utils.toggleMute();"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
@ -131,11 +210,11 @@
|
|||
videocontrols : null,
|
||||
playButton : null,
|
||||
muteButton : null,
|
||||
|
||||
durationLabel : null,
|
||||
scrubberThumb : null,
|
||||
scrubber : null,
|
||||
progressBar : null,
|
||||
bufferBar : null,
|
||||
thumbWidth : 0,
|
||||
|
||||
randomID : 0,
|
||||
videoEvents : ["play", "pause", "ended", "volumechange", "loadeddata",
|
||||
|
@ -359,6 +438,25 @@
|
|||
duration = this.maxCurrentTimeSeen;
|
||||
this.log("Duration is " + duration + "ms");
|
||||
|
||||
// Format the duration as "h:mm:ss" or "m:ss"
|
||||
var hours = Math.floor(duration / 3600000);
|
||||
var mins = Math.floor(duration % 3600000 / 60000);
|
||||
var secs = Math.floor(duration % 60000 / 1000);
|
||||
var timeString;
|
||||
if (secs < 10)
|
||||
secs = "0" + secs;
|
||||
if (hours) {
|
||||
if (mins < 10)
|
||||
mins = "0" + mins;
|
||||
timeString = hours + ":" + mins + ":" + secs;
|
||||
} else {
|
||||
timeString = mins + ":" + secs;
|
||||
}
|
||||
this.durationLabel.setAttribute("value", timeString);
|
||||
|
||||
// If the duration is over an hour, thumb should show h:mm:ss instead of mm:ss
|
||||
this.scrubberThumb.showHours = (duration >= 3600000);
|
||||
|
||||
this.scrubber.max = duration;
|
||||
// XXX Can't set increment here, due to bug 473103. Also, doing so causes
|
||||
// snapping when dragging with the mouse, so we can't just set a value for
|
||||
|
@ -388,18 +486,10 @@
|
|||
this.log("time update @ " + currentTime + "ms of " + duration + "ms");
|
||||
this.scrubber.value = currentTime;
|
||||
|
||||
// Extend the progressBar so it goes to the right-edge of the
|
||||
// scrubber thumb. This is a bit tricky, due to how the thumb is
|
||||
// positioned... It's flush-left at the minimum position, but
|
||||
// flush-right at the maximum position (so that the full thumb is
|
||||
// always visible in the <scale>'s box).
|
||||
// Extend the progressBar to the middle of the scrubber thumb.
|
||||
var percent = currentTime / duration;
|
||||
var leftEdge = Math.floor(percent * (this.scrubber.clientWidth - this.thumbWidth));
|
||||
var rightEdge = leftEdge + this.thumbWidth;
|
||||
var adjPercent = rightEdge / this.scrubber.clientWidth;
|
||||
|
||||
// The progressBar has max=10000
|
||||
this.progressBar.value = Math.round(adjPercent * 10000);
|
||||
this.progressBar.value = Math.round(percent * 10000);
|
||||
},
|
||||
|
||||
onMouseInOut : function (event) {
|
||||
|
@ -565,18 +655,14 @@
|
|||
|
||||
this.Utils.controlFader.element = document.getAnonymousElementByAttribute(this, "class", "controlBar");
|
||||
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.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.
|
||||
var thumb = document.getAnonymousElementByAttribute(this.Utils.scrubber, "class", "scale-thumb");
|
||||
if (thumb)
|
||||
this.Utils.thumbWidth = thumb.clientWidth;
|
||||
this.Utils.scrubberThumb = document.getAnonymousElementByAttribute(this.Utils.scrubber, "class", "scale-thumb");
|
||||
this.Utils.durationLabel = document.getAnonymousElementByAttribute(this, "class", "durationLabel");
|
||||
|
||||
this.Utils.setupInitialState();
|
||||
|
||||
|
|
|
@ -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/scrubberThumbWide.png (media/scrubberThumbWide.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)
|
||||
|
|
Двоичные данные
toolkit/themes/pinstripe/global/media/scrubberThumb.png
Двоичные данные
toolkit/themes/pinstripe/global/media/scrubberThumb.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 167 B После Ширина: | Высота: | Размер: 312 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 389 B |
|
@ -13,6 +13,8 @@
|
|||
padding: 0px;
|
||||
min-height: 28px;
|
||||
min-width: 28px;
|
||||
margin-right: -22px; /* 1/2 of scrubber thumb width, for overhang. */
|
||||
position: relative; /* Trick to work around negative margin interfering with clicking on the button. */
|
||||
}
|
||||
.playButton[paused="true"] {
|
||||
background: url(chrome://global/skin/media/playButton.png) no-repeat center;
|
||||
|
@ -31,17 +33,30 @@
|
|||
background: url(chrome://global/skin/media/unmuteButton.png) no-repeat center;
|
||||
}
|
||||
|
||||
.durationBox {
|
||||
-moz-box-pack: center;
|
||||
}
|
||||
|
||||
.durationLabel {
|
||||
margin-left: -22px; /* 1/2 of scrubber thumb width, for overhang. */
|
||||
padding-left: 8px; /* don't bump into the scrubber bar */
|
||||
padding-top: 2px; /* center vertically with scrubber bar */
|
||||
color: rgba(255,255,255,0.75);
|
||||
font: 11px sans-serif;
|
||||
}
|
||||
|
||||
.backgroundBar {
|
||||
/* make bar 8px tall (control height = 28, minus 2 * 10 margin) */
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
/* margin top/bottom: make bar 8px tall (control height = 28, minus 2 * 10 margin) */
|
||||
/* margin left/right: 1/2 of scrubber thumb width, for overhang. */
|
||||
margin: 10px 22px 10px 22px;
|
||||
background-color: rgba(255,255,255,0.5);
|
||||
-moz-border-radius: 4px 4px;
|
||||
}
|
||||
|
||||
.bufferBar, .progressBar {
|
||||
/* make bar 8px tall (control height = 28, minus 2 * 10 margin) */
|
||||
margin: 10px 0px 10px 0px;
|
||||
/* margin top/bottom: make bar 8px tall (control height = 28, minus 2 * 10 margin) */
|
||||
/* margin left/right: 1/2 of scrubber thumb width, for overhang. */
|
||||
margin: 10px 22px 10px 22px;
|
||||
-moz-appearance: none;
|
||||
min-width: 0px;
|
||||
}
|
||||
|
@ -59,7 +74,7 @@
|
|||
|
||||
.progressBar .progress-bar {
|
||||
background-color: white;
|
||||
-moz-border-radius: 4px 4px;
|
||||
-moz-border-radius: 4px 0px 0px 4px;
|
||||
}
|
||||
|
||||
/* .scale-slider is an element inside the <scale> implementation. */
|
||||
|
@ -74,10 +89,26 @@
|
|||
.scale-thumb {
|
||||
/* Override the default thumb appearance with a custom image. */
|
||||
-moz-appearance: none;
|
||||
background: url(chrome://global/skin/media/scrubberThumb.png) no-repeat center;
|
||||
background: transparent;
|
||||
border: none;
|
||||
min-width: 11px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.timeThumb {
|
||||
background: url(chrome://global/skin/media/scrubberThumb.png) no-repeat center;
|
||||
min-width: 44px;
|
||||
min-height: 22px;
|
||||
margin-top: -14px;
|
||||
-moz-box-pack: center;
|
||||
}
|
||||
|
||||
.timeThumb[showhours="true"] {
|
||||
background: url(chrome://global/skin/media/scrubberThumbWide.png) no-repeat center;
|
||||
}
|
||||
|
||||
.timeLabel {
|
||||
color: rgba(255,255,255,0.75);
|
||||
font: 10px sans-serif;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.statusOverlay {
|
||||
|
|
|
@ -151,6 +151,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/scrubberThumbWide.png (media/scrubberThumbWide.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)
|
||||
|
@ -324,6 +325,7 @@ classic.jar:
|
|||
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/scrubberThumbWide.png (media/scrubberThumbWide.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)
|
||||
|
|
Двоичные данные
toolkit/themes/winstripe/global/media/scrubberThumb.png
Двоичные данные
toolkit/themes/winstripe/global/media/scrubberThumb.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 167 B После Ширина: | Высота: | Размер: 312 B |
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 389 B |
|
@ -14,6 +14,8 @@
|
|||
min-height: 28px;
|
||||
min-width: 28px;
|
||||
border: none;
|
||||
margin-right: -22px; /* 1/2 of scrubber thumb width, for overhang. */
|
||||
position: relative; /* Trick to work around negative margin interfering with clicking on the button. */
|
||||
}
|
||||
.playButton[paused="true"] {
|
||||
background: url(chrome://global/skin/media/playButton.png) no-repeat center;
|
||||
|
@ -33,17 +35,30 @@
|
|||
background: url(chrome://global/skin/media/unmuteButton.png) no-repeat center;
|
||||
}
|
||||
|
||||
.durationBox {
|
||||
-moz-box-pack: center;
|
||||
}
|
||||
|
||||
.durationLabel {
|
||||
margin-left: -22px; /* 1/2 of scrubber thumb width, for overhang. */
|
||||
padding-left: 8px; /* don't bump into the scrubber bar */
|
||||
padding-top: 0px; /* center vertically with scrubber bar */
|
||||
color: rgba(255,255,255,0.75);
|
||||
font: 11px sans-serif;
|
||||
}
|
||||
|
||||
.backgroundBar {
|
||||
/* make bar 8px tall (control height = 28, minus 2 * 10 margin) */
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
/* margin top/bottom: make bar 8px tall (control height = 28, minus 2 * 10 margin) */
|
||||
/* margin left/right: 1/2 of scrubber thumb width, for overhang. */
|
||||
margin: 10px 22px 10px 22px;
|
||||
background-color: rgba(255,255,255,0.5);
|
||||
-moz-border-radius: 4px 4px;
|
||||
}
|
||||
|
||||
.bufferBar, .progressBar {
|
||||
/* make bar 8px tall (control height = 28, minus 2 * 10 margin) */
|
||||
margin: 10px 0px 10px 0px;
|
||||
/* margin top/bottom: make bar 8px tall (control height = 28, minus 2 * 10 margin) */
|
||||
/* margin left/right: 1/2 of scrubber thumb width, for overhang. */
|
||||
margin: 10px 22px 10px 22px;
|
||||
-moz-appearance: none;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
|
@ -65,7 +80,7 @@
|
|||
|
||||
.progressBar .progress-bar {
|
||||
background-color: white;
|
||||
-moz-border-radius: 4px 4px;
|
||||
-moz-border-radius: 4px 0px 0px 4px;
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
||||
|
@ -81,10 +96,26 @@
|
|||
.scale-thumb {
|
||||
/* Override the default thumb appearance with a custom image. */
|
||||
-moz-appearance: none;
|
||||
background: url(chrome://global/skin/media/scrubberThumb.png) no-repeat center;
|
||||
background: transparent;
|
||||
border: none;
|
||||
min-width: 11px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.timeThumb {
|
||||
background: url(chrome://global/skin/media/scrubberThumb.png) no-repeat center;
|
||||
min-width: 44px;
|
||||
min-height: 22px;
|
||||
margin-top: -14px;
|
||||
-moz-box-pack: center;
|
||||
}
|
||||
|
||||
.timeThumb[showhours="true"] {
|
||||
background: url(chrome://global/skin/media/scrubberThumbWide.png) no-repeat center;
|
||||
}
|
||||
|
||||
.timeLabel {
|
||||
color: rgba(255,255,255,0.75);
|
||||
font: 10px sans-serif;
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
.statusOverlay {
|
||||
|
|
Загрузка…
Ссылка в новой задаче