diff --git a/demos/video/js/video.js b/demos/video/js/video.js index 62e0b560..825dc31d 100644 --- a/demos/video/js/video.js +++ b/demos/video/js/video.js @@ -34,6 +34,7 @@ Ox.load('UI', { Ox.VideoPlayer({ controls: ['play', 'mute', 'fullscreen', 'scale', 'timeline', 'position'], enableKeyboard: true, + find: 'brick', focus: 'mouseenter', height: 192, 'in': 3128.725, @@ -126,6 +127,7 @@ Ox.load('UI', { .bindEvent({ resize: function(foo, size) { $videos[0].options({width: size - 32}); + $smallTimeline.options({width: size - 16}); } }), size: 392, @@ -163,7 +165,7 @@ Ox.load('UI', { .bindEvent({ resize: function(foo, size) { $videos[2].options({width: size - 32}); - $blockTimeline.options({width: size - 40}); + $blockTimeline.options({width: size - 16}); } }), size: 392, @@ -192,19 +194,43 @@ Ox.load('UI', { Ox.get('srt/0393109.srt', function(srt) { var subtitles = Ox.parseSRT(srt); $foo.append( - Ox.SmallVideoTimelineImages({ + $smallTimeline = Ox.SmallVideoTimeline({ duration: 6336.08, + find: 'brick', getTimelineURL: function(i) { return 'png/timeline.16.' + i + '.png'; }, - 'in': 1800, - out: 1900, - results: [ - {'in': 3600, out: 3700} - ], + 'in': 3128.725, + out: 3130.725, + results: results, subtitles: subtitles, type: 'editor', - width: 392 + width: 376 + }) + .css({ + position: 'absolute', + left: '4px', + top: '4px' + }) + ); + $foo.append( + $playerTimeline = Ox.SmallVideoTimeline({ + duration: 6336.08, + find: 'brick', + getTimelineURL: function(i) { + return 'png/timeline.16.' + i + '.png'; + }, + 'in': 3128.725, + out: 3130.725, + results: results, + subtitles: subtitles, + type: 'player', + width: 376 + }) + .css({ + position: 'absolute', + left: '4px', + top: '32px' }) ); $bar.append( @@ -217,13 +243,14 @@ Ox.load('UI', { 'in': 3128.725, out: 3130.725, results: results, + showMilliseconds: 2, subtitles: subtitles, - width: 353 + width: 376 }) .css({ position: 'absolute', - left: '16px', - top: '16px' + left: '4px', + top: '4px' }) .bindEvent('position', function(data) { $videos[2].options({ diff --git a/source/Ox.UI/js/Video/Ox.BlockVideoTimeline.js b/source/Ox.UI/js/Video/Ox.BlockVideoTimeline.js index b02ca61a..4f204ef5 100644 --- a/source/Ox.UI/js/Video/Ox.BlockVideoTimeline.js +++ b/source/Ox.UI/js/Video/Ox.BlockVideoTimeline.js @@ -16,6 +16,7 @@ Ox.BlockVideoTimeline = function(options, self) { .options(options || {}) .css({ position: 'absolute', + //background: 'rgba(192, 192, 192, 0.1)' }) .bind({ mousedown: mousedown, @@ -89,7 +90,7 @@ Ox.BlockVideoTimeline = function(options, self) { overflow: 'hidden' }) .appendTo(that.$element); - self.$images[i] = Ox.SmallVideoTimelineImages({ + self.$images[i] = Ox.SmallVideoTimelineImage({ duration: self.options.duration, editing: self.options.editing, getTimelineURL: self.options.getTimelineURL, @@ -105,13 +106,15 @@ Ox.BlockVideoTimeline = function(options, self) { marginLeft: (-i * self.options.width) + 'px' }) .appendTo(self.$lines[i]); - self.$interfaces[i] = $('
').addClass('OxInterface') + self.$interfaces[i] = $('
') + .addClass('OxInterface') .css({ position: 'absolute', top: '2px', width: Math.ceil(self.options.duration) + 'px', height: '20px', marginLeft: (-i * self.options.width) + 'px', + //background: 'rgba(255, 0, 0, 0.1)', zIndex: 11 }) .appendTo(self.$lines[i]); @@ -123,6 +126,7 @@ Ox.BlockVideoTimeline = function(options, self) { function getPosition(e) { //FIXME: this might still be broken in opera according to http://acko.net/blog/mouse-handling-and-absolute-positions-in-javascript + Ox.print('offsetX', e.offsetX) return (e.offsetX ? e.offsetX : e.clientX - $(e.target).offset().left); } @@ -171,7 +175,7 @@ Ox.BlockVideoTimeline = function(options, self) { Ox.highlight(subtitle.text, self.options.find, 'OxHighlight').replace(/\n/g, '
') + '
' + Ox.formatDuration(subtitle['in'], 3) + ' - ' + Ox.formatDuration(subtitle['out'], 3) : - Ox.formatDuration(position, 3) + Ox.formatDuration(position) }) .show(e.clientX, e.clientY); @@ -189,7 +193,6 @@ Ox.BlockVideoTimeline = function(options, self) { function setPointMarker(point) { var position = Math.round(self.options[point]); - Ox.print('$$ position', position) self.$pointMarker[point].css({ left: (position % self.options.width) + 'px', top: (parseInt(position / self.options.width) * diff --git a/source/Ox.UI/js/Video/Ox.SmallVideoTimeline.js b/source/Ox.UI/js/Video/Ox.SmallVideoTimeline.js index 93e734c4..d3d77630 100644 --- a/source/Ox.UI/js/Video/Ox.SmallVideoTimeline.js +++ b/source/Ox.UI/js/Video/Ox.SmallVideoTimeline.js @@ -8,46 +8,254 @@ Ox.SmallVideoTimeline = function(options, self) { getTimelineURL: null, 'in': 0, out: 0, - width: 256, - type: 'player' + paused: false, + showMilliseconds: 0, + type: 'player', + width: 256 }) .options(options || {}) .addClass('OxSmallVideoTimeline') - .css({ + .css(Ox.extend({ width: self.options.width + 'px' - }); + }, self.options.type == 'player' ? { + background: 'rgb(0, 0, 0)', + borderRadius: '8px' + } : {})); self.height = self.options.type == 'player' ? 16 : 24; + self.imageLeft = self.options.type == 'player' ? 8 : 4; + self.imageWidth = self.options.width - + (self.options.type == 'player' ? 16 : 8) self.imageHeight = self.options.type == 'player' ? 16 : 18; - self.imageTop = self.options.type == 'player' ? 0 : 3; + self.interfaceLeft = self.options.type == 'player' ? 0 : 4; + self.interfaceTop = self.options.type == 'player' ? 0 : 2; + self.interfaceWidth = self.options.type == 'player' ? self.options.width : self.imageWidth; that.css({ height: self.height + 'px' }); - self.tooltip = Ox.Tooltip({ + self.$image = Ox.SmallVideoTimelineImage({ + duration: self.options.duration, + editing: self.options.editing, + getTimelineURL: self.options.getTimelineURL, + 'in': self.options['in'], + out: self.options.out, + results: self.options.results, + subtitles: self.options.subtitles, + width: self.imageWidth, + type: self.options.type + }) + .css({ + position: 'absolute', + left: self.imageLeft + 'px', + width: self.options.width + 'px' + }) + .appendTo(that); + + self.$interface = Ox.Element() + .addClass('OxInterface') + .css({ + position: 'absolute', + left: self.interfaceLeft + 'px', + top: self.interfaceTop + 'px', + width: self.interfaceWidth + 'px', + height: '20px', + zIndex: 11 + }) + .bind({ + mousedown: mousedown, + mouseleave: mouseleave, + mousemove: mousemove + }) + .bindEvent({ + drag: function(event, e) { + mousedown(e); + } + }) + .appendTo(that); + + if (self.options.type == 'player') { + self.$positionMarker = $('
') + .css({ + position: 'absolute', + width: '14px', + height: '14px', + border: '1px solid rgba(0, 0, 0, 0.5)', + borderRadius: '8px' + }) + .append( + self.$positionMarkerRing = $('
') + .css({ + width: '10px', + height: '10px', + border: '2px solid rgba(255, 255, 255, ' + (self.options.paused ? 0.5 : 1) + ')', + borderRadius: '7px', + }) + .append( + $('
') + .css({ + width: '8px', + height: '8px', + border: '1px solid rgba(0, 0, 0, 0.5)', + borderRadius: '5px', + }) + ) + ) + .appendTo(that.$element); + } else { + self.$positionMarker = $('') + .attr({ + src: Ox.UI.PATH + 'png/videoMarkerPlay.png' + }) + .css({ + position: 'absolute', + top: '2px', + width: '9px', + height: '5px', + zIndex: 10 + }) + .appendTo(that.$element); + } + setPositionMarker(); + + if (self.options.type == 'editor') { + self.$pointMarker = {}; + ['in', 'out'].forEach(function(point) { + var titleCase = Ox.toTitleCase(point); + self.$pointMarker[point] = $('') + .addClass('OxPointMarker' + titleCase) + .attr({ + src: Ox.UI.PATH + 'png/videoMarker' + titleCase + '.png' + }) + .css({ + position: 'absolute', + top: '16px', + width: '6px', + height: '6px', + marginLeft: (point == 'in' ? -1 : 4) + 'px', + zIndex: 10 + }) + .appendTo(that.$element); + setPointMarker(point); + }); + } + + self.$tooltip = Ox.Tooltip({ animate: false }).css({ textAlign: 'center' }); - getImageURL('timeline', function(timelineURL) { + function getPosition(e) { + var position = + ( + (e.offsetX ? e.offsetX : e.clientX - $(e.target).offset().left) - + (self.options.type == 'player' ? 8 : 0) + ) * self.options.duration / self.imageWidth; + return Ox.limit(position, 0, self.options.duration); + } - $('') - .attr({ - src: timelineURL + function getSubtitle(position) { + var subtitle = ''; + Ox.forEach(self.options.subtitles, function(v) { + if (v['in'] <= position && v.out > position) { + subtitle = v; + return false; + } + }); + return subtitle; + } + + function mousedown(e) { + if ($(e.target).is('.OxInterface')) { + self.options.position = getPosition(e); + setPositionMarker(); + if (!self.triggered) { + that.triggerEvent('position', { + position: self.options.position + }); + self.triggered = true; + setTimeout(function() { + self.triggered = false; + }, 250); + } + } + } + + function mouseleave() { + self.$tooltip.hide(); + } + + function mousemove(e) { + var position, subtitle; + if ($(e.target).is('.OxInterface')) { + position = getPosition(e); + subtitle = getSubtitle(position); + self.$tooltip.options({ + title: subtitle ? + '' + + Ox.highlight(subtitle.text, self.options.find, 'OxHighlight').replace(/\n/g, '
') + + '

' + + Ox.formatDuration(subtitle['in'], self.options.showMilliseconds) + ' - ' + + Ox.formatDuration(subtitle['out'], self.options.showMilliseconds) : + Ox.formatDuration(position, self.options.showMilliseconds) + }) + .show(e.clientX, e.clientY); + + } else { + self.$tooltip.hide(); + } + } + + function setPointMarker(point) { + self.$pointMarker[point].css({ + left: self.imageLeft + Math.round( + self.options[point] * self.imageWidth / self.options.duration + ) + 'px' + }); + } + + function setPositionMarker() { + Ox.print(self.interfaceLeft + Math.round( + self.options.position * self.imageWidth / self.options.duration + )); + self.$positionMarker.css({ + left: self.interfaceLeft + Math.round( + self.options.position * self.imageWidth / self.options.duration + ) - (self.options.type == 'editor' ? 4 : 0) + 'px', + }); + } + + function setWidth() { + that.css({ + width: self.options.width + 'px' + }); + self.$image.css({ + width: self.imageWidth + 'px' + }); + self.$image.children().css({ + width: self.imageWidth + 'px' + }); + self.$interface.css({ + width: self.interfaceWidth + 'px' + }); + setPositionMarker(); + if (self.options.type == 'editor') { + setPointMarker('in'); + setPointMarker('out'); + } + } + + self.setOption = function(key, value) { + if (key == 'paused') { + self.$positionMarkerRing.css({ + borderColor: 'rgba(255, 255, 255, ' + (self.options.paused ? 0.5 : 1) + ')' }) - .css({ - width: self.options.width + 'px', - height: self.imageHeight + 'px', - top: self.imageTop + 'px' - }) - .appendTo(that.$element); - - - - }); - + } else if (key == 'width') { + setWidth(); + } + }; return that; diff --git a/source/Ox.UI/js/Video/Ox.SmallVideoTimelineImages.js b/source/Ox.UI/js/Video/Ox.SmallVideoTimelineImage.js similarity index 99% rename from source/Ox.UI/js/Video/Ox.SmallVideoTimelineImages.js rename to source/Ox.UI/js/Video/Ox.SmallVideoTimelineImage.js index 5e0df72c..f6b3bf07 100644 --- a/source/Ox.UI/js/Video/Ox.SmallVideoTimelineImages.js +++ b/source/Ox.UI/js/Video/Ox.SmallVideoTimelineImage.js @@ -1,4 +1,4 @@ -Ox.SmallVideoTimelineImages = function(options, self) { +Ox.SmallVideoTimelineImage = function(options, self) { self = self || {}; var that = Ox.Element({}, self) diff --git a/source/Ox.UI/js/Video/Ox.VideoPlayer.js b/source/Ox.UI/js/Video/Ox.VideoPlayer.js index a465e6e8..7e02e999 100644 --- a/source/Ox.UI/js/Video/Ox.VideoPlayer.js +++ b/source/Ox.UI/js/Video/Ox.VideoPlayer.js @@ -508,7 +508,6 @@ Ox.VideoPlayer = function(options, self) { //*/ self.$positionMarker = $('
') - .addClass('positionmarker') .css({ float: 'left', width: '14px',