oxjs/source/Ox.UI/js/Video/BlockVideoTimeline.js

341 lines
10 KiB
JavaScript
Raw Normal View History

2011-11-05 16:46:53 +00:00
'use strict';
2012-05-21 10:38:18 +00:00
/*@
2012-05-31 10:32:54 +00:00
Ox.BlockVideoTimeline <f> Block Video Timeline
options <o> Options
self <o> Shared private variable
2012-05-31 10:32:54 +00:00
([options[, self]]) -> <o:Ox.Element> Block Video Timeline
2012-06-17 22:38:26 +00:00
edit <!> edit
select <!> select
position <!> position
2012-05-21 10:38:18 +00:00
@*/
2011-05-15 16:18:58 +00:00
Ox.BlockVideoTimeline = function(options, self) {
self = self || {};
var that = Ox.Element({}, self)
2011-05-15 16:18:58 +00:00
.defaults({
duration: 0,
find: '',
2011-05-18 16:00:29 +00:00
getImageURL: null,
2011-05-15 16:18:58 +00:00
'in': 0,
out: 0,
position: 0,
results: [],
2011-10-17 10:23:16 +00:00
showPointMarkers: false,
state: 'default',
2011-05-15 16:18:58 +00:00
subtitles: [],
type: '',
2011-05-15 16:18:58 +00:00
width: 0
})
.options(options || {})
2012-05-28 19:35:41 +00:00
.update({
'in': function() {
self.options.showPointMarkers && setPoint('in');
},
out: function() {
self.options.showPointMarkers && setPoint('out');
},
position: setPositionMarker,
results: setResults,
subtitles: setSubtitles,
state: setState,
2012-06-15 13:20:07 +00:00
type: setType,
2012-05-28 19:35:41 +00:00
width: setWidth
})
.addClass('OxBlockVideoTimeline')
2011-05-15 16:18:58 +00:00
.css({
2012-05-26 15:48:19 +00:00
position: 'absolute'
2011-05-15 16:18:58 +00:00
})
2012-05-28 14:06:22 +00:00
.on({
2011-05-15 16:18:58 +00:00
mousedown: mousedown,
mouseleave: mouseleave,
mousemove: mousemove
})
.bindEvent({
2012-01-10 14:49:28 +00:00
doubleclick: doubleclick,
2011-09-17 11:49:29 +00:00
drag: function(data) {
mousedown(data);
2011-05-15 16:18:58 +00:00
}
});
self.$images = [];
self.$interfaces = [];
self.$lines = [];
self.$tooltip = Ox.Tooltip({
2012-03-14 10:35:46 +00:00
animate: false
})
.css({
textAlign: 'center'
});
2011-05-15 16:18:58 +00:00
self.height = 16;
self.lines = getLines();
self.margin = 8;
setCSS();
2012-06-15 13:20:07 +00:00
self.$image = getImage();
Ox.loop(self.lines, function(i) {
addLine(i);
});
2011-05-15 16:18:58 +00:00
2014-09-20 10:37:27 +00:00
self.$positionMarker = Ox.$('<img>')
2011-05-15 16:18:58 +00:00
.attr({
2014-09-25 10:28:47 +00:00
src: Ox.getImageURL('markerPosition')
2011-05-15 16:18:58 +00:00
})
.addClass('OxMarkerPosition')
.appendTo(that);
2011-05-15 16:18:58 +00:00
setPositionMarker();
2011-10-17 10:23:16 +00:00
if (self.options.showPointMarkers) {
self.$pointMarker = {};
['in', 'out'].forEach(function(point) {
var titlecase = Ox.toTitleCase(point);
2014-09-20 10:37:27 +00:00
self.$pointMarker[point] = Ox.$('<img>')
2011-10-17 10:23:16 +00:00
.addClass('OxMarkerPoint' + titlecase)
.attr({
2014-09-25 10:28:47 +00:00
src: Ox.getImageURL('marker' + titlecase)
2011-10-17 10:23:16 +00:00
})
.appendTo(that);
2011-10-17 10:23:16 +00:00
setPointMarker(point);
});
}
2011-05-15 16:18:58 +00:00
function addLine(i) {
2014-09-20 10:37:27 +00:00
self.$lines[i] = Ox.$('<div>')
2011-05-15 16:18:58 +00:00
.css({
position: 'absolute',
2012-03-14 10:35:46 +00:00
left: self.margin / 2 + 'px',
2011-05-15 16:18:58 +00:00
top: i * (self.height + self.margin) + 'px',
width: self.options.width + 'px',
height: '24px',
overflow: 'hidden'
})
.appendTo(that);
self.$images[i] = self.$image.clone()
2011-05-15 16:18:58 +00:00
.css({
position: 'absolute',
2012-03-14 10:35:46 +00:00
marginLeft: -i * self.options.width + 'px'
2011-05-15 16:18:58 +00:00
})
.appendTo(self.$lines[i]);
2014-09-20 10:37:27 +00:00
self.$interfaces[i] = Ox.$('<div>')
2011-10-17 10:23:16 +00:00
// OxTarget and OxSpecialTarget are needed for InfoList
.addClass('OxInterface OxTarget OxSpecialTarget')
2011-05-15 16:18:58 +00:00
.css({
top: '2px',
2011-05-18 18:30:58 +00:00
width: Math.round(self.options.duration) + 'px',
2011-05-15 16:18:58 +00:00
height: '20px',
2012-05-26 15:48:19 +00:00
marginLeft: -i * self.options.width + 'px'
2011-05-15 18:50:05 +00:00
//background: 'rgba(255, 0, 0, 0.1)',
2011-05-15 16:18:58 +00:00
})
.appendTo(self.$lines[i]);
}
2012-01-10 14:49:28 +00:00
function doubleclick(e) {
var position;
if ($(e.target).is('.OxInterface')) {
position = getPosition(e);
if (
self.options.state == 'selected'
&& position >= self.options['in']
&& position <= self.options.out
) {
that.triggerEvent('edit');
} else if (self.options.state != 'editing') {
that.triggerEvent('select');
}
}
}
2012-06-15 13:20:07 +00:00
function getImage() {
return Ox.SmallVideoTimelineImage({
duration: self.options.duration,
editing: self.options.editing,
imageURL: self.options.getImageURL,
'in': self.options['in'],
mode: 'editor',
out: self.options.out,
results: self.options.results,
state: self.options.state,
2013-10-22 17:43:38 +00:00
subtitles: Ox.clone(self.options.subtitles, true),
2012-06-15 13:20:07 +00:00
type: self.options.type,
width: Math.round(self.options.duration)
}).bindEvent({
loaded: updateTimelines
2012-06-15 13:20:07 +00:00
});
}
2011-05-15 16:18:58 +00:00
function getLines() {
return Math.ceil(self.options.duration / self.options.width);
}
function getPosition(e) {
2012-07-05 08:58:08 +00:00
// FIXME: this might still be broken in opera according to
// http://acko.net/blog/mouse-handling-and-absolute-positions-in-javascript
2012-03-14 10:35:46 +00:00
return e.offsetX ? e.offsetX
: e.clientX - $(e.target).offset().left;
2011-05-15 16:18:58 +00:00
}
function getSubtitle(position) {
var subtitle = '';
Ox.forEach(self.options.subtitles, function(v) {
if (v['in'] <= position && v.out > position) {
subtitle = v;
2012-07-05 08:58:08 +00:00
return false; // break
2011-05-15 16:18:58 +00:00
}
});
return subtitle;
}
2012-01-10 14:49:28 +00:00
function getTooltip(e) {
}
2011-05-15 16:18:58 +00:00
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) {
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({
2012-03-14 10:35:46 +00:00
title: subtitle
2012-06-03 09:07:35 +00:00
? '<span class=\'OxBright\'>' + Ox.highlight(
2012-06-15 16:26:18 +00:00
subtitle.text, self.options.find, 'OxHighlight', true
).replace(/\n/g, ' ') + '</span><br/>'
2012-06-03 08:41:18 +00:00
+ Ox.formatDuration(subtitle['in'], 3) + ' - '
2012-03-14 10:35:46 +00:00
+ Ox.formatDuration(subtitle['out'], 3)
: Ox.formatDuration(position)
2011-05-15 16:18:58 +00:00
})
.show(e.clientX, e.clientY);
} else {
self.$tooltip.hide();
}
}
function setCSS() {
that.css({
2013-06-02 20:19:36 +00:00
width: (self.options.width + self.margin) + 'px',
height: ((self.height + self.margin) * self.lines) + 4 + 'px'
// fixme: the + 4 represent the margin-bottom in the video editor
// is there a better way to get a proper margin-bottom?
2011-05-15 16:18:58 +00:00
});
}
2011-05-18 18:30:58 +00:00
function setPoint(point) {
setPointMarker(point);
self.$image.options(point, self.options[point]);
updateTimelines();
2011-05-18 18:30:58 +00:00
}
2011-05-15 16:18:58 +00:00
function setPointMarker(point) {
var position = Math.round(self.options[point]);
self.$pointMarker[point].css({
left: (position % self.options.width) + 'px',
top: (Math.floor(position / self.options.width) *
(self.height + self.margin) + 15) + 'px'
2011-05-15 16:18:58 +00:00
});
}
function setPositionMarker() {
var position = Math.round(self.options.position);
2011-05-15 16:18:58 +00:00
self.$positionMarker.css({
left: (position % self.options.width) - 1 + 'px',
top: (Math.floor(position / self.options.width) *
2011-05-15 16:18:58 +00:00
(self.height + self.margin) + 2) + 'px'
});
}
function setResults() {
self.$image.options({results: self.options.results});
updateTimelines();
}
function setState() {
self.$image.options({state: self.options.state});
updateTimelines();
}
function setSubtitles() {
2013-10-22 17:43:38 +00:00
self.$image.options({subtitles: Ox.clone(self.options.subtitles, true)});
updateTimelines();
}
2012-06-15 13:20:07 +00:00
function setType() {
self.$image = getImage();
self.$images.forEach(function($image, i) {
self.$images[i].replaceWith(
self.$images[i] = self.$image.clone()
.css({
position: 'absolute',
marginLeft: -i * self.options.width + 'px'
})
);
});
}
2011-05-15 16:18:58 +00:00
function setWidth() {
self.lines = getLines();
2013-06-02 20:19:36 +00:00
setCSS();
Ox.loop(self.lines, function(i) {
2011-05-15 16:18:58 +00:00
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();
2011-10-17 10:23:16 +00:00
if (self.options.showPointMarkers) {
setPointMarker('in');
setPointMarker('out');
}
2011-05-15 16:18:58 +00:00
}
function updateTimelines() {
self.$lines.forEach(function($line, i) {
$($line.children()[0]).replaceWith(
2012-06-15 13:20:07 +00:00
self.$images[i] = self.$image.clone().css({
position: 'absolute',
marginLeft: (-i * self.options.width) + 'px'
})
);
});
}
2011-05-15 16:18:58 +00:00
return that;
};