new timeline implementation
This commit is contained in:
parent
0642c10951
commit
fd1fc212f2
8 changed files with 690 additions and 54 deletions
|
@ -2,8 +2,31 @@ Ox.load('UI', {
|
|||
debug: true,
|
||||
theme: 'modern'
|
||||
}, function() {
|
||||
|
||||
var $foo, $bar;
|
||||
|
||||
var id = '0393109',
|
||||
poster = 'png/poster.png',
|
||||
results = [
|
||||
{'in': 190.335, out: 192.353},
|
||||
{'in': 1185.215, out: 1188.115},
|
||||
{'in': 1784.525, out: 1785.915},
|
||||
{'in': 1786.015, out: 1787.835},
|
||||
{'in': 3087.365, out: 3090.275},
|
||||
{'in': 3704.915, out: 3706.795},
|
||||
{'in': 3706.895, out: 3709.615},
|
||||
{'in': 4061.655, out: 4063.95},
|
||||
{'in': 4531.775, out: 4533.415},
|
||||
{'in': 4946.095, out: 4948.875},
|
||||
{'in': 5292.885, out: 5294.665},
|
||||
{'in': 5381.965, out: 5383.338},
|
||||
{'in': 5385.415, out: 5389.58},
|
||||
{'in': 5434.93, out: 5436.93},
|
||||
{'in': 5437.405, out: 5439.405},
|
||||
{'in': 5749.535, out: 5751.915},
|
||||
{'in': 5780.235, out: 5782.435},
|
||||
{'in': 5881.365, out: 5886.635}
|
||||
],
|
||||
timeline = 'http://next.0xdb.org/' + id + '/timeline.16.png',
|
||||
url = 'http://next.0xdb.org/' + id + '/96p.webm',
|
||||
videoSize = getVideoSize(),
|
||||
|
@ -13,9 +36,11 @@ Ox.load('UI', {
|
|||
enableKeyboard: 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,6 +76,7 @@ Ox.load('UI', {
|
|||
Ox.VideoPlayer({
|
||||
controls: ['play', 'playInToOut', 'mute', 'size', 'space', 'position'],
|
||||
externalControls: true,
|
||||
find: 'brick',
|
||||
height: 192,
|
||||
'in': 3128.725,
|
||||
out: 3130.725,
|
||||
|
@ -66,8 +92,10 @@ Ox.load('UI', {
|
|||
top: '16px'
|
||||
})
|
||||
.bindEvent({
|
||||
size: function() {
|
||||
|
||||
position: function(data) {
|
||||
$blockTimeline.options({
|
||||
position: data.position
|
||||
});
|
||||
}
|
||||
})
|
||||
];
|
||||
|
@ -90,7 +118,7 @@ Ox.load('UI', {
|
|||
resize: [100, 400]
|
||||
},
|
||||
{
|
||||
element: Ox.Element()
|
||||
element: $foo = Ox.Element()
|
||||
}
|
||||
],
|
||||
orientation: 'vertical'
|
||||
|
@ -127,7 +155,7 @@ Ox.load('UI', {
|
|||
resize: [100, 400]
|
||||
},
|
||||
{
|
||||
element: Ox.Element()
|
||||
element: $bar = Ox.Element()
|
||||
}
|
||||
],
|
||||
orientation: 'vertical'
|
||||
|
@ -135,6 +163,7 @@ Ox.load('UI', {
|
|||
.bindEvent({
|
||||
resize: function(foo, size) {
|
||||
$videos[2].options({width: size - 32});
|
||||
$blockTimeline.options({width: size - 40});
|
||||
}
|
||||
}),
|
||||
size: 392,
|
||||
|
@ -160,4 +189,49 @@ Ox.load('UI', {
|
|||
});
|
||||
}
|
||||
|
||||
Ox.get('srt/0393109.srt', function(srt) {
|
||||
var subtitles = Ox.parseSRT(srt);
|
||||
$foo.append(
|
||||
Ox.SmallVideoTimelineImages({
|
||||
duration: 6336.08,
|
||||
getTimelineURL: function(i) {
|
||||
return 'png/timeline.16.' + i + '.png';
|
||||
},
|
||||
'in': 1800,
|
||||
out: 1900,
|
||||
results: [
|
||||
{'in': 3600, out: 3700}
|
||||
],
|
||||
subtitles: subtitles,
|
||||
type: 'editor',
|
||||
width: 392
|
||||
})
|
||||
);
|
||||
$bar.append(
|
||||
$blockTimeline = Ox.BlockVideoTimeline({
|
||||
duration: 6336.08,
|
||||
find: 'brick',
|
||||
getTimelineURL: function(i) {
|
||||
return 'png/timeline.16.' + i + '.png';
|
||||
},
|
||||
'in': 3128.725,
|
||||
out: 3130.725,
|
||||
results: results,
|
||||
subtitles: subtitles,
|
||||
width: 353
|
||||
})
|
||||
.css({
|
||||
position: 'absolute',
|
||||
left: '16px',
|
||||
top: '16px'
|
||||
})
|
||||
.bindEvent('position', function(data) {
|
||||
$videos[2].options({
|
||||
position: data.position
|
||||
});
|
||||
})
|
||||
);
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
|
|
|
@ -331,7 +331,7 @@ Ox.Element = function() {
|
|||
Ox.forEach(Ox.makeObject(arguments), function(data, event) {
|
||||
if ([
|
||||
'mousedown', 'mouserepeat', 'anyclick', 'singleclick', 'doubleclick',
|
||||
'dragstart', 'drag', 'dragpause', 'dragend', 'playing', 'progress'
|
||||
'dragstart', 'drag', 'dragpause', 'dragend', 'playing', 'position', 'progress'
|
||||
].indexOf(event) == -1) {
|
||||
Ox.print(that.id, self.options.id, 'trigger', event, data);
|
||||
}
|
||||
|
|
|
@ -516,7 +516,7 @@ Ox.Input = function(options, self) {
|
|||
Ox.UI.$document.unbind('keydown', keypress);
|
||||
Ox.UI.$document.unbind('keypress', keypress);
|
||||
}
|
||||
that.triggerEvent('blur', {});
|
||||
that.triggerEvent('blur');
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
|
@ -602,6 +602,7 @@ Ox.Input = function(options, self) {
|
|||
Ox.UI.$document.keypress(keypress);
|
||||
self.options.autocompleteSelect && setTimeout(autocomplete, 0); // fixme: why is the timeout needed?
|
||||
}
|
||||
that.triggerEvent('focus');
|
||||
}
|
||||
|
||||
function getInputWidth() {
|
||||
|
|
|
@ -4,7 +4,6 @@ Ox.BlockTimeline = function(options, self) {
|
|||
var self = self || {},
|
||||
that = new Ox.Element({}, self)
|
||||
.defaults({
|
||||
cuts: [],
|
||||
duration: 0,
|
||||
find: '',
|
||||
matches: [],
|
||||
|
@ -113,7 +112,7 @@ Ox.BlockTimeline = function(options, self) {
|
|||
.appendTo(self.$lines[i].$element);
|
||||
}
|
||||
if (self.options.points[0] != self.options.points[1]) {
|
||||
addSelection[i];
|
||||
addSelection(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
246
source/Ox.UI/js/Video/Ox.BlockVideoTimeline.js
Normal file
246
source/Ox.UI/js/Video/Ox.BlockVideoTimeline.js
Normal file
|
@ -0,0 +1,246 @@
|
|||
Ox.BlockVideoTimeline = function(options, self) {
|
||||
|
||||
self = self || {};
|
||||
var that = new Ox.Element({}, self)
|
||||
.defaults({
|
||||
duration: 0,
|
||||
find: '',
|
||||
getTimelineURL: null,
|
||||
'in': 0,
|
||||
out: 0,
|
||||
position: 0,
|
||||
results: [],
|
||||
subtitles: [],
|
||||
width: 0
|
||||
})
|
||||
.options(options || {})
|
||||
.css({
|
||||
position: 'absolute',
|
||||
})
|
||||
.bind({
|
||||
mousedown: mousedown,
|
||||
mouseleave: mouseleave,
|
||||
mousemove: mousemove
|
||||
})
|
||||
.bindEvent({
|
||||
drag: function(event, e) {
|
||||
mousedown(e);
|
||||
}
|
||||
});
|
||||
|
||||
self.$images = [];
|
||||
self.$interfaces = [];
|
||||
self.$lines = [];
|
||||
self.$tooltip = new Ox.Tooltip({
|
||||
animate: false
|
||||
}).css({
|
||||
textAlign: 'center'
|
||||
});
|
||||
self.height = 16;
|
||||
self.lines = getLines();
|
||||
self.margin = 8;
|
||||
|
||||
setCSS();
|
||||
|
||||
Ox.loop(self.lines, function(i) {
|
||||
addLine(i);
|
||||
});
|
||||
|
||||
self.$positionMarker = $('<img>')
|
||||
.attr({
|
||||
src: Ox.UI.PATH + 'png/videoMarkerPlay.png'
|
||||
})
|
||||
.css({
|
||||
position: 'absolute',
|
||||
width: '9px',
|
||||
height: '5px',
|
||||
zIndex: 10
|
||||
})
|
||||
.appendTo(that.$element);
|
||||
setPositionMarker();
|
||||
|
||||
self.$pointMarker = {};
|
||||
['in', 'out'].forEach(function(point) {
|
||||
var titleCase = Ox.toTitleCase(point);
|
||||
self.$pointMarker[point] = $('<img>')
|
||||
.addClass('OxPointMarker' + titleCase)
|
||||
.attr({
|
||||
src: Ox.UI.PATH + 'png/videoMarker' + titleCase + '.png'
|
||||
})
|
||||
.css({
|
||||
position: 'absolute',
|
||||
width: '6px',
|
||||
height: '6px',
|
||||
marginLeft: (point == 'in' ? -1 : 4) + 'px',
|
||||
zIndex: 10
|
||||
})
|
||||
.appendTo(that.$element);
|
||||
setPointMarker(point);
|
||||
});
|
||||
|
||||
function addLine(i) {
|
||||
self.$lines[i] = $('<div>')
|
||||
.css({
|
||||
position: 'absolute',
|
||||
left: (self.margin / 2) + 'px',
|
||||
top: i * (self.height + self.margin) + 'px',
|
||||
width: self.options.width + 'px',
|
||||
height: '24px',
|
||||
overflow: 'hidden'
|
||||
})
|
||||
.appendTo(that.$element);
|
||||
self.$images[i] = Ox.SmallVideoTimelineImages({
|
||||
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: Math.ceil(self.options.duration),
|
||||
type: self.options.type
|
||||
})
|
||||
.css({
|
||||
position: 'absolute',
|
||||
marginLeft: (-i * self.options.width) + 'px'
|
||||
})
|
||||
.appendTo(self.$lines[i]);
|
||||
self.$interfaces[i] = $('<div>').addClass('OxInterface')
|
||||
.css({
|
||||
position: 'absolute',
|
||||
top: '2px',
|
||||
width: Math.ceil(self.options.duration) + 'px',
|
||||
height: '20px',
|
||||
marginLeft: (-i * self.options.width) + 'px',
|
||||
zIndex: 11
|
||||
})
|
||||
.appendTo(self.$lines[i]);
|
||||
}
|
||||
|
||||
function getLines() {
|
||||
return Math.ceil(self.options.duration / self.options.width);
|
||||
}
|
||||
|
||||
function getPosition(e) {
|
||||
//FIXME: this might still be broken in opera according to http://acko.net/blog/mouse-handling-and-absolute-positions-in-javascript
|
||||
return (e.offsetX ? e.offsetX : e.clientX - $(e.target).offset().left);
|
||||
}
|
||||
|
||||
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();
|
||||
// fixme: check if this pattern is better
|
||||
// than the one used for list selection
|
||||
if (!self.triggered) {
|
||||
Ox.print('$$$$$$$$$$$$$$$')
|
||||
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 ?
|
||||
'<span class=\'OxBright\'>' +
|
||||
Ox.highlight(subtitle.text, self.options.find, 'OxHighlight').replace(/\n/g, '<br/>') +
|
||||
'</span><br/>' +
|
||||
Ox.formatDuration(subtitle['in'], 3) + ' - ' + Ox.formatDuration(subtitle['out'], 3) :
|
||||
Ox.formatDuration(position, 3)
|
||||
})
|
||||
.show(e.clientX, e.clientY);
|
||||
|
||||
} else {
|
||||
self.$tooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function setCSS() {
|
||||
that.css({
|
||||
width: (self.options.width + self.margin) + 'px',
|
||||
height: ((self.height + self.margin) * self.lines) + 'px'
|
||||
});
|
||||
}
|
||||
|
||||
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) *
|
||||
(self.height + self.margin) + 16) + 'px'
|
||||
});
|
||||
}
|
||||
|
||||
function setPositionMarker() {
|
||||
self.$positionMarker.css({
|
||||
left: (self.options.position % self.options.width) + 'px',
|
||||
top: (parseInt(self.options.position / self.options.width) *
|
||||
(self.height + self.margin) + 2) + 'px'
|
||||
});
|
||||
}
|
||||
|
||||
function setWidth() {
|
||||
self.lines = getLines();
|
||||
setCSS();
|
||||
Ox.loop(self.lines, function(i) {
|
||||
if (self.$lines[i]) {
|
||||
self.$lines[i].css({
|
||||
width: self.options.width + 'px'
|
||||
});
|
||||
self.$images[i].css({
|
||||
marginLeft: (-i * self.options.width) + 'px'
|
||||
});
|
||||
self.$interfaces[i].css({
|
||||
marginLeft: (-i * self.options.width) + 'px'
|
||||
});
|
||||
} else {
|
||||
addLine(i);
|
||||
}
|
||||
});
|
||||
while (self.$lines.length > self.lines) {
|
||||
self.$lines[self.$lines.length - 1].remove();
|
||||
self.$lines.pop();
|
||||
self.$images.pop();
|
||||
}
|
||||
setPositionMarker();
|
||||
setPointMarker('in');
|
||||
setPointMarker('out');
|
||||
}
|
||||
|
||||
self.setOption = function(key, value) {
|
||||
if (key == 'position') {
|
||||
setPositionMarker();
|
||||
} else if (key == 'width') {
|
||||
setWidth();
|
||||
}
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
};
|
54
source/Ox.UI/js/Video/Ox.SmallVideoTimeline.js
Normal file
54
source/Ox.UI/js/Video/Ox.SmallVideoTimeline.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
Ox.SmallVideoTimeline = function(options, self) {
|
||||
|
||||
self = self || {};
|
||||
var that = Ox.Element({}, self)
|
||||
.defaults({
|
||||
duration: 0,
|
||||
editing: false,
|
||||
getTimelineURL: null,
|
||||
'in': 0,
|
||||
out: 0,
|
||||
width: 256,
|
||||
type: 'player'
|
||||
})
|
||||
.options(options || {})
|
||||
.addClass('OxSmallVideoTimeline')
|
||||
.css({
|
||||
width: self.options.width + 'px'
|
||||
});
|
||||
|
||||
self.height = self.options.type == 'player' ? 16 : 24;
|
||||
self.imageHeight = self.options.type == 'player' ? 16 : 18;
|
||||
self.imageTop = self.options.type == 'player' ? 0 : 3;
|
||||
|
||||
that.css({
|
||||
height: self.height + 'px'
|
||||
});
|
||||
|
||||
self.tooltip = Ox.Tooltip({
|
||||
animate: false
|
||||
}).css({
|
||||
textAlign: 'center'
|
||||
});
|
||||
|
||||
getImageURL('timeline', function(timelineURL) {
|
||||
|
||||
$('<img>')
|
||||
.attr({
|
||||
src: timelineURL
|
||||
})
|
||||
.css({
|
||||
width: self.options.width + 'px',
|
||||
height: self.imageHeight + 'px',
|
||||
top: self.imageTop + 'px'
|
||||
})
|
||||
.appendTo(that.$element);
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
return that;
|
||||
|
||||
};
|
187
source/Ox.UI/js/Video/Ox.SmallVideoTimelineImages.js
Normal file
187
source/Ox.UI/js/Video/Ox.SmallVideoTimelineImages.js
Normal file
|
@ -0,0 +1,187 @@
|
|||
Ox.SmallVideoTimelineImages = function(options, self) {
|
||||
|
||||
self = self || {};
|
||||
var that = Ox.Element({}, self)
|
||||
.defaults({
|
||||
duration: 0,
|
||||
editing: false,
|
||||
getTimelineURL: null,
|
||||
'in': 0,
|
||||
out: 0,
|
||||
results: [],
|
||||
subtitles: [],
|
||||
width: 256,
|
||||
type: 'player'
|
||||
})
|
||||
.options(options || {})
|
||||
.addClass('OxSmallVideoTimeline')
|
||||
.css({
|
||||
position: 'absolute',
|
||||
width: self.options.width + 'px'
|
||||
});
|
||||
|
||||
self.height = self.options.type == 'player' ? 16 : 24;
|
||||
self.imageHeight = self.options.type == 'player' ? 16 : 18;
|
||||
self.imageTop = self.options.type == 'player' ? 0 : 3;
|
||||
|
||||
that.css({
|
||||
height: self.height + 'px'
|
||||
});
|
||||
|
||||
self.$timeline = $('<img>')
|
||||
.attr({
|
||||
src: Ox.UI.PATH + 'png/transparent.png'
|
||||
})
|
||||
.css({
|
||||
position: 'absolute',
|
||||
width: self.options.width + 'px',
|
||||
height: self.imageHeight + 'px',
|
||||
top: self.imageTop + 'px'
|
||||
})
|
||||
.appendTo(that.$element);
|
||||
|
||||
getImageURL('timeline', function(imageURL) {
|
||||
self.$timeline.attr({
|
||||
src: imageURL
|
||||
});
|
||||
});
|
||||
|
||||
self.$subtitles = $('<img>')
|
||||
.attr({
|
||||
src: getImageURL('subtitles')
|
||||
})
|
||||
.css({
|
||||
position: 'absolute',
|
||||
width: self.options.width + 'px',
|
||||
height: self.imageHeight + 'px',
|
||||
top: self.imageTop + 'px'
|
||||
})
|
||||
.appendTo(that.$element);
|
||||
|
||||
self.$results = $('<img>')
|
||||
.attr({
|
||||
src: getImageURL('results')
|
||||
})
|
||||
.css({
|
||||
position: 'absolute',
|
||||
width: self.options.width + 'px',
|
||||
height: self.imageHeight + 'px',
|
||||
top: self.imageTop + 'px'
|
||||
})
|
||||
.appendTo(that.$element);
|
||||
|
||||
self.$selection = $('<img>')
|
||||
.attr({
|
||||
src: getImageURL('selection')
|
||||
})
|
||||
.css({
|
||||
position: 'absolute',
|
||||
width: self.options.width + 'px',
|
||||
height: self.imageHeight + 'px',
|
||||
top: self.imageTop + 'px'
|
||||
})
|
||||
.appendTo(that.$element);
|
||||
|
||||
function getImageURL(image, callback) {
|
||||
var width = Math.ceil(self.options.duration),
|
||||
height = self.imageHeight,
|
||||
canvas = $('<canvas>')
|
||||
.attr({
|
||||
width: width,
|
||||
height: height
|
||||
})[0],
|
||||
context = canvas.getContext('2d'),
|
||||
imageData = context.createImageData(width, height),
|
||||
data = imageData.data;
|
||||
if (image == 'results') {
|
||||
var top = 0,
|
||||
bottom = height;
|
||||
self.options.results.forEach(function(result) {
|
||||
var left = Math.round(result['in']),
|
||||
right = Math.round(result.out) + 1;
|
||||
Ox.loop(left, right, function(x) {
|
||||
Ox.loop(top, bottom, function(y) {
|
||||
var color = (y == top || y == bottom - 1) ? [255, 255, 0, 255] : [255, 255, 0, 64],
|
||||
index = x * 4 + y * 4 * width;
|
||||
data[index] = color[0];
|
||||
data[index + 1] = color[1];
|
||||
data[index + 2] = color[2];
|
||||
data[index + 3] = color[3];
|
||||
});
|
||||
});
|
||||
});
|
||||
} else if (image == 'selection') {
|
||||
var left = Math.round(self.options['in']),
|
||||
right = Math.round(self.options.out) + 1,
|
||||
top = 0,
|
||||
bottom = height,
|
||||
rgb = self.options.editing ? [128, 255, 255] : [255, 255, 255];
|
||||
Ox.loop(left, right, function(x) {
|
||||
Ox.loop(top, bottom, function(y) {
|
||||
var color = [rgb[0], rgb[1], rgb[2], (y == top || y == bottom - 1) ? 255 : 64],
|
||||
index = x * 4 + y * 4 * width;
|
||||
data[index] = color[0];
|
||||
data[index + 1] = color[1];
|
||||
data[index + 2] = color[2];
|
||||
data[index + 3] = color[3];
|
||||
});
|
||||
});
|
||||
} else if (image == 'subtitles') {
|
||||
var bottom = self.options.type == 'player' ? 14 : 15;
|
||||
self.options.subtitles.forEach(function(subtitle) {
|
||||
var left = Math.round(subtitle['in']),
|
||||
right = Math.round(subtitle.out) + 1,
|
||||
top = bottom - subtitle.text.split('\n').length - 2;
|
||||
Ox.loop(left, right, function(x) {
|
||||
Ox.loop(top, bottom, function(y) {
|
||||
var color = (y == top || y == bottom - 1) ? [0, 0, 0] : [255, 255, 255],
|
||||
index = x * 4 + y * 4 * width;
|
||||
data[index] = color[0];
|
||||
data[index + 1] = color[1];
|
||||
data[index + 2] = color[2];
|
||||
data[index + 3] = 128;
|
||||
});
|
||||
});
|
||||
});
|
||||
} else if (image == 'timeline') {
|
||||
var counter = 0,
|
||||
images = Math.ceil(self.options.duration / 3600),
|
||||
top = self.options.type == 'player' ? 0 : 1;
|
||||
Ox.loop(images, function(i) {
|
||||
var $image = $('<img>')
|
||||
.attr({
|
||||
src: self.options.getTimelineURL(i)
|
||||
})
|
||||
.load(function() {
|
||||
context.drawImage($image[0], i * 3600, top);
|
||||
if (++counter == images) {
|
||||
callback(canvas.toDataURL());
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
if (image != 'timeline') {
|
||||
context.putImageData(imageData, 0, 0);
|
||||
return canvas.toDataURL();
|
||||
}
|
||||
}
|
||||
|
||||
self.setOption = function(key, value) {
|
||||
if (key == 'in' || key == 'out') {
|
||||
self.$selection.attr({
|
||||
src: getImageURL('selection')
|
||||
});
|
||||
} else if (key == 'results') {
|
||||
self.$results.attr({
|
||||
src: getImageURL('results')
|
||||
});
|
||||
} else if (key == 'subtitles') {
|
||||
self.$subtitles.attr({
|
||||
src: getImageURL('subtitles')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
}
|
|
@ -16,6 +16,7 @@ Ox.VideoPlayer <f> Generic Video Player
|
|||
duration <n|-1> Duration (sec)
|
||||
enableKeyboard <b|false> If true, enable keyboard controls
|
||||
externalControls <b|false> If true, controls are outside the video
|
||||
find <s|''> Query string
|
||||
focus <s|'click'> focus on 'click', 'load' or 'mouseover'
|
||||
fps <n|25> Frames per second
|
||||
fullscreen <b|false> If true, video is in fullscreen
|
||||
|
@ -68,6 +69,7 @@ Ox.VideoPlayer = function(options, self) {
|
|||
duration: 86399,
|
||||
enableKeyboard: false,
|
||||
externalControls: false,
|
||||
find: '',
|
||||
focus: 'click',
|
||||
fps: 25,
|
||||
fullscreen: false,
|
||||
|
@ -143,7 +145,7 @@ Ox.VideoPlayer = function(options, self) {
|
|||
setPosition(self.options.position + self.secondsPerFrame, true);
|
||||
},
|
||||
key_shift_f: function() {
|
||||
toggleFullscreen();
|
||||
toggleFullscreen(true);
|
||||
},
|
||||
key_space: function() {
|
||||
togglePaused(true);
|
||||
|
@ -154,8 +156,14 @@ Ox.VideoPlayer = function(options, self) {
|
|||
if (self.options.enableKeyboard) {
|
||||
if (self.options.focus == 'mouseenter') {
|
||||
that.bind({
|
||||
mouseenter: that.gainFocus,
|
||||
mouseleave: that.loseFocus
|
||||
mouseenter: function() {
|
||||
if (!self.inputHasFocus) {
|
||||
that.gainFocus();
|
||||
}
|
||||
},
|
||||
mouseleave: function() {
|
||||
that.loseFocus();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
that.bind({
|
||||
|
@ -164,10 +172,21 @@ Ox.VideoPlayer = function(options, self) {
|
|||
}
|
||||
}
|
||||
|
||||
if ((!self.options.externalControls && self.options.controls.length) || self.options.showIcon || self.options.title) {
|
||||
if (
|
||||
(!self.options.externalControls && self.options.controls.length) ||
|
||||
self.options.showIcon || self.options.title
|
||||
) {
|
||||
that.bind({
|
||||
mouseenter: showInterface,
|
||||
mouseleave: hideInterface
|
||||
mouseenter: function() {
|
||||
showInterface();
|
||||
self.mouseHasLeft = false;
|
||||
Ox.print('MOUSE HAS ENTERED')
|
||||
},
|
||||
mouseleave: function() {
|
||||
hideInterface();
|
||||
self.mouseHasLeft = true;
|
||||
Ox.print('MOUSE HAS LEFT')
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -300,7 +319,7 @@ Ox.VideoPlayer = function(options, self) {
|
|||
}
|
||||
|
||||
if (self.options.title) {
|
||||
self.$titlebar = $('<div>')
|
||||
self.$title = $('<div>')
|
||||
.addClass('OxInterface')
|
||||
.css({
|
||||
position: 'absolute',
|
||||
|
@ -388,7 +407,9 @@ Ox.VideoPlayer = function(options, self) {
|
|||
type: 'image'
|
||||
})
|
||||
.css({float: 'left'})
|
||||
.bindEvent('click', toggleMuted)
|
||||
.bindEvent('click', function() {
|
||||
toggleMuted();
|
||||
})
|
||||
.appendTo(self.$controls);
|
||||
|
||||
} else if (control == 'volume') {
|
||||
|
@ -420,7 +441,9 @@ Ox.VideoPlayer = function(options, self) {
|
|||
type: 'image'
|
||||
})
|
||||
.css({float: 'left'})
|
||||
.bindEvent('click', toggleFullscreen)
|
||||
.bindEvent('click', function() {
|
||||
toggleFullscreen();
|
||||
})
|
||||
.appendTo(self.$controls);
|
||||
|
||||
} else if (control == 'size') {
|
||||
|
@ -576,12 +599,6 @@ Ox.VideoPlayer = function(options, self) {
|
|||
MozBoxShadow: '0 0 0',
|
||||
WebkitBoxShadow: '0 0 0'
|
||||
})
|
||||
.bind({
|
||||
blur: function() {
|
||||
},
|
||||
focus: function() {
|
||||
}
|
||||
})
|
||||
.bindEvent({
|
||||
focus: function() {
|
||||
self.inputHasFocus = true;
|
||||
|
@ -618,6 +635,11 @@ Ox.VideoPlayer = function(options, self) {
|
|||
|
||||
setSizes();
|
||||
|
||||
function clearInterfaceTimeout() {
|
||||
clearTimeout(self.interfaceTimeout);
|
||||
self.interfaceTimeout = 0;
|
||||
}
|
||||
|
||||
function ended() {
|
||||
if (!self.options.paused) {
|
||||
togglePaused(true);
|
||||
|
@ -643,7 +665,7 @@ Ox.VideoPlayer = function(options, self) {
|
|||
|
||||
function getCSS(element) {
|
||||
var css;
|
||||
if (element == 'controls' || element == 'titlebar') {
|
||||
if (element == 'controls' || element == 'title') {
|
||||
css = {
|
||||
width: self.width + 'px'
|
||||
};
|
||||
|
@ -655,11 +677,11 @@ Ox.VideoPlayer = function(options, self) {
|
|||
height: self.iconSize + 'px'
|
||||
};
|
||||
} else if (element == 'logo') {
|
||||
var logoHeight = Math.round(self.height / 10);
|
||||
self.logoMargin = Math.round(self.height / 20);
|
||||
var logoHeight = Math.round(self.height / 10),
|
||||
logoMargin = Math.round(self.height / 20);
|
||||
css = {
|
||||
left: self.logoMargin + 'px',
|
||||
top: self.logoMargin + 'px',
|
||||
left: logoMargin + 'px',
|
||||
top: (logoMargin + !!self.titleIsVisible * 16) + 'px',
|
||||
height: logoHeight + 'px',
|
||||
};
|
||||
} else if (element == 'player') {
|
||||
|
@ -727,7 +749,7 @@ Ox.VideoPlayer = function(options, self) {
|
|||
};
|
||||
} else if (element == 'subtitle') {
|
||||
css = {
|
||||
bottom: parseInt(self.height / 16) + 'px',
|
||||
bottom: (parseInt(self.height / 16) + !!self.controlsAreVisible * 16) + 'px',
|
||||
width: self.width + 'px',
|
||||
fontSize: parseInt(self.height / 20) + 'px',
|
||||
WebkitTextStroke: (self.height / 1000) + 'px rgb(0, 0, 0)'
|
||||
|
@ -811,7 +833,7 @@ Ox.VideoPlayer = function(options, self) {
|
|||
v['in'] <= self.options.position &&
|
||||
v.out > self.options.position
|
||||
) {
|
||||
subtitle = v.text;
|
||||
subtitle = Ox.highlight(v.text, self.options.find, 'OxHighlight');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
@ -819,13 +841,16 @@ Ox.VideoPlayer = function(options, self) {
|
|||
}
|
||||
|
||||
function hideInterface() {
|
||||
if (!self.inputHasFocus) {
|
||||
self.controlsTimeout = setTimeout(function() {
|
||||
Ox.print('hideInterface');
|
||||
self.interfaceTimeout = setTimeout(function() {
|
||||
if (!self.exitFullscreen && !self.inputHasFocus && !self.mouseIsInControls) {
|
||||
self.titleIsVisible = false;
|
||||
self.controlsAreVisible = false;
|
||||
that.find('.OxInterface').animate({
|
||||
opacity: 0
|
||||
}, 250);
|
||||
self.$logo && self.$logo.animate({
|
||||
top: self.logoMargin + 'px',
|
||||
top: getCSS('logo').top,
|
||||
opacity: 0.25
|
||||
}, 250, function() {
|
||||
self.options.logoLink && self.$logo.unbind('click');
|
||||
|
@ -833,10 +858,10 @@ Ox.VideoPlayer = function(options, self) {
|
|||
self.$logo.unbind('mouseenter').unbind('mouseleave');
|
||||
});
|
||||
self.$subtitle && self.$subtitle.animate({
|
||||
bottom: parseInt(self.options.height / 16) + 'px',
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
bottom: getCSS('subtitle').bottom,
|
||||
}, 250);
|
||||
}
|
||||
}, self.options.fullscreen ? 2500 : 1000);
|
||||
}
|
||||
|
||||
function hideLoadingIcon() {
|
||||
|
@ -932,6 +957,9 @@ Ox.VideoPlayer = function(options, self) {
|
|||
} else {
|
||||
setPosition(self.options.position);
|
||||
}
|
||||
that.triggerEvent('position', {
|
||||
position: self.options.position
|
||||
});
|
||||
}
|
||||
|
||||
function playInToOut() {
|
||||
|
@ -1020,7 +1048,7 @@ 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.$titlebar && self.$titlebar.animate(getCSS('titlebar'), ms);
|
||||
self.$title && self.$title.animate(getCSS('title'), ms);
|
||||
self.$controls && self.$controls.animate(getCSS('controls'), ms);
|
||||
if (self.$timeline) {
|
||||
self.$timeline.animate(getCSS('timeline'), ms);
|
||||
|
@ -1045,12 +1073,19 @@ Ox.VideoPlayer = function(options, self) {
|
|||
}
|
||||
|
||||
function showInterface() {
|
||||
clearTimeout(self.controlsTimeout);
|
||||
Ox.print('showInterface');
|
||||
clearTimeout(self.interfaceTimeout);
|
||||
if (self.$title) {
|
||||
self.titleIsVisible = true;
|
||||
}
|
||||
if (self.$controls) {
|
||||
self.controlsAreVisible = true;
|
||||
}
|
||||
that.find('.OxInterface').animate({
|
||||
opacity: 1
|
||||
}, 250);
|
||||
self.$logo && self.$logo.animate({
|
||||
top: self.logoMargin + 16 + 'px',
|
||||
top: getCSS('logo').top,
|
||||
opacity: 0.5
|
||||
}, 250, function() {
|
||||
self.options.logoLink && self.$logo
|
||||
|
@ -1067,9 +1102,9 @@ Ox.VideoPlayer = function(options, self) {
|
|||
mouseleave: self.$logoTooltip.hide
|
||||
});
|
||||
});
|
||||
self.$subtitle.animate({
|
||||
bottom: self.barHeight + parseInt(self.options.height / 16) + 'px',
|
||||
});
|
||||
self.$subtitle && self.$subtitle.animate({
|
||||
bottom: getCSS('subtitle').bottom,
|
||||
}, 250);
|
||||
}
|
||||
|
||||
function showLoadingIcon() {
|
||||
|
@ -1088,12 +1123,17 @@ Ox.VideoPlayer = function(options, self) {
|
|||
self.video.play();
|
||||
self.wasPlaying = false;
|
||||
}
|
||||
if (self.focus == 'mouseenter' && !self.mouseHasLeft) {
|
||||
that.gainFocus();
|
||||
}
|
||||
self.mouseHasLeft && hideInterface();
|
||||
}
|
||||
|
||||
function toggleFullscreen() {
|
||||
function toggleFullscreen(toggleButton) {
|
||||
var parentOffset, wasPlaying;
|
||||
self.options.fullscreen = !self.options.fullscreen;
|
||||
if (!self.options.paused) {
|
||||
// video won't keep playing accross detach/append
|
||||
self.video.pause();
|
||||
wasPlaying = true;
|
||||
}
|
||||
|
@ -1114,10 +1154,36 @@ Ox.VideoPlayer = function(options, self) {
|
|||
.appendTo(Ox.UI.$body);
|
||||
setSizes(function() {
|
||||
wasPlaying && self.video.play();
|
||||
that.bind({
|
||||
mousemove: function() {
|
||||
if (!self.mouseIsInControls) {
|
||||
showInterface();
|
||||
hideInterface();
|
||||
}
|
||||
}
|
||||
});
|
||||
self.$controls && self.$controls.bind({
|
||||
mouseenter: function() {
|
||||
self.mouseIsInControls = true;
|
||||
},
|
||||
mouseleave: function() {
|
||||
self.mouseIsInControls = false;
|
||||
}
|
||||
});
|
||||
showInterface();
|
||||
hideInterface();
|
||||
});
|
||||
} else {
|
||||
// flag makes the animation end on absolute position
|
||||
self.exitFullscreen = true;
|
||||
that.unbind('mousemove');
|
||||
self.$controls && self.$controls
|
||||
.trigger('mouseleave')
|
||||
.unbind('mouseenter')
|
||||
.unbind('mouseleave');
|
||||
Ox.print('???', self.mouseIsInControls);
|
||||
setSizes(function() {
|
||||
self.exitFullscreen = false;
|
||||
that.detach()
|
||||
.css({
|
||||
left: self.relativeOffset.left + 'px',
|
||||
|
@ -1125,17 +1191,24 @@ Ox.VideoPlayer = function(options, self) {
|
|||
})
|
||||
.appendTo(self.$parent);
|
||||
wasPlaying && self.video.play();
|
||||
self.exitFullscreen = false;
|
||||
self.options.enableKeyboard && that.gainFocus();
|
||||
//showInterface();
|
||||
});
|
||||
}
|
||||
if (toggleButton && self.$fullscreenButton) {
|
||||
self.$fullscreenButton.toggleTitle();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleMuted() {
|
||||
function toggleMuted(toggleButton) {
|
||||
self.options.muted = !self.options.muted;
|
||||
self.video.muted = self.options.muted;
|
||||
if (toggleButton && self.$muteButton) {
|
||||
self.$muteButton.toggleTitle();
|
||||
}
|
||||
}
|
||||
|
||||
function togglePaused(togglePlayButton) {
|
||||
function togglePaused(toggleButton) {
|
||||
self.options.paused = !self.options.paused;
|
||||
self.$timeline && self.$positionMarkerRing.css({
|
||||
borderColor: 'rgba(255, 255, 255, ' + (self.options.paused ? 0.5 : 1) + ')'
|
||||
|
@ -1161,7 +1234,7 @@ Ox.VideoPlayer = function(options, self) {
|
|||
}, 250, togglePlayIcon);
|
||||
}
|
||||
}
|
||||
if (togglePlayButton && self.$playButton) {
|
||||
if (toggleButton && self.$playButton) {
|
||||
self.$playButton.toggleTitle();
|
||||
}
|
||||
}
|
||||
|
@ -1174,10 +1247,13 @@ Ox.VideoPlayer = function(options, self) {
|
|||
});
|
||||
}
|
||||
|
||||
function toggleScale() {
|
||||
function toggleScale(toggleButton) {
|
||||
self.options.scaleToFill = !self.options.scaleToFill;
|
||||
self.$video.animate(getCSS('video'), 250);
|
||||
self.$poster && self.$poster.animate(getCSS('poster'), 250);
|
||||
if (toggleButton && self.$scaleButton) {
|
||||
self.$scaleButton.toggleTitle();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSize() {
|
||||
|
@ -1189,18 +1265,17 @@ Ox.VideoPlayer = function(options, self) {
|
|||
|
||||
self.setOption = function(key, value) {
|
||||
if (key == 'fullscreen') {
|
||||
toggleFullscreen();
|
||||
toggleFullscreen(true);
|
||||
} else if (key == 'height' || key == 'width') {
|
||||
setSizes();
|
||||
} else if (key == 'muted') {
|
||||
toggleMuted();
|
||||
self.$muteButton && self.$muteButton.toggleTitle();
|
||||
toggleMuted(true);
|
||||
} else if (key == 'paused') {
|
||||
togglePaused(true);
|
||||
} else if (key == 'position') {
|
||||
setPosition(value);
|
||||
setPosition(value, true);
|
||||
} else if (key == 'scaleToFill') {
|
||||
self.$video.css(getVideoCSS());
|
||||
toggleScale(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue