2011-05-12 22:12:41 +00:00
|
|
|
/*@
|
2011-05-13 15:44:50 +00:00
|
|
|
Ox.VideoPlayer <f> Generic Video Player
|
2011-05-12 22:12:41 +00:00
|
|
|
(options, self) -> <o> Video Player
|
|
|
|
options <o> Options
|
2011-05-13 15:44:50 +00:00
|
|
|
annotation <[o]> Array of annotation tracks
|
|
|
|
name <s> Name of the annotation track
|
|
|
|
data <[o]> Annotation data
|
|
|
|
in <n> In point (sec)
|
|
|
|
out <n> Out point (sec)
|
|
|
|
text <s> 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
|
|
|
|
duration <n|-1> Duration (sec)
|
|
|
|
enableKeyboard <b|false> If true, enable keyboard controls
|
|
|
|
externalControls <b|false> If true, controls are outside the video
|
|
|
|
focus <s|'click'> focus on 'click', 'load' or 'mouseover'
|
|
|
|
fps <n|25> Frames per second
|
|
|
|
height <n|144> Height in px (excluding external controls)
|
|
|
|
in <n> In point (sec)
|
|
|
|
keepIconVisible <b|false> If true, play icon stays visible after mouseleave
|
|
|
|
keepLargeTimelineVisible <b|false> If true, large timeline stays visible after mouseleave
|
|
|
|
keepLogoVisible <b|false> If true, logo stays visible after mouseleave
|
|
|
|
logo <s|''> Logo image URL
|
|
|
|
logoLink <s|''> Logo link URL
|
|
|
|
logoTitle <s|''> Text for tooltip
|
|
|
|
muted <b|false> If true, video is muted
|
|
|
|
paused <b|false> If true, video is paused
|
|
|
|
playInToOut <b|false> If true, video plays only from in to out
|
|
|
|
position <n|0> Initial position (sec)
|
|
|
|
poster <s|''> Poster URL
|
|
|
|
posterFrame <n|-1> Position of poster frame (sec)
|
|
|
|
preload <s|'auto'> 'auto', 'metadata' or 'none'
|
|
|
|
out <n|-1> Out point (sec)
|
|
|
|
scaleToFill <b|false> If true, scale to fill (otherwise, scale to fit)
|
|
|
|
showControlsOnLoad <b|false> If true, show controls on load
|
|
|
|
showFind <b|false> If true, show find input
|
|
|
|
showHours <b|false> If true, don't show hours for videos shorter than one hour
|
|
|
|
showIcon <b|false> If true, show play icon
|
|
|
|
showIconOnLoad <b|false> If true, show icon on load
|
|
|
|
showLargeTimeline <b|false> If true, show large timeline
|
|
|
|
showMilliseconds <b|false> If true, show milliseconds
|
|
|
|
showPointMarkers <b|false> If true, show in/out markers
|
|
|
|
sizeIsLarge <b|false> If true, initial state of the size control is large
|
|
|
|
subtitles <s|[o]|[]> URL or SRT or array of subtitles
|
|
|
|
in <n> In point (sec)
|
|
|
|
out <n> Out point (sec)
|
2011-05-12 22:12:41 +00:00
|
|
|
text <s> Text
|
2011-05-13 15:44:50 +00:00
|
|
|
timeline <s> Timeline image URL
|
|
|
|
title <s|''> Video title
|
|
|
|
type <s|'play'> 'play', 'in' or 'out'
|
|
|
|
video <s|''> Video URL
|
|
|
|
volume <n|1> Volume (0-1)
|
|
|
|
width <n|256> Width in px
|
2011-05-12 22:12:41 +00:00
|
|
|
@*/
|
|
|
|
|
2011-05-12 10:39:48 +00:00
|
|
|
Ox.VideoPlayer = function(options, self) {
|
|
|
|
|
|
|
|
self = self || {};
|
|
|
|
var that = Ox.Element({}, self)
|
|
|
|
.defaults({
|
2011-05-13 15:44:50 +00:00
|
|
|
annotations: [],
|
|
|
|
controls: [],
|
|
|
|
duration: -1,
|
|
|
|
enableKeyboard: false,
|
|
|
|
externalControls: false,
|
|
|
|
focus: 'click',
|
|
|
|
fps: 25,
|
|
|
|
height: 144,
|
|
|
|
'in': -1,
|
|
|
|
keepIconVisible: false,
|
|
|
|
keepLargeTimelineVisible: false,
|
|
|
|
keepLogoVisible: false,
|
|
|
|
logo: '',
|
2011-05-12 22:12:41 +00:00
|
|
|
logoLink: '',
|
|
|
|
logoTitle: '',
|
2011-05-13 15:44:50 +00:00
|
|
|
muted: false,
|
|
|
|
paused: false,
|
|
|
|
playInToOut: false,
|
2011-05-12 10:39:48 +00:00
|
|
|
position: 0,
|
2011-05-13 15:44:50 +00:00
|
|
|
poster: '',
|
|
|
|
preload: 'auto',
|
|
|
|
out: -1,
|
|
|
|
scaleToFill: false,
|
|
|
|
showControlsOnLoad: false,
|
|
|
|
showFind: false,
|
|
|
|
showHours: false,
|
|
|
|
showIcon: false,
|
|
|
|
showIconOnLoad: false,
|
|
|
|
showLargeTimeline: false,
|
|
|
|
showMilliseconds: false,
|
|
|
|
showPointMarkers: false,
|
2011-05-12 22:12:41 +00:00
|
|
|
subtitles: [],
|
2011-05-13 15:44:50 +00:00
|
|
|
timeline: '',
|
2011-05-12 22:12:41 +00:00
|
|
|
title: '',
|
2011-05-13 15:44:50 +00:00
|
|
|
type: 'play',
|
|
|
|
video: '',
|
|
|
|
volume: 1,
|
2011-05-12 10:39:48 +00:00
|
|
|
width: 256
|
|
|
|
})
|
|
|
|
.options(options || {})
|
|
|
|
.css({
|
2011-05-13 15:44:50 +00:00
|
|
|
position: 'absolute'
|
2011-05-12 10:39:48 +00:00
|
|
|
});
|
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
if (self.options.controls.length || self.options.showIcon || self.options.title) {
|
|
|
|
that.bind({
|
|
|
|
mouseenter: showInterface,
|
|
|
|
mouseleave: hideInterface
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2011-05-12 22:12:41 +00:00
|
|
|
if (Ox.isString(self.options.subtitles)) {
|
|
|
|
if (self.options.subtitles.indexOf('\n') > -1) {
|
|
|
|
self.options.subtitles = Ox.parseSRT(self.options.subtitles);
|
|
|
|
} else {
|
|
|
|
Ox.get(self.options.subtitles, function(data) {
|
|
|
|
self.options.subtitles = Ox.parseSRT(data);
|
|
|
|
});
|
|
|
|
//self.options.subtitles = [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
// fixme: this is _relative_, resizing can happen
|
|
|
|
self.ratio = self.options.width / self.options.height;
|
|
|
|
self.barHeight = 16;
|
|
|
|
setSize();
|
|
|
|
|
|
|
|
self.millisecondsPerFrame = 1000 / self.options.fps;
|
|
|
|
|
2011-05-12 10:39:48 +00:00
|
|
|
self.buffered = [];
|
|
|
|
self.controlsTimeout;
|
2011-05-12 11:15:32 +00:00
|
|
|
self.dragTimeout;
|
2011-05-12 10:39:48 +00:00
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
self.$videoContainer = $('<div>')
|
2011-05-12 10:39:48 +00:00
|
|
|
.css({
|
|
|
|
position: 'absolute',
|
2011-05-13 15:44:50 +00:00
|
|
|
width: self.options.width + 'px',
|
|
|
|
height: self.options.height + 'px',
|
|
|
|
overflow: 'hidden'
|
|
|
|
})
|
|
|
|
.appendTo(that.$element)
|
|
|
|
|
|
|
|
self.$video = $('<video>')
|
|
|
|
.attr(Ox.extend({
|
|
|
|
preload: self.options.preload,
|
|
|
|
src: self.options.video
|
|
|
|
}, !self.options.paused ? {
|
|
|
|
autoplay: 'autoplay'
|
|
|
|
} : {}, self.options.poster ? {
|
|
|
|
poster: self.options.poster
|
|
|
|
} : {}))
|
|
|
|
.css({
|
|
|
|
position: 'absolute'
|
2011-05-12 10:39:48 +00:00
|
|
|
})
|
2011-05-13 15:44:50 +00:00
|
|
|
.bind({
|
|
|
|
click: togglePaused,
|
|
|
|
ended: ended,
|
2011-05-12 10:39:48 +00:00
|
|
|
loadedmetadata: loadedmetadata,
|
2011-05-13 15:44:50 +00:00
|
|
|
progress: progress,
|
|
|
|
seeked: seeked,
|
|
|
|
seeking: seeking
|
2011-05-12 10:39:48 +00:00
|
|
|
})
|
2011-05-13 15:44:50 +00:00
|
|
|
.appendTo(self.$videoContainer);
|
|
|
|
self.video = self.$video[0];
|
2011-05-12 10:39:48 +00:00
|
|
|
|
2011-05-12 20:02:22 +00:00
|
|
|
if (self.options.title) {
|
|
|
|
self.$titlebar = $('<div>')
|
2011-05-13 15:44:50 +00:00
|
|
|
.addClass('OxInterface')
|
2011-05-12 20:02:22 +00:00
|
|
|
.css({
|
|
|
|
position: 'absolute',
|
|
|
|
width: self.options.width + 'px',
|
2011-05-13 15:44:50 +00:00
|
|
|
height: (self.barHeight - 1) + 'px',
|
2011-05-12 20:02:22 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
if (self.options.logo) {
|
|
|
|
self.logoHeight = Math.round(self.options.height / 10);
|
|
|
|
self.logoMargin = Math.round(self.options.height / 20);
|
|
|
|
self.$logo = $('<img>')
|
|
|
|
.attr({
|
|
|
|
src: self.options.logo
|
|
|
|
})
|
|
|
|
.css({
|
|
|
|
position: 'absolute',
|
|
|
|
left: self.logoMargin + 'px',
|
|
|
|
top: self.logoMargin + 'px',
|
|
|
|
height: self.logoHeight + 'px',
|
|
|
|
cursor: self.options.logoLink ? 'pointer' : 'default',
|
|
|
|
opacity: 0.25,
|
|
|
|
})
|
|
|
|
.appendTo(that.$element);
|
|
|
|
if (self.options.logoTitle) {
|
|
|
|
self.$logoTooltip = Ox.Tooltip({
|
|
|
|
title: self.options.logoTitle
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.iconSize = Math.min(Math.round(self.options.height / 10), 16);
|
2011-05-12 10:51:17 +00:00
|
|
|
self.$loadingIcon = $('<img>')
|
|
|
|
.attr({
|
2011-05-12 20:02:22 +00:00
|
|
|
src: Ox.UI.getImagePath('symbolLoadingAnimated.svg').replace('/classic/', '/modern/')
|
2011-05-12 10:51:17 +00:00
|
|
|
})
|
|
|
|
.css({
|
|
|
|
position: 'absolute',
|
2011-05-13 15:44:50 +00:00
|
|
|
left: parseInt((self.options.width - self.iconSize) / 2) + 'px',
|
|
|
|
top: parseInt((self.options.height - self.iconSize) / 2) + 'px',
|
|
|
|
width: self.iconSize + 'px',
|
|
|
|
height: self.iconSize + 'px'
|
2011-05-12 10:51:17 +00:00
|
|
|
})
|
|
|
|
.appendTo(that.$element);
|
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
if (self.options.showIcon) {
|
|
|
|
self.$playIcon = $('<div>')
|
|
|
|
.addClass('OxInterface')
|
|
|
|
.css({
|
|
|
|
position: 'absolute',
|
|
|
|
left: parseInt(self.options.width / 2) - 16 + 'px',
|
|
|
|
top: parseInt(self.options.height / 2) - 16 + 'px',
|
|
|
|
width: '28px',
|
|
|
|
height: '28px',
|
|
|
|
border: '2px solid rgb(255, 255, 255)',
|
|
|
|
borderRadius: '16px',
|
|
|
|
opacity: 0
|
|
|
|
})
|
|
|
|
.append(
|
|
|
|
self.$playIconImage = $('<img>')
|
|
|
|
.attr({
|
|
|
|
src: Ox.UI.getImagePath('symbolPlay.svg').replace('/classic/', '/modern/')
|
|
|
|
})
|
|
|
|
.css({
|
|
|
|
width: '20px',
|
|
|
|
height: '20px',
|
|
|
|
margin: '4px'
|
|
|
|
})
|
|
|
|
)
|
|
|
|
.appendTo(that.$element);
|
|
|
|
}
|
2011-05-12 22:12:41 +00:00
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
if (self.options.subtitles.length) {
|
|
|
|
self.$subtitle = $('<div>')
|
|
|
|
//.addClass('OxSubtitle')
|
|
|
|
.css({
|
|
|
|
position: 'absolute',
|
|
|
|
left: 0,
|
|
|
|
right: 0,
|
|
|
|
textAlign: 'center',
|
|
|
|
textShadow: 'rgba(0, 0, 0, 1) 0 0 4px',
|
|
|
|
color: 'rgb(255, 255, 255)'
|
|
|
|
})
|
|
|
|
.appendTo(that.$element);
|
|
|
|
setSubtitleSize();
|
|
|
|
}
|
2011-05-12 22:12:41 +00:00
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
if (self.options.controls.length) {
|
2011-05-12 10:39:48 +00:00
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
self.$controls = $('<div>')
|
|
|
|
.addClass('OxInterface')
|
|
|
|
.css({
|
|
|
|
position: 'absolute',
|
|
|
|
bottom: 0,
|
|
|
|
width: self.options.width + 'px',
|
|
|
|
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.$element);
|
2011-05-12 10:39:48 +00:00
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
self.$control = {};
|
2011-05-12 10:39:48 +00:00
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
self.positionWidth = 48 + (self.options.showMilliseconds ? 16 : 0);
|
|
|
|
self.outerTrackWidth = self.options.width - self.options.controls.reduce(function(prev, curr) {
|
|
|
|
return prev + (
|
|
|
|
curr == 'timeline' || curr == 'space' ? 0 :
|
|
|
|
curr == 'position' ? self.positionWidth : 16
|
|
|
|
);
|
|
|
|
}, 0);
|
|
|
|
self.innerTrackWidth = self.outerTrackWidth - self.barHeight;
|
|
|
|
self.markerOffset = -self.innerTrackWidth - 8;
|
|
|
|
|
|
|
|
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', togglePaused)
|
|
|
|
.appendTo(self.$controls);
|
2011-05-12 10:39:48 +00:00
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
} else if (control == 'playInToOut') {
|
2011-05-12 10:39:48 +00:00
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
self.$playInToOutButton = Ox.Button({
|
|
|
|
style: 'symbol',
|
|
|
|
title: 'playInToOut',
|
|
|
|
tooltip: 'Play In to Out',
|
|
|
|
type: 'image'
|
2011-05-12 20:02:22 +00:00
|
|
|
})
|
2011-05-13 15:44:50 +00:00
|
|
|
.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', toggleMuted)
|
|
|
|
.appendTo(self.$controls);
|
|
|
|
|
|
|
|
} else if (control == 'volume') {
|
|
|
|
|
|
|
|
} 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 == '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', toggleScale)
|
|
|
|
.appendTo(self.$controls);
|
|
|
|
|
|
|
|
} else if (control == 'timeline') {
|
|
|
|
|
|
|
|
self.$outerTrack = Ox.Element()
|
|
|
|
.css({
|
|
|
|
float: 'left',
|
|
|
|
width: self.outerTrackWidth + 'px',
|
|
|
|
height: self.barHeight + 'px',
|
|
|
|
background: 'rgba(0, 0, 0, 0.75)',
|
|
|
|
borderRadius: self.barHeight / 2 + 'px'
|
|
|
|
})
|
|
|
|
.appendTo(self.$controls);
|
|
|
|
|
|
|
|
self.$innerTrack = Ox.Element()
|
|
|
|
.css({
|
|
|
|
float: 'left',
|
|
|
|
width: self.innerTrackWidth + 'px',
|
|
|
|
height: self.barHeight + 'px',
|
|
|
|
marginLeft: self.barHeight / 2 + 'px'
|
|
|
|
})
|
|
|
|
.appendTo(self.$outerTrack);
|
2011-05-12 11:15:32 +00:00
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
self.$timeline = $('<img>')
|
|
|
|
.attr({
|
|
|
|
src: self.options.timeline
|
|
|
|
})
|
|
|
|
.css({
|
|
|
|
float: 'left',
|
|
|
|
width: self.innerTrackWidth + 'px',
|
|
|
|
height: self.barHeight + 'px'
|
|
|
|
})
|
|
|
|
.appendTo(self.$innerTrack.$element);
|
2011-05-12 10:39:48 +00:00
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
/*
|
|
|
|
self.$buffered = $('<img>')
|
|
|
|
.attr({
|
|
|
|
src: getBufferedImageURL()
|
|
|
|
})
|
|
|
|
.css({
|
|
|
|
float: 'left',
|
|
|
|
marginLeft: -self.innerTrackWidth + 'px',
|
|
|
|
width: self.innerTrackWidth + 'px',
|
|
|
|
height: self.barHeight + 'px',
|
|
|
|
})
|
|
|
|
.appendTo(self.$innerTrack.$element);
|
|
|
|
*/
|
|
|
|
|
|
|
|
self.$positionMarker = $('<div>')
|
|
|
|
.css({
|
|
|
|
float: 'left',
|
|
|
|
width: '14px',
|
|
|
|
height: '14px',
|
|
|
|
marginLeft: self.markerOffset + 'px',
|
|
|
|
border: '1px solid rgba(0, 0, 0, 0.5)',
|
|
|
|
borderRadius: '8px'
|
|
|
|
})
|
|
|
|
.append(
|
|
|
|
self.$positionMarkerRing = $('<div>')
|
|
|
|
.css({
|
|
|
|
width: '10px',
|
|
|
|
height: '10px',
|
|
|
|
border: '2px solid rgba(255, 255, 255, 0.5)',
|
|
|
|
borderRadius: '7px',
|
|
|
|
})
|
|
|
|
.append(
|
|
|
|
$('<div>')
|
|
|
|
.css({
|
|
|
|
width: '8px',
|
|
|
|
height: '8px',
|
|
|
|
border: '1px solid rgba(0, 0, 0, 0.5)',
|
|
|
|
borderRadius: '5px',
|
|
|
|
})
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.appendTo(self.$outerTrack.$element);
|
|
|
|
|
|
|
|
self.$trackInterface = Ox.Element()
|
|
|
|
.css({
|
|
|
|
float: 'left',
|
|
|
|
width: self.outerTrackWidth + 'px',
|
|
|
|
height: self.barHeight + 'px',
|
|
|
|
marginLeft: - self.outerTrackWidth + 'px'
|
2011-05-12 20:02:22 +00:00
|
|
|
})
|
2011-05-13 15:44:50 +00:00
|
|
|
.appendTo(self.$controls);
|
|
|
|
|
|
|
|
self.$tooltip = Ox.Tooltip({
|
|
|
|
animate: false
|
|
|
|
});
|
|
|
|
|
|
|
|
} else if (control == 'space') {
|
|
|
|
|
|
|
|
} else if (control == 'position') {
|
|
|
|
|
|
|
|
self.$position = $('<div>')
|
|
|
|
.addClass('foo')
|
|
|
|
.css({
|
|
|
|
float: 'left',
|
|
|
|
width: '44px',
|
|
|
|
height: '12px',
|
|
|
|
padding: '2px',
|
|
|
|
fontSize: '9px',
|
|
|
|
textAlign: 'center'
|
|
|
|
})
|
|
|
|
.html(Ox.formatDuration(self.options.position))
|
|
|
|
.bind({
|
|
|
|
click: function() {
|
|
|
|
if (!self.options.paused) {
|
|
|
|
self.wasPlaying = true;
|
|
|
|
togglePaused();
|
|
|
|
//togglePlayIcon();
|
|
|
|
self.$playButton.toggleTitle();
|
|
|
|
}
|
|
|
|
self.$position.hide();
|
|
|
|
self.$positionInput
|
|
|
|
.options({
|
|
|
|
value: Ox.formatDuration(self.options.position)
|
|
|
|
})
|
|
|
|
.show()
|
|
|
|
.focusInput(false);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.appendTo(self.$controls);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
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))'
|
|
|
|
});
|
|
|
|
|
2011-05-12 20:02:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
function ended() {
|
|
|
|
|
2011-05-12 20:02:22 +00:00
|
|
|
}
|
2011-05-12 10:39:48 +00:00
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
function getVideoCSS() {
|
|
|
|
var playerWidth = self.options.width,
|
|
|
|
playerHeight = self.options.height,
|
|
|
|
playerRatio = playerWidth / playerHeight,
|
|
|
|
videoWidth = self.video.videoWidth,
|
|
|
|
videoHeight = self.video.videoHeight,
|
|
|
|
videoRatio = videoWidth / videoHeight,
|
|
|
|
videoIsWider = videoRatio > playerRatio,
|
|
|
|
width, height;
|
|
|
|
if (self.options.scaleToFill) {
|
|
|
|
width = videoIsWider ? playerHeight * videoRatio : playerWidth;
|
|
|
|
height = videoIsWider ? playerHeight : playerWidth / videoRatio;
|
2011-05-12 10:39:48 +00:00
|
|
|
} else {
|
2011-05-13 15:44:50 +00:00
|
|
|
width = videoIsWider ? playerWidth : playerHeight * videoRatio;
|
|
|
|
height = videoIsWider ? playerWidth / videoRatio : playerHeight;
|
2011-05-12 10:39:48 +00:00
|
|
|
}
|
2011-05-13 15:44:50 +00:00
|
|
|
width = Math.round(width);
|
|
|
|
height = Math.round(height);
|
|
|
|
return {
|
|
|
|
width: width + 'px',
|
|
|
|
height: height + 'px',
|
|
|
|
marginLeft: parseInt((playerWidth - width) / 2),
|
|
|
|
marginTop: parseInt((playerHeight - height) / 2)
|
|
|
|
};
|
|
|
|
}
|
2011-05-12 10:39:48 +00:00
|
|
|
|
|
|
|
function getBufferedImageURL() {
|
2011-05-12 22:12:41 +00:00
|
|
|
var width = self.innerTrackWidth,
|
2011-05-13 15:44:50 +00:00
|
|
|
height = self.barHeight,
|
2011-05-12 10:39:48 +00:00
|
|
|
$canvas = $('<canvas>')
|
|
|
|
.attr({
|
|
|
|
width: width,
|
|
|
|
height: height,
|
|
|
|
}),
|
|
|
|
canvas = $canvas[0],
|
|
|
|
context = canvas.getContext('2d');
|
|
|
|
//Ox.print(width, height)
|
|
|
|
context.fillStyle = 'rgba(255, 0, 0, 0.5)';
|
|
|
|
context.fillRect(0, 0, width, height);
|
|
|
|
var imageData = context.getImageData(0, 0, width, height),
|
|
|
|
data = imageData.data;
|
|
|
|
|
|
|
|
self.buffered.forEach(function(range) {
|
2011-05-13 15:44:50 +00:00
|
|
|
var left = Math.round(range[0] * width / self.video.duration),
|
|
|
|
right = Math.round(range[1] * width / self.video.duration);
|
2011-05-12 10:39:48 +00:00
|
|
|
Ox.loop(left, right, function(x) {
|
|
|
|
Ox.loop(height, function(y) {
|
|
|
|
index = x * 4 + y * 4 * width;
|
|
|
|
data[index + 3] = 0;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
context.putImageData(imageData, 0, 0);
|
|
|
|
return canvas.toDataURL();
|
|
|
|
}
|
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
function getPosition(e) {
|
|
|
|
// fixme: no offsetX in firefox???
|
|
|
|
if ($.browser.mozilla) {
|
|
|
|
//Ox.print(e, e.layerX - 56)
|
|
|
|
return Ox.limit(
|
|
|
|
(e.layerX - 48 - self.barHeight / 2) / self.innerTrackWidth * self.video.duration,
|
|
|
|
0, self.video.duration
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
/*Ox.print(e.offsetX, Ox.limit(
|
|
|
|
(e.offsetX - self.barHeight / 2) / self.innerTrackWidth * self.video.duration,
|
|
|
|
0, self.video.duration
|
|
|
|
))*/
|
|
|
|
return Ox.limit(
|
|
|
|
(e.offsetX - self.barHeight / 2) / self.innerTrackWidth * self.video.duration,
|
|
|
|
0, self.video.duration
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-12 22:12:41 +00:00
|
|
|
function getSubtitle() {
|
|
|
|
var subtitle = '';
|
|
|
|
Ox.forEach(self.options.subtitles, function(v) {
|
|
|
|
if (
|
|
|
|
v['in'] <= self.options.position &&
|
|
|
|
v.out > self.options.position
|
|
|
|
) {
|
|
|
|
subtitle = v.text;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return subtitle;
|
|
|
|
}
|
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
function hideInterface() {
|
|
|
|
Ox.print('HIDE')
|
|
|
|
if (!(self.$positionInput && self.$positionInput.hasFocus())) {
|
2011-05-12 20:02:22 +00:00
|
|
|
self.controlsTimeout = setTimeout(function() {
|
2011-05-13 15:44:50 +00:00
|
|
|
$('.OxInterface').animate({
|
2011-05-12 20:02:22 +00:00
|
|
|
opacity: 0
|
|
|
|
}, 250);
|
2011-05-13 15:44:50 +00:00
|
|
|
self.$logo && self.$logo.animate({
|
|
|
|
top: self.logoMargin + 'px',
|
|
|
|
opacity: 0.25
|
|
|
|
}, 250, function() {
|
|
|
|
self.options.logoLink && self.$logo.unbind('click');
|
|
|
|
self.options.logoTitle &&
|
|
|
|
self.$logo.unbind('mouseenter').unbind('mouseleave');
|
|
|
|
});
|
|
|
|
self.$subtitle.animate({
|
|
|
|
bottom: parseInt(self.options.height / 16) + 'px',
|
|
|
|
});
|
2011-05-12 20:02:22 +00:00
|
|
|
}, 1000);
|
|
|
|
}
|
2011-05-12 10:39:48 +00:00
|
|
|
}
|
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
/*
|
2011-05-12 10:51:17 +00:00
|
|
|
function hideLoadingIcon() {
|
|
|
|
self.$loadingIcon.animate({
|
|
|
|
opacity: 0
|
2011-05-13 15:44:50 +00:00
|
|
|
}, 0, function() {
|
|
|
|
self.$playIcon.animate({
|
|
|
|
opacity: 1
|
|
|
|
}, 250);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
function hideLoadingIcon() {
|
|
|
|
self.$loadingIcon.hide().attr({
|
|
|
|
src: Ox.UI.getImagePath('symbolLoading.svg')
|
|
|
|
.replace('/classic/', '/modern/')
|
|
|
|
});
|
2011-05-12 10:51:17 +00:00
|
|
|
}
|
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
function loadedmetadata() {
|
|
|
|
|
|
|
|
self.$video.css(getVideoCSS());
|
|
|
|
|
2011-05-12 11:15:32 +00:00
|
|
|
hideLoadingIcon();
|
|
|
|
that.gainFocus().bindEvent({
|
|
|
|
key_space: function() {
|
2011-05-13 15:44:50 +00:00
|
|
|
togglePlayIcon();
|
2011-05-12 11:15:32 +00:00
|
|
|
self.$playButton.toggleTitle();
|
2011-05-13 15:44:50 +00:00
|
|
|
togglePaused();
|
2011-05-12 11:15:32 +00:00
|
|
|
}
|
|
|
|
});
|
2011-05-12 20:02:22 +00:00
|
|
|
self.$trackInterface
|
2011-05-12 11:15:32 +00:00
|
|
|
.bind({
|
2011-05-12 20:02:22 +00:00
|
|
|
mousedown: mousedownTrack,
|
|
|
|
mouseleave: mouseleaveTrack,
|
|
|
|
mousemove: mousemoveTrack,
|
2011-05-12 11:15:32 +00:00
|
|
|
})
|
|
|
|
.bindEvent({
|
2011-05-12 20:02:22 +00:00
|
|
|
drag: dragTrack,
|
|
|
|
dragpause: dragpauseTrack,
|
|
|
|
dragend: dragpauseTrack
|
2011-05-12 11:15:32 +00:00
|
|
|
});
|
2011-05-13 15:44:50 +00:00
|
|
|
// fixme: maybe not the right moment
|
|
|
|
if (!self.options.paused) {
|
|
|
|
self.playInterval = setInterval(playing, self.millisecondsPerFrame);
|
|
|
|
}
|
|
|
|
Ox.print('W', self.video.videoWidth)
|
2011-05-12 11:15:32 +00:00
|
|
|
}
|
|
|
|
|
2011-05-12 20:02:22 +00:00
|
|
|
function dragTrack(e) {
|
2011-05-12 11:15:32 +00:00
|
|
|
setPosition(getPosition(e));
|
2011-05-13 15:44:50 +00:00
|
|
|
self.video.currentTime = self.options.position;
|
2011-05-12 11:15:32 +00:00
|
|
|
if (self.dragTimeout) {
|
|
|
|
clearTimeout(self.dragTimeout);
|
|
|
|
self.dragTimeout = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-12 20:02:22 +00:00
|
|
|
function dragpauseTrack(e) {
|
2011-05-13 15:44:50 +00:00
|
|
|
self.video.currentTime = self.options.position;
|
2011-05-12 20:02:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function mousedownTrack(e) {
|
2011-05-12 11:15:32 +00:00
|
|
|
setPosition(getPosition(e));
|
2011-05-13 15:44:50 +00:00
|
|
|
self.video.currentTime = self.options.position;
|
2011-05-12 11:15:32 +00:00
|
|
|
}
|
|
|
|
|
2011-05-12 20:02:22 +00:00
|
|
|
function mouseleaveTrack(e) {
|
2011-05-12 11:15:32 +00:00
|
|
|
self.$tooltip.hide();
|
|
|
|
}
|
|
|
|
|
2011-05-12 20:02:22 +00:00
|
|
|
function mousemoveTrack(e) {
|
2011-05-12 11:15:32 +00:00
|
|
|
self.$tooltip.options({
|
|
|
|
title: Ox.formatDuration(getPosition(e))
|
|
|
|
}).show(e.clientX, e.clientY);
|
|
|
|
}
|
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
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.video.duration);
|
|
|
|
}
|
|
|
|
|
|
|
|
function playing() {
|
|
|
|
var event = 'playing';
|
|
|
|
self.options.position = Math.round(
|
|
|
|
self.video.currentTime * self.options.fps
|
|
|
|
) / self.options.fps;
|
|
|
|
if (
|
|
|
|
(self.options.playInToOut || self.playInToOut) &&
|
|
|
|
self.options.position >= self.options.out
|
|
|
|
) {
|
|
|
|
togglePaused();
|
|
|
|
setPosition(self.options.out);
|
|
|
|
} else {
|
|
|
|
setPosition();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function progress() {
|
|
|
|
return;
|
|
|
|
var buffered = self.video.buffered;
|
|
|
|
for (var i = 0; i < buffered.length; i++) {
|
|
|
|
self.buffered[i] = [buffered.start(i), buffered.end(i)];
|
|
|
|
// fixme: firefox weirdness
|
|
|
|
if (self.buffered[i][0] > self.buffered[i][1]) {
|
|
|
|
self.buffered[i][0] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.$buffered.attr({
|
|
|
|
src: getBufferedImageURL()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function seeked() {
|
|
|
|
hideLoadingIcon();
|
|
|
|
}
|
|
|
|
|
|
|
|
function seeking() {
|
|
|
|
showLoadingIcon();
|
|
|
|
}
|
|
|
|
|
|
|
|
function setSize() {
|
|
|
|
self.height = self.options.height + (
|
|
|
|
self.options.externalControls
|
|
|
|
? (!!self.options.controls.length + !!self.options.title) * self.barHeight
|
|
|
|
: 0
|
|
|
|
);
|
|
|
|
that.css({
|
|
|
|
position: 'absolute',
|
|
|
|
width: self.options.width + 'px',
|
|
|
|
height: self.height + 'px'
|
|
|
|
});
|
2011-05-12 10:39:48 +00:00
|
|
|
}
|
|
|
|
|
2011-05-12 11:15:32 +00:00
|
|
|
function setPosition(position) {
|
2011-05-13 15:44:50 +00:00
|
|
|
if (!Ox.isUndefined(position)) {
|
|
|
|
self.options.position = position;
|
|
|
|
}
|
|
|
|
//Ox.print('SP', self.options.position)
|
2011-05-12 22:12:41 +00:00
|
|
|
setSubtitle();
|
2011-05-12 11:15:32 +00:00
|
|
|
self.$positionMarker.css({
|
2011-05-13 15:44:50 +00:00
|
|
|
marginLeft: self.innerTrackWidth * self.options.position / self.video.duration + self.markerOffset + 'px',
|
2011-05-12 11:15:32 +00:00
|
|
|
});
|
2011-05-13 15:44:50 +00:00
|
|
|
self.$position.html(Ox.formatDuration(self.options.position));
|
2011-05-12 11:15:32 +00:00
|
|
|
}
|
|
|
|
|
2011-05-12 22:12:41 +00:00
|
|
|
function setSubtitle() {
|
|
|
|
var subtitle = getSubtitle();
|
|
|
|
if (subtitle != self.subtitle) {
|
|
|
|
self.subtitle = subtitle;
|
|
|
|
self.$subtitle.html(
|
|
|
|
Ox.highlight(self.subtitle, self.options.find, 'Ox.Highlight')
|
|
|
|
.replace(/\n/g, '<br/>')
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function setSubtitleSize() {
|
|
|
|
self.$subtitle.css({
|
2011-05-13 15:44:50 +00:00
|
|
|
bottom: parseInt(self.options.height / 16) + 'px',
|
2011-05-12 22:12:41 +00:00
|
|
|
width: self.options.width + 'px',
|
|
|
|
fontSize: parseInt(self.options.height / 20) + 'px',
|
|
|
|
WebkitTextStroke: (self.options.height / 1000) + 'px rgb(0, 0, 0)'
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
function showInterface() {
|
|
|
|
clearTimeout(self.controlsTimeout);
|
|
|
|
$('.OxInterface').animate({
|
2011-05-12 10:51:17 +00:00
|
|
|
opacity: 1
|
2011-05-13 15:44:50 +00:00
|
|
|
}, 250);
|
|
|
|
self.$logo && self.$logo.animate({
|
|
|
|
top: self.logoMargin + 16 + 'px',
|
|
|
|
opacity: 0.5
|
|
|
|
}, 250, function() {
|
|
|
|
self.options.logoLink && self.$logo
|
|
|
|
.bind({
|
|
|
|
click: function() {
|
|
|
|
document.location.href = self.options.logoLink;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
self.options.logoTitle && self.$logo
|
|
|
|
.bind({
|
|
|
|
mouseenter: self.$logoTooltip.show,
|
|
|
|
mouseleave: self.$logoTooltip.hide
|
|
|
|
});
|
|
|
|
});
|
|
|
|
self.$subtitle.animate({
|
|
|
|
bottom: self.barHeight + parseInt(self.options.height / 16) + 'px',
|
|
|
|
});
|
2011-05-12 10:51:17 +00:00
|
|
|
}
|
2011-05-13 15:44:50 +00:00
|
|
|
|
|
|
|
function showLoadingIcon() {
|
|
|
|
self.$loadingIcon.attr({
|
|
|
|
src: Ox.UI.getImagePath('symbolLoadingAnimated.svg')
|
|
|
|
.replace('/classic/', '/modern/')
|
|
|
|
})
|
|
|
|
.show();
|
|
|
|
}
|
|
|
|
|
|
|
|
function submitPositionInput() {
|
|
|
|
self.$positionInput.hide();
|
|
|
|
self.$position.html('').show();
|
|
|
|
setPosition(parsePositionInput(self.$positionInput.options('value')));
|
|
|
|
self.video.currentTime = self.options.position;
|
|
|
|
if (self.wasPlaying) {
|
|
|
|
self.video.play();
|
|
|
|
togglePlayIcon();
|
|
|
|
self.$playButton.toggleTitle();
|
|
|
|
self.wasPlaying = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function toggleMuted() {
|
|
|
|
self.options.muted = !self.options.muted;
|
|
|
|
self.video.muted = self.options.muted;
|
2011-05-12 10:39:48 +00:00
|
|
|
}
|
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
function togglePaused() {
|
|
|
|
self.options.paused = !self.options.paused;
|
2011-05-12 20:02:22 +00:00
|
|
|
self.$positionMarkerRing.css({
|
2011-05-13 15:44:50 +00:00
|
|
|
borderColor: 'rgba(255, 255, 255, ' + (self.options.paused ? 0.5 : 1) + ')'
|
2011-05-12 10:39:48 +00:00
|
|
|
});
|
2011-05-13 15:44:50 +00:00
|
|
|
if (self.options.paused) {
|
|
|
|
self.video.pause();
|
|
|
|
clearInterval(self.playInterval);
|
|
|
|
self.playInToOut = false;
|
|
|
|
} else {
|
|
|
|
self.video.play();
|
|
|
|
self.playInterval = setInterval(playing, self.millisecondsPerFrame);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function togglePlayIcon() {
|
|
|
|
self.$playIconImage.attr({
|
|
|
|
src: Ox.UI.getImagePath('symbol' + (self.video.paused() ? 'Play' : 'Pause')+ '.svg').replace('/classic/', '/modern/')
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function toggleScale() {
|
|
|
|
Ox.print('TOGGLE SCALE')
|
|
|
|
self.options.scaleToFill = !self.options.scaleToFill;
|
|
|
|
self.$video.animate(getVideoCSS(), 250);
|
|
|
|
}
|
|
|
|
|
|
|
|
function toggleSize() {
|
|
|
|
self.options.sizeIsLarge = !self.options.sizeIsLarge;
|
|
|
|
that.triggerEvent('size', {
|
|
|
|
size: self.options.sizeIsLarge ? 'large' : 'small'
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
self.setOptions = function(key, value) {
|
|
|
|
if (key == 'height' || key == 'width') {
|
|
|
|
setSize();
|
|
|
|
} else if (key == 'muted') {
|
|
|
|
toggleMuted();
|
|
|
|
} else if (key == 'paused') {
|
|
|
|
togglePaused();
|
|
|
|
} else if (key == 'position') {
|
|
|
|
setPosition();
|
|
|
|
}
|
2011-05-12 10:39:48 +00:00
|
|
|
}
|
|
|
|
|
2011-05-13 15:44:50 +00:00
|
|
|
that.playInToOut = function() {
|
|
|
|
self.playInToOut = true;
|
|
|
|
setPosition(self.options['in']);
|
|
|
|
self.options.paused && that.play();
|
|
|
|
return that;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-05-12 10:39:48 +00:00
|
|
|
return that;
|
|
|
|
|
|
|
|
};
|