From a19c271e8f65e572d1cd974efc6a6c2d231a8dd5 Mon Sep 17 00:00:00 2001 From: rolux Date: Thu, 12 May 2011 22:02:22 +0200 Subject: [PATCH] some improvements to Ox.VideoPlayer --- demos/video/js/video.js | 18 +- source/Ox.UI/css/Ox.UI.css | 1 + source/Ox.UI/js/Core/Ox.Focus.js | 4 + source/Ox.UI/js/Form/Ox.Input.js | 10 +- source/Ox.UI/js/Video/Ox.VideoPlayer.js | 227 +++++++++++++++++++----- source/Ox.UI/themes/classic/_index.html | 2 +- 6 files changed, 213 insertions(+), 49 deletions(-) diff --git a/demos/video/js/video.js b/demos/video/js/video.js index 915c0c4b..e8580fc5 100644 --- a/demos/video/js/video.js +++ b/demos/video/js/video.js @@ -9,9 +9,23 @@ Ox.load('UI', { padding: '16px' }); Ox.VideoPlayer({ - height: 288, + height: 96 * 256/180, + timeline: timeline, + title: 'Brick', + url: url, + width: 256 + }).appendTo(Ox.UI.$body); + /* + var id = '0133093'; + var url = 'http://next.0xdb.org/' + id + '/96p.webm?' + Ox.random(1000000); + var timeline = 'http://next.0xdb.org/' + id + '/timeline.16.png'; + Ox.VideoPlayer({ + height: 96 * 256/230, timeline: timeline, url: url, - width: 540 + width: 256 + }).css({ + left: '300px' }).appendTo(Ox.UI.$body); + */ }); diff --git a/source/Ox.UI/css/Ox.UI.css b/source/Ox.UI/css/Ox.UI.css index 9182d11c..fa080f0c 100644 --- a/source/Ox.UI/css/Ox.UI.css +++ b/source/Ox.UI/css/Ox.UI.css @@ -1647,6 +1647,7 @@ Video margin-left: 4px; } + .OxVideoPlayer > .OxBar .OxInputGroup { //width: 98px; } diff --git a/source/Ox.UI/js/Core/Ox.Focus.js b/source/Ox.UI/js/Core/Ox.Focus.js index 5f5e0e39..5103387e 100644 --- a/source/Ox.UI/js/Core/Ox.Focus.js +++ b/source/Ox.UI/js/Core/Ox.Focus.js @@ -13,6 +13,10 @@ Ox.Focus = function() { _print: function() { Ox.print(stack); }, + _reset: function() { + $('.OxFocus').removeClass('OxFocus'); + stack = []; + }, blur: function(id) { var index = stack.indexOf(id); if (index > -1 && index == stack.length - 1) { diff --git a/source/Ox.UI/js/Form/Ox.Input.js b/source/Ox.UI/js/Form/Ox.Input.js index 36f276fc..efc9f891 100644 --- a/source/Ox.UI/js/Form/Ox.Input.js +++ b/source/Ox.UI/js/Form/Ox.Input.js @@ -729,12 +729,18 @@ Ox.Input = function(options, self) { } }; - that.focusInput = function() { + that.focusInput = function(select) { + select = Ox.isUndefined(select) ? true : select; self.$input.focus(); - cursor(0, self.$input.val().length); + if (select) { + cursor(0, self.$input.val().length); + } else { + cursor(self.$input.val().length); + } return that; }; + // fixme: deprecate, options are enough that.value = function() { return self.$input.hasClass('OxPlaceholder') ? '' : self.$input.val(); }; diff --git a/source/Ox.UI/js/Video/Ox.VideoPlayer.js b/source/Ox.UI/js/Video/Ox.VideoPlayer.js index 3d29aba4..cf7976cc 100644 --- a/source/Ox.UI/js/Video/Ox.VideoPlayer.js +++ b/source/Ox.UI/js/Video/Ox.VideoPlayer.js @@ -11,6 +11,7 @@ Ox.VideoPlayer = function(options, self) { }) .options(options || {}) .css({ + position: 'absolute', width: self.options.width + 'px', height: self.options.height + 'px' //background: 'red' @@ -27,9 +28,7 @@ Ox.VideoPlayer = function(options, self) { self.barHeight = 16; self.outerBarWidth = self.options.width - 96; self.innerBarWidth = self.outerBarWidth - self.barHeight; - self.markerSize = 12; - self.markerBorderSize = 2; - self.markerOffset = -self.innerBarWidth - self.markerSize / 2; + self.markerOffset = -self.innerBarWidth - 8; self.$video = Ox.VideoElement({ height: self.options.height, @@ -44,10 +43,12 @@ Ox.VideoPlayer = function(options, self) { loadedmetadata: loadedmetadata, paused: function(data) { // called when playback ends + /* self.$playButton.toggleTitle(); - self.$positionMarker.css({ - borderColor: 'rgb(192, 192, 192)' + self.$positionMarkerRing.css({ + borderColor: 'rgba(255, 255, 255, 0.5)' }); + */ }, playing: function(data) { setPosition(data.position); @@ -60,7 +61,7 @@ Ox.VideoPlayer = function(options, self) { if (self.buffered[i][0] > self.buffered[i][1]) { self.buffered[i][0] = 0; } - Ox.print(i, self.buffered[i][0], self.buffered[i][1]) + //Ox.print(i, self.buffered[i][0], self.buffered[i][1]) } self.$buffered.attr({ src: getBufferedImageURL() @@ -72,14 +73,33 @@ Ox.VideoPlayer = function(options, self) { }) .appendTo(that); + if (self.options.title) { + self.$titlebar = $('
') + .css({ + position: 'absolute', + width: self.options.width + 'px', + height: '15px', + paddingTop: '1px', + textAlign: 'center' + }) + .css({ + backgroundImage: '-moz-linear-gradient(top, rgba(64, 64, 64, 0.5), rgba(0, 0, 0, 0.5))' + }) + .css({ + backgroundImage: '-webkit-linear-gradient(top, rgba(64, 64, 64, 0.5), rgba(0, 0, 0, 0.5))' + }) + .html(self.options.title) + .appendTo(that.$element); + } + self.$loadingIcon = $('') .attr({ - src: Ox.UI.getImagePath('symbolLoadingAnimated.svg') + src: Ox.UI.getImagePath('symbolLoadingAnimated.svg').replace('/classic/', '/modern/') }) .css({ position: 'absolute', - left: self.options.width / 2 - 16 + 'px', - top: self.options.height / 2 - 16 + 'px', + left: parseInt(self.options.width / 2) - 16 + 'px', // fixme + top: parseInt(self.options.height / 2) - 16 + 'px', width: '32px', height: '32px' }) @@ -93,6 +113,12 @@ Ox.VideoPlayer = function(options, self) { width: self.options.width + 'px', marginTop: self.options.height - self.barHeight + 'px', }) + .css({ + backgroundImage: '-moz-linear-gradient(top, rgba(64, 64, 64, 0.5), rgba(0, 0, 0, 0.5))' + }) + .css({ + backgroundImage: '-webkit-linear-gradient(top, rgba(64, 64, 64, 0.5), rgba(0, 0, 0, 0.5))' + }) .appendTo(that); self.$buttons = Ox.Element() @@ -150,9 +176,17 @@ Ox.VideoPlayer = function(options, self) { float: 'left', width: self.outerBarWidth + 'px', height: self.barHeight + 'px', - background: 'rgb(0, 0, 0)', + background: 'rgba(0, 0, 0, 0.75)', borderRadius: self.barHeight / 2 + 'px' }) + /* + .css({ + backgroundImage: '-moz-linear-gradient(top, rgba(0, 0, 0, 0.75), rgba(64, 64, 64, 0.75))' + }) + .css({ + backgroundImage: '-webkit-linear-gradient(top, rgba(0, 0, 0, 0.75), rgba(64, 64, 64, 0.75))' + }) + */ .appendTo(self.$controls); self.$innerBar = Ox.Element() @@ -187,21 +221,36 @@ Ox.VideoPlayer = function(options, self) { }) .appendTo(self.$innerBar.$element); - self.$positionMarker = Ox.Element() + self.$positionMarker = $('
') .css({ float: 'left', - width: self.markerSize - self.markerBorderSize * 2 + 'px', - height: self.markerSize - self.markerBorderSize * 2 + 'px', - marginTop: (self.barHeight - self.markerSize) / 2 + 'px', + width: '14px', + height: '14px', marginLeft: self.markerOffset + 'px', - border: self.markerBorderSize + 'px solid rgb(192, 192, 192)', - borderRadius: self.markerSize - self.markerBorderSize * 2 + 'px', - //background: 'rgba(0, 0, 0, 0.5)', - boxShadow: '0 0 ' + (self.barHeight - self.markerSize) / 2 + 'px black' + border: '1px solid rgba(0, 0, 0, 0.5)', + borderRadius: '8px' }) - .appendTo(self.$outerBar); + .append( + self.$positionMarkerRing = $('
') + .css({ + width: '10px', + height: '10px', + border: '2px solid rgba(255, 255, 255, 0.5)', + borderRadius: '7px', + }) + .append( + $('
') + .css({ + width: '8px', + height: '8px', + border: '1px solid rgba(0, 0, 0, 0.5)', + borderRadius: '5px', + }) + ) + ) + .appendTo(self.$outerBar.$element); - self.$interfaceBar = Ox.Element() + self.$trackInterface = Ox.Element() .css({ float: 'left', width: self.outerBarWidth + 'px', @@ -214,7 +263,7 @@ Ox.VideoPlayer = function(options, self) { animate: false }); - self.$position = Ox.Element() + self.$position = $('
') .css({ float: 'left', width: '44px', @@ -224,7 +273,81 @@ Ox.VideoPlayer = function(options, self) { textAlign: 'center' }) .html(Ox.formatDuration(self.options.position)) - .appendTo(self.$controls) + .bind({ + click: function() { + if (!self.$video.paused()) { + self.wasPlaying = true; + self.$video.pause(); + self.$playButton.toggleTitle(); + } + self.$position.hide(); + self.$positionInput + .options({ + value: Ox.formatDuration(self.options.position) + }) + .show() + .focusInput(false); + } + }) + .appendTo(self.$controls.$element) + + self.$positionInput = Ox.Input({ + value: Ox.formatDuration(self.options.position), + width: 48 + }) + .css({ + float: 'left', + background: 'rgba(0, 0, 0, 0)', + MozBoxShadow: '0 0 0', + WebkitBoxShadow: '0 0 0' + }) + .bindEvent({ + blur: submitPositionInput, + change: submitPositionInput, + //submit: submitPositionInput + }) + .hide() + .appendTo(self.$controls.$element); + + self.$positionInput.children('input').css({ + width: '42px', + height: '16px', + padding: '0 3px 0 3px', + border: '0px', + borderRadius: '8px', + fontSize: '9px', + color: 'rgb(255, 255, 255)' + }) + .css({ + background: '-moz-linear-gradient(top, rgba(0, 0, 0, 0.5), rgba(64, 64, 64, 0.5))' + }) + .css({ + background: '-webkit-linear-gradient(top, rgba(0, 0, 0, 0.5), rgba(64, 64, 64, 0.5))' + }); + + function submitPositionInput() { + self.$positionInput.hide(); + self.$position.html('').show(); + setPosition(parsePositionInput(self.$positionInput.options('value'))); + self.$video.position(self.options.position); + if (self.wasPlaying) { + self.$video.play(); + self.$playButton.toggleTitle(); + self.wasPlaying = false; + } + } + + function parsePositionInput(str) { + var position, + split = str.split(':').reverse(); + while (split.length > 3) { + split.pop(); + } + position = split.reduce(function(prev, curr, i) { + return prev + (parseFloat(curr) || 0) * Math.pow(60, i); + }, 0) + return Ox.limit(position, 0, self.duration); + } function getPosition(e) { // fixme: no offsetX in firefox??? @@ -235,7 +358,10 @@ Ox.VideoPlayer = function(options, self) { 0, self.duration ); } else { - Ox.print(e.offsetX) + /*Ox.print(e.offsetX, Ox.limit( + (e.offsetX - self.barHeight / 2) / self.innerBarWidth * self.duration, + 0, self.duration + ))*/ return Ox.limit( (e.offsetX - self.barHeight / 2) / self.innerBarWidth * self.duration, 0, self.duration @@ -274,11 +400,18 @@ Ox.VideoPlayer = function(options, self) { } function hideControls() { - self.controlsTimeout = setTimeout(function() { - self.$controls.animate({ - opacity: 0 - }, 250); - }, 1000); + Ox.print('!!!!!!', self.$positionInput.hasFocus()) + if (!self.$positionInput.hasFocus()) { + self.controlsTimeout = setTimeout(function() { + // fixme: use class + self.$titlebar.animate({ + opacity: 0 + }, 250); + self.$controls.animate({ + opacity: 0 + }, 250); + }, 1000); + } } function hideLoadingIcon() { @@ -289,9 +422,9 @@ Ox.VideoPlayer = function(options, self) { function loadedmetadata(data) { //self.$position.html(Ox.formatDuration(data.video.duration)) - Ox.print('!!!!', data.video.width, data.video.height, data.video.videoWidth, data.video.videoHeight) + //Ox.print('!!!!', data.video.width, data.video.height, data.video.videoWidth, data.video.videoHeight) self.duration = data.video.duration; - Ox.print('DURATION', Ox.formatDuration(self.duration)); + //Ox.print('DURATION', Ox.formatDuration(self.duration)); hideLoadingIcon(); that.gainFocus().bindEvent({ key_space: function() { @@ -299,38 +432,41 @@ Ox.VideoPlayer = function(options, self) { togglePlay(); } }); - self.$interfaceBar + self.$trackInterface .bind({ - mousedown: mousedownBar, - mouseleave: mouseleaveBar, - mousemove: mousemoveBar, + mousedown: mousedownTrack, + mouseleave: mouseleaveTrack, + mousemove: mousemoveTrack, }) .bindEvent({ - drag: dragBar, + drag: dragTrack, + dragpause: dragpauseTrack, + dragend: dragpauseTrack }); } - function dragBar(e) { + function dragTrack(e) { setPosition(getPosition(e)); if (self.dragTimeout) { clearTimeout(self.dragTimeout); self.dragTimeout = 0; } - self.dragTimeout = setTimeout(function() { - self.$video.position(self.options.position); - }, 1000); } - function mousedownBar(e) { + function dragpauseTrack(e) { + self.$video.position(self.options.position); + } + + function mousedownTrack(e) { setPosition(getPosition(e)); self.$video.position(self.options.position); } - function mouseleaveBar(e) { + function mouseleaveTrack(e) { self.$tooltip.hide(); } - function mousemoveBar(e) { + function mousemoveTrack(e) { self.$tooltip.options({ title: Ox.formatDuration(getPosition(e)) }).show(e.clientX, e.clientY); @@ -338,6 +474,9 @@ Ox.VideoPlayer = function(options, self) { function showControls() { clearTimeout(self.controlsTimeout); + self.$titlebar.animate({ + opacity: 1 + }, 250); self.$controls.animate({ opacity: 1 }, 250); @@ -363,8 +502,8 @@ Ox.VideoPlayer = function(options, self) { function togglePlay() { self.$video.togglePlay(); - self.$positionMarker.css({ - borderColor: self.$video.paused() ? 'rgb(192, 192, 192)' : 'rgb(255, 255, 255)' + self.$positionMarkerRing.css({ + borderColor: 'rgba(255, 255, 255, ' + (self.$video.paused() ? 0.5 : 1) + ')' }); } diff --git a/source/Ox.UI/themes/classic/_index.html b/source/Ox.UI/themes/classic/_index.html index 4a1ca8a5..5060b397 100644 --- a/source/Ox.UI/themes/classic/_index.html +++ b/source/Ox.UI/themes/classic/_index.html @@ -40,7 +40,7 @@ height: 256px; } - +