From 117c6bff62187f1ada2ba9a891ad2dcee8f44b93 Mon Sep 17 00:00:00 2001 From: rolux Date: Mon, 16 May 2011 20:05:29 +0200 Subject: [PATCH] revised controls (find, volume) --- demos/video/js/video.js | 11 +- source/Ox.UI/js/Form/Ox.Input.js | 5 + .../js/Video/Ox.SmallVideoTimelineImage.js | 4 +- source/Ox.UI/js/Video/Ox.VideoPlayer.js | 831 ++++++++++++------ 4 files changed, 553 insertions(+), 298 deletions(-) diff --git a/demos/video/js/video.js b/demos/video/js/video.js index e1bbbbd8..c8b2cb7d 100644 --- a/demos/video/js/video.js +++ b/demos/video/js/video.js @@ -32,17 +32,17 @@ Ox.load('UI', { videoSize = getVideoSize(), $videos = [ Ox.VideoPlayer({ - controls: ['play', 'mute', 'fullscreen', 'scale', 'timeline', 'position'], + controlsBottom: ['play', 'volume', 'scale', 'timeline', 'position'], + controlsTop: ['fullscreen', 'title', 'find'], enableFind: true, enableFullscreen: true, enableKeyboard: true, + enableVolume: true, focus: 'mouseenter', height: 192, - 'in': 3128.725, logoLink: 'http://next.0xdb.org/' + id, logoTitle: 'Watch on 0xdb', logo: 'png/logo.png', - out: 3130.725, paused: true, poster: poster, showIconOnLoad: true, @@ -51,7 +51,7 @@ Ox.load('UI', { timeline: function(i) { return 'png/timeline.16.' + i + '.png'; }, - title: 'Brick - Rian Johnson - 2005', + title: 'Brick - Rian Johnson - 2005', video: url + '?' + + Ox.random(1000000), width: 360 }) @@ -78,9 +78,8 @@ Ox.load('UI', { top: '16px' }), Ox.VideoPlayer({ - controls: ['play', 'playInToOut', 'mute', 'size', 'space', 'position'], + controlsBottom: ['play', 'playInToOut', 'mute', 'size', 'space', 'position'], externalControls: true, - find: 'brick', height: 192, 'in': 3128.725, out: 3130.725, diff --git a/source/Ox.UI/js/Form/Ox.Input.js b/source/Ox.UI/js/Form/Ox.Input.js index 696df97e..dcc56297 100644 --- a/source/Ox.UI/js/Form/Ox.Input.js +++ b/source/Ox.UI/js/Form/Ox.Input.js @@ -733,6 +733,11 @@ Ox.Input = function(options, self) { } }; + that.blurInput = function() { + self.$input.blur(); + return that; + }; + that.focusInput = function(select) { select = Ox.isUndefined(select) ? true : select; self.$input.focus(); diff --git a/source/Ox.UI/js/Video/Ox.SmallVideoTimelineImage.js b/source/Ox.UI/js/Video/Ox.SmallVideoTimelineImage.js index 06445a7d..4350b7e5 100644 --- a/source/Ox.UI/js/Video/Ox.SmallVideoTimelineImage.js +++ b/source/Ox.UI/js/Video/Ox.SmallVideoTimelineImage.js @@ -3,7 +3,7 @@ Ox.SmallVideoTimelineImage = function(options, self) { self = self || {}; var that = Ox.Element({}, self) .defaults({ - duration: 0, + duration: 1920, editing: false, getTimelineURL: null, 'in': 0, @@ -120,7 +120,7 @@ Ox.SmallVideoTimelineImage = function(options, self) { }); }); }); - } else if (image == 'selection') { + } else if (image == 'selection' && self.options.out > self.options['in']) { var left = Math.round( self.options['in'] * self.options.width / self.options.duration ), diff --git a/source/Ox.UI/js/Video/Ox.VideoPlayer.js b/source/Ox.UI/js/Video/Ox.VideoPlayer.js index 9835ac2d..0a3c0cf2 100644 --- a/source/Ox.UI/js/Video/Ox.VideoPlayer.js +++ b/source/Ox.UI/js/Video/Ox.VideoPlayer.js @@ -10,11 +10,11 @@ Ox.VideoPlayer Generic Video Player in In point (sec) out Out point (sec) text Text - controls <[s]> Controls, from left to right - Can be 'play', 'playInToOut', 'mute', 'volume', 'size', 'scale', - 'timeline', 'space', 'position', 'settings'. The 'space' control - is just empty space that separates left-aligned from right-aligned - controls + controls <[[s]]|[[][]]> Controls, first top, then bottom, from left to right + Can be 'fullscreen', 'scale', 'title', 'find', 'menu', + 'play', 'playInToOut', 'mute', 'volume', 'size', 'timeline', 'space', + 'position', 'settings'. The 'space' control is just empty space + that separates left-aligned from right-aligned controls. duration Duration (sec) enableFind If true, enable find enableFullscreen If true, enable fullscreen @@ -69,7 +69,8 @@ Ox.VideoPlayer = function(options, self) { var that = Ox.Element({}, self) .defaults({ annotations: [], - controls: [], + controlsBottom: [], + controlsTop: [], duration: 0, enableFind: false, enableFullscreen: false, @@ -139,7 +140,7 @@ Ox.VideoPlayer = function(options, self) { if (self.options.enableKeyboard) { that.bindEvent({ key_1: function() { - toggleScale(); + toggleScale(true); }, key_f: function() { // need timeout so the "f" doesn't appear in the input field @@ -151,6 +152,9 @@ Ox.VideoPlayer = function(options, self) { key_left: function() { setPosition(self.options.position - self.secondsPerFrame, true); }, + key_m: function() { + toggleMuted(true); + }, key_p: function() { playInToOut(); }, @@ -189,8 +193,9 @@ Ox.VideoPlayer = function(options, self) { } if ( - (!self.options.externalControls && self.options.controls.length) || - self.options.showIcon || self.options.title + (!self.options.externalControls && + (self.options.controlsTop.length || self.options.controlsBottom.length)) || + self.options.showIcon ) { that.bind({ mouseenter: function() { @@ -343,38 +348,15 @@ Ox.VideoPlayer = function(options, self) { .appendTo(self.$videoContainer); } - if (self.options.title) { - self.$title = $('
') - .addClass('OxInterface') - .css({ - position: 'absolute', - height: (self.barHeight - 1) + 'px', - paddingTop: '1px', - textAlign: 'center', - color: 'rgb(255, 255, 255)', - opacity: 0 - }) - .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); - } - if (self.options.enableFind) { self.$find = $('
') - .addClass('OxInterface') .css({ position: 'absolute', - right: '16px', - top: (self.options.title ? 32 : 16) + 'px', - width: '128px', - borderRadius: '8px', - opacity: 0 + right: 0, + top: self.options.controlsTop.length ? '16px' : 0, + borderBottomLeftRadius: '8px', + borderBottomRightRadius: '8px' }) .css({ backgroundImage: '-moz-linear-gradient(top, rgba(64, 64, 64, 0.5), rgba(0, 0, 0, 0.5))' @@ -382,8 +364,34 @@ Ox.VideoPlayer = function(options, self) { .css({ backgroundImage: '-webkit-linear-gradient(top, rgba(64, 64, 64, 0.5), rgba(0, 0, 0, 0.5))' }) + .hide() .appendTo(that.$element); + self.$playResultsButton = Ox.Button({ + style: 'symbol', + title: 'PlayInToOut', + tooltip: 'Play Results', + type: 'image' + }) + .css({float: 'left', opacity: 0.25}) + .bindEvent({ + click: function() { + + } + }) + .appendTo(self.$find); + + self.$results = $('
') + .css({ + float: 'left', + width: '24px', + paddingTop: '2px', + fontSize: '9px', + textAlign: 'center' + }) + .html('0') + .appendTo(self.$find); + self.$previousButton = Ox.Button({ style: 'symbol', title: 'arrowLeft', @@ -413,9 +421,7 @@ Ox.VideoPlayer = function(options, self) { .appendTo(self.$find); self.$findInput = Ox.Input({ - placeholder: 'Find', - value: self.options.find, - width: 86 + value: self.options.find }) .css({ float: 'left', @@ -449,16 +455,18 @@ Ox.VideoPlayer = function(options, self) { .css({ background: '-webkit-linear-gradient(top, rgba(0, 0, 0, 0.5), rgba(64, 64, 64, 0.5))' }); - + + ///* self.$clearButton = Ox.Button({ style: 'symbol', - title: 'close', + title: 'delete', tooltip: 'Clear', type: 'image' }) .css({float: 'left'}) .bindEvent({ click: function() { + self.$results.html('0'); self.$findInput .options({value: ''}) .focusInput(); @@ -466,249 +474,386 @@ Ox.VideoPlayer = function(options, self) { self.$timeline && self.$timeline.options({ results: self.results }); + //setTimeout(self.$findInput.focusInput, 10); } }) .appendTo(self.$find); + //*/ } - if (self.options.controls.length) { + ['top', 'bottom'].forEach(function(edge) { - self.$controls = Ox.Bar({ + var titlecase = Ox.toTitleCase(edge); + + if (self.options['controls' + titlecase].length) { + + self['$controls' + titlecase] = Ox.Bar({ size: self.barHeight }) - .addClass('OxInterface') + .addClass('OxControls OxInterface') .css({ position: 'absolute', - bottom: 0, opacity: self.options.externalControls ? 1 : 0 }) + .css(edge, 0) .appendTo(that.$element); - if (!self.options.externalControls) { - self.$controls.css({ + if (!self.options.externalControls) { + self['$controls' + titlecase].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))' + }); + } + + self.options['controls' + titlecase].forEach(function(control) { + + if (control == 'find') { + + self.$findButton = Ox.Button({ + style: 'symbol', + title: [ + {id: 'find', title: 'find'}, + {id: 'close', title: 'close'} + ], + tooltip: ['Find', 'Close'], + type: 'image' + }) + .css({float: 'left'}) + .bindEvent('click', toggleFind) + .appendTo(self['$controls' + titlecase]); + + } else if (control == 'fullscreen') { + + self.$fullscreenButton = Ox.Button({ + style: 'symbol', + title: [ + {id: 'grow', title: 'grow', selected: !self.options.fullscreen}, + {id: 'shrink', title: 'shrink', selected: self.options.fullscreen} + ], + tooltip: ['Enter Fullscreen', 'Exit Fullscreen'], + type: 'image' + }) + .css({float: 'left'}) + .bindEvent('click', function() { + toggleFullscreen(); + }) + .appendTo(self['$controls' + titlecase]); + + } else if (control == 'mute') { + + self.$muteButton = Ox.Button({ + style: 'symbol', + title: [ + {id: 'mute', title: 'mute', selected: !self.options.muted}, + {id: 'unmute', title: 'unmute', selected: self.options.muted} + ], + tooltip: ['Mute', 'Unmute'], + type: 'image' + }) + .css({float: 'left'}) + .bindEvent('click', function() { + toggleMuted(); + }) + .appendTo(self['$controls' + titlecase]); + + } else if (control == 'play') { + + self.$playButton = Ox.Button({ + style: 'symbol', + // FIXME: this is retarded, fix Ox.Button + title: [ + {id: 'play', title: 'play', selected: self.options.paused}, + {id: 'pause', title: 'pause', selected: !self.options.paused} + ], + tooltip: ['Play', 'Pause'], + type: 'image' + }) + .css({float: 'left'}) + .bindEvent('click', function() { + togglePaused(); + }) + .appendTo(self['$controls' + titlecase]); + + } else if (control == 'playInToOut') { + + self.$playInToOutButton = Ox.Button({ + style: 'symbol', + title: 'playInToOut', + tooltip: 'Play In to Out', + type: 'image' + }) + .css({float: 'left'}) + .bindEvent('click', playInToOut) + .appendTo(self['$controls' + titlecase]); + + } else if (control == 'position') { + + self.positionWidth = 48 + + !!self.options.showMilliseconds * 2 + + self.options.showMilliseconds * 6; + + self.$position = $('
') + .addClass('foo') + .css({ + float: 'left', + width: (self.positionWidth - 4) + 'px', + height: '12px', + padding: '2px', + fontSize: '9px', + textAlign: 'center', + color: 'rgb(255, 255, 255)' + }) + .html(formatPosition) + .bind({ + click: function() { + if (!self.options.paused) { + self.wasPlaying = true; + togglePaused(true); + } + self.$position.hide(); + self.$positionInput + .options({ + value: formatPosition() + }) + .show() + .focusInput(false); + } + }) + .appendTo(self['$controls' + titlecase].$element); + + self.$positionInput = Ox.Input({ + value: formatPosition(), + width: self.positionWidth + }) + .css({ + float: 'left', + background: 'rgba(0, 0, 0, 0)', + MozBoxShadow: '0 0 0', + WebkitBoxShadow: '0 0 0' + }) + .bindEvent({ + focus: function() { + self.inputHasFocus = true; + }, + blur: function() { + self.inputHasFocus = false; + submitPositionInput(); + } + }) + .hide() + .appendTo(self['$controls' + titlecase].$element); + + self.$positionInput.children('input').css({ + width: (self.positionWidth - 6) + 'px', + 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))' + }); + + } else if (control == 'scale') { + + self.$scaleButton = Ox.Button({ + style: 'symbol', + title: [ + {id: 'fill', title: 'fill', selected: !self.options.scaleToFill}, + {id: 'fit', title: 'fit', selected: self.options.scaleToFill} + ], + tooltip: ['Scale to Fill', 'Scale to Fit'], + type: 'image' + }) + .css({float: 'left'}) + .bindEvent('click', function() { + toggleScale(); + }) + .appendTo(self['$controls' + titlecase]); + + } else if (control == 'size') { + + self.$sizeButton = Ox.Button({ + style: 'symbol', + title: [ + {id: 'grow', title: 'grow', selected: !self.options.sizeIsLarge}, + {id: 'shrink', title: 'shrink', selected: self.options.sizeIsLarge} + ], + tooltip: ['Larger', 'Smaller'], + type: 'image' + }) + .css({float: 'left'}) + .bindEvent('click', toggleSize) + .appendTo(self['$controls' + titlecase]); + + } else if (control == 'space') { + + self['$space' + titlecase] = $('
') + .css({float: 'left'}) + .html(' ') // fixme: ?? + .appendTo(self['$controls' + titlecase].$element); + + } else if (control == 'timeline') { + + /* + if (self.options.showProgress) { + self.$progress = $('') + .attr({ + src: getProgressImageURL() + }) + .css({ + float: 'left', + height: self.barHeight + 'px', + }) + .appendTo(self.$timelineImages.$element); + } + */ + + if (self.options.duration) { + self.$timeline = getTimeline() + } else { + self.$timeline = Ox.Element() + .css({ + float: 'left' + }) + .html(' '); + } + self.$timeline.appendTo(self['$controls' + titlecase]); + + } else if (control == 'title') { + + self.$title = $('
') + .addClass('OxInterface') + .css({ + float: 'left', + paddingTop: '1px', + textAlign: 'center', + color: 'rgb(255, 255, 255)' + }) + .html(self.options.title) + .appendTo(self['$controls' + titlecase].$element); + + } else if (control == 'volume') { + + self.$volumeButton = Ox.Button({ + style: 'symbol', + title: 'mute', + tooltip: 'Volume', + type: 'image' + }) + .css({float: 'left'}) + .bindEvent('click', function() { + self.$volume.toggle(); + }) + .appendTo(self['$controls' + titlecase]); + + } + + }); + + } + + }); + + if (self.options.enableVolume) { + + self.$volume = $('
') + .css({ + position: 'absolute', + left: 0, + bottom: self.options.controlsBottom.length ? '16px' : 0, + height: '16px', + borderTopLeftRadius: '8px', + borderTopRightRadius: '8px' + }) + .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))' + }) + .hide() + .appendTo(that.$element); + + self.$muteButton = Ox.Button({ + style: 'symbol', + title: [ + {id: 'mute', title: 'mute', selected: !self.options.muted}, + {id: 'unmute', title: 'unmute', selected: self.options.muted} + ], + tooltip: ['Mute', 'Unmute'], + type: 'image' + }) + .css({float: 'left'}) + .bindEvent({ + click: function() { + toggleMuted(); + } + }) + .appendTo(self.$volume); + + self.$volumeInput = Ox.Range({ + max: 1, + min: 0, + step: 0.001, + value: self.options.muted ? 0 : self.options.volume + }) + .css({ + float: 'left' + }) + .bindEvent({ + change: setVolume + }) + .appendTo(self.$volume); + + self.$volumeInput.find('.OxTrack') + .css({ + //border: '1px solid rgba(64, 64, 64, 1)' + padding: '1px', + border: 0 + }) + .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))' + }); + + self.$volumeInput.find('.OxThumb') + .css({ + //border: '1px solid rgba(64, 64, 64, 1)' + padding: '1px 7px 1px 7px', + border: 0 + }) + .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))' }); - } - self.$control = {}; - - self.options.controls.forEach(function(control) { - - if (control == 'play') { - - self.$playButton = Ox.Button({ - style: 'symbol', - // FIXME: this is retarded, fix Ox.Button - title: [ - {id: 'play', title: 'play', selected: self.options.paused}, - {id: 'pause', title: 'pause', selected: !self.options.paused} - ], - tooltip: ['Play', 'Pause'], - type: 'image' - }) - .css({float: 'left'}) - .bindEvent('click', function() { - togglePaused(); - }) - .appendTo(self.$controls); - - } else if (control == 'playInToOut') { - - self.$playInToOutButton = Ox.Button({ - style: 'symbol', - title: 'playInToOut', - tooltip: 'Play In to Out', - type: 'image' - }) - .css({float: 'left'}) - .bindEvent('click', playInToOut) - .appendTo(self.$controls); - - } else if (control == 'mute') { - - self.$muteButton = Ox.Button({ - style: 'symbol', - title: [ - {id: 'mute', title: 'mute', selected: !self.options.muted}, - {id: 'unmute', title: 'unmute', selected: self.options.muted} - ], - tooltip: ['Mute', 'Unmute'], - type: 'image' - }) - .css({float: 'left'}) - .bindEvent('click', function() { - toggleMuted(); - }) - .appendTo(self.$controls); - - } else if (control == 'volume') { - - } else if (control == 'scale') { - - self.$scaleButton = Ox.Button({ - style: 'symbol', - title: [ - {id: 'fill', title: 'fill', selected: !self.options.scaleToFill}, - {id: 'fit', title: 'fit', selected: self.options.scaleToFill} - ], - tooltip: ['Scale to Fill', 'Scale to Fit'], - type: 'image' - }) - .css({float: 'left'}) - .bindEvent('click', function() { - toggleScale(); - }) - .appendTo(self.$controls); - - } else if (control == 'fullscreen') { - - self.$fullscreenButton = Ox.Button({ - style: 'symbol', - title: [ - {id: 'grow', title: 'grow', selected: !self.options.fullscreen}, - {id: 'shrink', title: 'shrink', selected: self.options.fullscreen} - ], - tooltip: ['Enter Fullscreen', 'Exit Fullscreen'], - type: 'image' - }) - .css({float: 'left'}) - .bindEvent('click', function() { - toggleFullscreen(); - }) - .appendTo(self.$controls); - - } else if (control == 'size') { - - self.$sizeButton = Ox.Button({ - style: 'symbol', - title: [ - {id: 'grow', title: 'grow', selected: !self.options.sizeIsLarge}, - {id: 'shrink', title: 'shrink', selected: self.options.sizeIsLarge} - ], - tooltip: ['Larger', 'Smaller'], - type: 'image' - }) - .css({float: 'left'}) - .bindEvent('click', toggleSize) - .appendTo(self.$controls); - - } else if (control == 'timeline') { - - /* - if (self.options.showProgress) { - self.$progress = $('') - .attr({ - src: getProgressImageURL() - }) - .css({ - float: 'left', - height: self.barHeight + 'px', - }) - .appendTo(self.$timelineImages.$element); - } - */ - - if (self.options.duration) { - self.$timeline = getTimeline() - } else { - self.$timeline = Ox.Element() - .css({ - float: 'left' - }) - .html(' '); - } - self.$timeline.appendTo(self.$controls); - - } else if (control == 'space') { - - self.$space = $('
') - .css({float: 'left'}) - .html(' ') // fixme: ?? - .appendTo(self.$controls.$element); - - } else if (control == 'position') { - - self.positionWidth = 48 + - !!self.options.showMilliseconds * 2 - + self.options.showMilliseconds * 6; - - self.$position = $('
') - .addClass('foo') - .css({ - float: 'left', - width: (self.positionWidth - 4) + 'px', - height: '12px', - padding: '2px', - fontSize: '9px', - textAlign: 'center', - color: 'rgb(255, 255, 255)' - }) - .html(formatPosition) - .bind({ - click: function() { - if (!self.options.paused) { - self.wasPlaying = true; - togglePaused(true); - } - self.$position.hide(); - self.$positionInput - .options({ - value: formatPosition() - }) - .show() - .focusInput(false); - } - }) - .appendTo(self.$controls.$element); - - self.$positionInput = Ox.Input({ - value: formatPosition(), - width: self.positionWidth - }) - .css({ - float: 'left', - background: 'rgba(0, 0, 0, 0)', - MozBoxShadow: '0 0 0', - WebkitBoxShadow: '0 0 0' - }) - .bindEvent({ - focus: function() { - self.inputHasFocus = true; - }, - blur: function() { - self.inputHasFocus = false; - submitPositionInput(); - } - }) - .hide() - .appendTo(self.$controls.$element); - - self.$positionInput.children('input').css({ - width: (self.positionWidth - 6) + 'px', - 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))' - }); - - } - - }); + self.$volumeValue = $('
') + .css({ + float: 'left', + width: '24px', + paddingTop: '2px', + fontSize: '9px', + textAlign: 'center' + }) + .html(self.options.muted ? 0 : Math.round(self.options.volume * 100)) + .appendTo(self.$volume); } + setSizes(); function clearInterfaceTimeout() { @@ -735,13 +880,22 @@ Ox.VideoPlayer = function(options, self) { } function find(query) { - query = query.toLowerCase(); - return query.length ? Ox.map(self.options.subtitles, function(subtitle) { - return subtitle.text.toLowerCase().indexOf(query) > -1 ? { - 'in': subtitle['in'], - out: subtitle.out - } : null; - }) : []; + var results = []; + Ox.print(query) + if (query.length) { + query = query.toLowerCase(); + results = Ox.map(self.options.subtitles, function(subtitle) { + return subtitle.text.toLowerCase().indexOf(query) > -1 ? { + 'in': subtitle['in'], + out: subtitle.out + } : null; + }); + if (results.length == 0) { + // fixme: doesn't happen + self.$findInput.focusInput(); + } + } + return results; } function formatPosition(position) { @@ -751,10 +905,14 @@ Ox.VideoPlayer = function(options, self) { function getCSS(element) { var css; - if (element == 'controls' || element == 'title') { + if (element == 'controlsTop' || element == 'controlsBottom') { css = { width: self.width + 'px' }; + } else if (element == 'find') { + css = { + width: Math.min(208, self.width) + 'px' + }; } else if (element == 'loadingIcon') { css = { left: self.iconLeft + 'px', @@ -767,7 +925,7 @@ Ox.VideoPlayer = function(options, self) { logoMargin = Math.round(self.height / 20); css = { left: logoMargin + 'px', - top: (logoMargin + !!self.titleIsVisible * 16) + 'px', + top: logoMargin + (self.controlsTopAreVisible ? 16 : 0) + 'px', height: logoHeight + 'px', }; } else if (element == 'player') { @@ -777,7 +935,7 @@ Ox.VideoPlayer = function(options, self) { ? window.innerHeight : self.height + ( self.options.externalControls - ? (!!self.options.controls.length + !!self.options.title) * self.barHeight + ? (!!self.options.controlsTop.length + !!self.options.controlsBottom.length) * self.barHeight : 0)) + 'px' }, self.options.fullscreen ? { left: 0, @@ -828,20 +986,28 @@ Ox.VideoPlayer = function(options, self) { }; } else if (element == 'subtitle') { css = { - bottom: (parseInt(self.height / 16) + !!self.controlsAreVisible * 16) + 'px', + bottom: (parseInt(self.height / 16) + !!self.controlsBottomAreVisible * 16) + 'px', width: self.width + 'px', fontSize: parseInt(self.height / 20) + 'px', WebkitTextStroke: (self.height / 1000) + 'px rgb(0, 0, 0)' }; - } else if (element == 'space' || element == 'timeline') { + } else if (element == 'spaceBottom' || element == 'timeline') { css = { width: self.timelineWidth + 'px' }; + } else if (element == 'spaceTop' || element == 'title') { + css = { + width: getTitleWidth() + 'px' + }; } else if (element == 'videoContainer') { css = { width: self.width + 'px', height: self.height + 'px' }; + } else if (element == 'volume') { + css = { + width: Math.min(168, self.width) + }; } return css; } @@ -929,6 +1095,12 @@ Ox.VideoPlayer = function(options, self) { .css({ float: 'left' }) + .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))' + }) .bindEvent({ position: function(data) { setPosition(data.position, true); @@ -946,7 +1118,7 @@ Ox.VideoPlayer = function(options, self) { function getTimelineLeft() { var left = 0; - Ox.forEach(self.options.controls, function(control) { + Ox.forEach(self.options.controlsBottom, function(control) { if (control == 'timeline') { return false; } @@ -957,7 +1129,7 @@ Ox.VideoPlayer = function(options, self) { function getTimelineWidth() { return (self.options.fullscreen ? window.innerWidth : self.options.width) - - self.options.controls.reduce(function(prev, curr) { + self.options.controlsBottom.reduce(function(prev, curr) { return prev + ( curr == 'timeline' || curr == 'space' ? 0 : curr == 'position' ? self.positionWidth : 16 @@ -965,13 +1137,45 @@ Ox.VideoPlayer = function(options, self) { }, 0); } + function getTitleWidth() { + return (self.options.fullscreen ? window.innerWidth : self.options.width) - + self.options.controlsTop.reduce(function(prev, curr) { + return prev + ( + curr == 'title' || curr == 'space' ? 0 : 16 + ); + }, 0); + } + + function getVolumeImageURL() { + var symbol; + if (self.options.muted || self.options.volume == 0) { + symbol = 'unmute'; + } else if (self.options.volume < 1/3) { + symbol = 'VolumeUp'; + } else if (self.options.volume < 2/3) { + symbol = 'VolumeDown'; + } else { + symbol = 'mute'; + } + return Ox.UI.getImagePath('symbol' + symbol + '.svg').replace('/classic/', '/modern/'); + } + function hideInterface() { Ox.print('hideInterface'); self.interfaceTimeout = setTimeout(function() { if (!self.exitFullscreen && !self.inputHasFocus && !self.mouseIsInControls) { - self.titleIsVisible = false; - self.controlsAreVisible = false; - that.find('.OxInterface').animate({ + self.controlsTopAreVisible = false; + self.controlsBottomAreVisible = false; + self.$controlsTop && self.$controlsTop.animate({ + opacity: 0 + }, 250); + self.$controlsBottom && self.$controlsBottom.animate({ + opacity: 0 + }, 250); + self.$find && self.$find.is(':visible') && self.$find.animate({ + opacity: 0 + }, 250); + self.$volume && self.$volume.is(':visible') && self.$volume.animate({ opacity: 0 }, 250); self.$logo && self.$logo.animate({ @@ -1133,7 +1337,7 @@ Ox.VideoPlayer = function(options, self) { self.iconTop = parseInt((self.height - self.iconSize) / 2); if (self.$timeline || self.$space) { self.timelineWidth = self.width - - self.options.controls.reduce(function(prev, curr) { + self.options.controlsBottom.reduce(function(prev, curr) { return prev + ( curr == 'timeline' || curr == 'space' ? 0 : curr == 'position' ? self.positionWidth : 16 @@ -1151,8 +1355,10 @@ Ox.VideoPlayer = function(options, self) { self.$loadingIcon.animate(getCSS('loadingIcon'), ms); self.$playIcon && self.$playIcon.animate(getCSS('playIcon'), ms); self.$subtitle && self.$subtitle.animate(getCSS('subtitle'), ms); + self.$controlsTop && self.$controlsTop.animate(getCSS('controlsTop'), ms); self.$title && self.$title.animate(getCSS('title'), ms); - self.$controls && self.$controls.animate(getCSS('controls'), ms); + self.$spaceTop && self.$spaceTop.animate(getCSS('spaceTop'), ms); + self.$controlsBottom && self.$controlsBottom.animate(getCSS('controlsBottom'), ms); if (self.$timeline) { self.$timeline.animate(getCSS('timeline'), ms, function() { self.$timeline.options({ @@ -1160,7 +1366,19 @@ Ox.VideoPlayer = function(options, self) { }) }); } - self.$space && self.$space.animate(getCSS('space'), ms); + self.$spaceBottom && self.$spaceBottom.animate(getCSS('spaceBottom'), ms); + if (self.$find) { + self.$find.animate(getCSS('find'), ms); + self.$findInput.options({ + width: Math.min(128, self.width - 80) + }); + } + if (self.$volume) { + self.$volume.animate(getCSS('volume'), ms); + self.$volumeInput.options({ + width: Math.min(128, self.width - 40) + }); + } } function setSubtitle() { @@ -1174,16 +1392,34 @@ Ox.VideoPlayer = function(options, self) { } } + function setVolume(data) { + self.options.volume = data.value; + self.$volumeButton.attr({ + src: getVolumeImageURL() + }); + self.$volumeValue.html(self.options.muted ? 0 : Math.round(self.options.volume * 100)); + self.video.volume = self.options.volume; + } + function showInterface() { Ox.print('showInterface'); clearTimeout(self.interfaceTimeout); - if (self.$title) { - self.titleIsVisible = true; + if (self.$controlsTop) { + self.controlsTopAreVisible = true; } - if (self.$controls) { - self.controlsAreVisible = true; + if (self.$controlsBottom) { + self.controlsBottomAreVisible = true; } - that.find('.OxInterface').animate({ + self.$controlsTop && self.$controlsTop.animate({ + opacity: 1 + }, 250); + self.$controlsBottom && self.$controlsBottom.animate({ + opacity: 1 + }, 250); + self.$find && self.$find.is(':visible') && self.$find.animate({ + opacity: 1 + }, 250); + self.$volume && self.$volume.is(':visible') && self.$volume.animate({ opacity: 1 }, 250); self.$logo && self.$logo.animate({ @@ -1219,12 +1455,12 @@ Ox.VideoPlayer = function(options, self) { function submitFindInput() { self.options.find = self.$findInput.options('value'); self.results = find(self.options.find); + self.$results.html(self.results.length); self.$timeline && self.$timeline.options({ results: self.results }); if (self.results.length) { - setPosition(self.results[0]['in'] + self.secondsPerFrame, true); - self.currentResult = 0; + goToNextResult(1); } } @@ -1262,6 +1498,11 @@ Ox.VideoPlayer = function(options, self) { self.mouseHasLeft && hideInterface(); } + function toggleFind() { + self.$find.toggle(); + self.$find.is(':visible') && self.$findInput.focusInput(false); + } + function toggleFullscreen(toggleButton) { var parentOffset, wasPlaying; self.options.fullscreen = !self.options.fullscreen; @@ -1295,7 +1536,7 @@ Ox.VideoPlayer = function(options, self) { } } }); - self.$controls && self.$controls.bind({ + that.find('.OxControls').bind({ mouseenter: function() { self.mouseIsInControls = true; }, @@ -1310,7 +1551,7 @@ Ox.VideoPlayer = function(options, self) { // flag makes the animation end on absolute position self.exitFullscreen = true; that.unbind('mousemove'); - self.$controls && self.$controls + that.find('.OxControls') .trigger('mouseleave') .unbind('mouseenter') .unbind('mouseleave'); @@ -1320,7 +1561,8 @@ Ox.VideoPlayer = function(options, self) { that.detach() .css({ left: self.relativeOffset.left + 'px', - top: self.relativeOffset.top + 'px' + top: self.relativeOffset.top + 'px', + zIndex: 1 }) .appendTo(self.$parent); wasPlaying && self.video.play(); @@ -1339,6 +1581,15 @@ Ox.VideoPlayer = function(options, self) { if (toggleButton && self.$muteButton) { self.$muteButton.toggleTitle(); } + self.$volumeButton && self.$volumeButton.attr({ + src: getVolumeImageURL() + }); + self.$volumeInput && self.$volumeInput.options({ + value: self.options.muted ? 0 : self.options.volume + }); + self.$volumeValue && + self.$volumeValue.html(self.options.muted ? 0 : Math.round(self.options.volume * 100)); + } function togglePaused(toggleButton) {