forked from 0x2620/oxjs
new-style find-as-you-type for video editor
This commit is contained in:
parent
d326adf2e9
commit
9f4f9dfa39
135 changed files with 9182 additions and 44 deletions
|
|
@ -154,8 +154,9 @@ Ox.Button = function(options, self) {
|
|||
@*/
|
||||
that.toggleDisabled = function() {
|
||||
that.options({
|
||||
enabled: !self.options.disabled
|
||||
disabled: !self.options.disabled
|
||||
});
|
||||
return that;
|
||||
//self.options.disabled = !self.options.disabled;
|
||||
}
|
||||
|
||||
|
|
@ -167,6 +168,7 @@ Ox.Button = function(options, self) {
|
|||
that.options({
|
||||
selected: !self.options.selected
|
||||
});
|
||||
return that;
|
||||
//self.options.selected = !self.options.selected;
|
||||
}
|
||||
|
||||
|
|
@ -180,6 +182,7 @@ Ox.Button = function(options, self) {
|
|||
self.$tooltip && self.$tooltip.options({
|
||||
title: self.tooltips[self.selectedTitle]
|
||||
});
|
||||
return that;
|
||||
}
|
||||
|
||||
return that;
|
||||
|
|
|
|||
|
|
@ -149,7 +149,6 @@ Ox.BlockVideoTimeline = function(options, self) {
|
|||
// 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
|
||||
});
|
||||
|
|
@ -197,15 +196,7 @@ Ox.BlockVideoTimeline = function(options, self) {
|
|||
function setPoint(point) {
|
||||
setPointMarker(point);
|
||||
self.$image.options(point, self.options[point]);
|
||||
self.$lines.forEach(function($line, i) {
|
||||
$($line.children()[0]).replaceWith(
|
||||
self.$images[i] = self.$image.clone()
|
||||
.css({
|
||||
position: 'absolute',
|
||||
marginLeft: (-i * self.options.width) + 'px'
|
||||
})
|
||||
);
|
||||
});
|
||||
updateTimelines();
|
||||
}
|
||||
|
||||
function setPointMarker(point) {
|
||||
|
|
@ -225,6 +216,11 @@ Ox.BlockVideoTimeline = function(options, self) {
|
|||
});
|
||||
}
|
||||
|
||||
function setResults() {
|
||||
self.$image.options({results: self.options.results});
|
||||
updateTimelines();
|
||||
}
|
||||
|
||||
function setWidth() {
|
||||
self.lines = getLines();
|
||||
setCSS();
|
||||
|
|
@ -253,11 +249,25 @@ Ox.BlockVideoTimeline = function(options, self) {
|
|||
setPointMarker('out');
|
||||
}
|
||||
|
||||
function updateTimelines() {
|
||||
self.$lines.forEach(function($line, i) {
|
||||
$($line.children()[0]).replaceWith(
|
||||
self.$images[i] = self.$image.clone()
|
||||
.css({
|
||||
position: 'absolute',
|
||||
marginLeft: (-i * self.options.width) + 'px'
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
self.setOption = function(key, value) {
|
||||
if (key == 'in' || key == 'out') {
|
||||
setPoint(key)
|
||||
} else if (key == 'position') {
|
||||
setPositionMarker();
|
||||
} else if (key == 'results') {
|
||||
setResults();
|
||||
} else if (key == 'width') {
|
||||
setWidth();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,10 +33,9 @@ Ox.VideoEditor = function(options, self) {
|
|||
showAnnotations: false,
|
||||
subtitles: [],
|
||||
videoHeight: 0,
|
||||
videoId: '',
|
||||
videoWidth: 0,
|
||||
videoSize: 'small',
|
||||
videoURL: '',
|
||||
video: '',
|
||||
width: 0
|
||||
})
|
||||
.options(options || {})
|
||||
|
|
@ -100,7 +99,7 @@ Ox.VideoEditor = function(options, self) {
|
|||
movePositionBy(self.options.duration);
|
||||
},
|
||||
key_shift_left: function() {
|
||||
movePositionBy(1);
|
||||
movePositionBy(-1);
|
||||
},
|
||||
key_shift_i: function() {
|
||||
goToPoint('in');
|
||||
|
|
@ -146,7 +145,7 @@ Ox.VideoEditor = function(options, self) {
|
|||
['play', 'in', 'out'].forEach(function(type, i) {
|
||||
self.$player[i] = new Ox.VideoPlayer({
|
||||
controlsBottom: type == 'play' ?
|
||||
['play', 'playInToOut', 'volume', 'size', 'space', 'position'] :
|
||||
['play', 'playInToOut', 'volume', 'space', 'position'] :
|
||||
['goto', 'set', 'space', 'position'],
|
||||
duration: self.options.duration,
|
||||
externalControls: true,
|
||||
|
|
@ -159,7 +158,7 @@ Ox.VideoEditor = function(options, self) {
|
|||
position: type == 'play' ? self.options.position : self.options[type],
|
||||
posterFrame: self.options.posterFrame,
|
||||
showMarkers: true,
|
||||
showMilliseconds: 2,
|
||||
showMilliseconds: 3,
|
||||
subtitles: self.options.subtitles,
|
||||
type: type,
|
||||
video: type == 'play' ? self.options.video : self.options.getFrameURL,
|
||||
|
|
@ -269,10 +268,255 @@ Ox.VideoEditor = function(options, self) {
|
|||
.appendTo(self.$annotations);
|
||||
});
|
||||
|
||||
that.$element = new Ox.SplitPanel({
|
||||
self.$menubar = Ox.Bar({
|
||||
size: 16
|
||||
}).addClass('OxVideoPlayer');
|
||||
|
||||
self.$sizeButton = Ox.Button({
|
||||
style: 'symbol',
|
||||
title: [
|
||||
{id: 'grow', title: 'grow', selected: self.options.size == 'small'},
|
||||
{id: 'shrink', title: 'shrink', selected: self.options.size == 'large'}
|
||||
],
|
||||
tooltip: ['Larger', 'Smaller'],
|
||||
type: 'image'
|
||||
})
|
||||
.css({float: 'left'})
|
||||
.bindEvent({
|
||||
click: toggleSize
|
||||
})
|
||||
.appendTo(self.$menubar);
|
||||
|
||||
self.resolutions = [];
|
||||
Ox.forEach(self.options.video, function(url, resolution) {
|
||||
Ox.print(url, resolution)
|
||||
self.resolutions.push(
|
||||
{id: resolution + '', title: resolution + 'p'}
|
||||
);
|
||||
});
|
||||
Ox.print('::::::',self.resolutions)
|
||||
|
||||
self.$resolutionSelect = Ox.Select({
|
||||
items: [{id: '96', title: '96p'},{id: '240', title: '240p'}],//self.resolutions,
|
||||
width: 48
|
||||
})
|
||||
.css({float: 'left'})
|
||||
.bindEvent({
|
||||
change: function() {
|
||||
|
||||
}
|
||||
})
|
||||
.appendTo(self.$menubar);
|
||||
|
||||
|
||||
//$('<div>').css({float: 'left', width: '8px', height: '1px'}).appendTo(self.$menubar.$element);
|
||||
|
||||
self.$linkButton = Ox.Button({
|
||||
style: 'symbol',
|
||||
title: 'arrowRight',
|
||||
tooltip: 'Link...',
|
||||
type: 'image'
|
||||
})
|
||||
.css({float: 'left'})
|
||||
//.css({marginLeft: '16px'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
window.location.hash =
|
||||
Ox.formatDuration(self.options['in'], 3) + '-' +
|
||||
Ox.formatDuration(self.options.out, 3);
|
||||
}
|
||||
})
|
||||
.appendTo(self.$menubar);
|
||||
|
||||
self.$embedButton = Ox.Button({
|
||||
style: 'symbol',
|
||||
title: 'embed',
|
||||
tooltip: 'Embed...',
|
||||
type: 'image'
|
||||
})
|
||||
.css({float: 'left'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
|
||||
}
|
||||
})
|
||||
.appendTo(self.$menubar);
|
||||
|
||||
self.$downloadButton = Ox.Button({
|
||||
style: 'symbol',
|
||||
title: 'download',
|
||||
tooltip: 'Download...',
|
||||
type: 'image'
|
||||
})
|
||||
.css({float: 'left'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
|
||||
}
|
||||
})
|
||||
.appendTo(self.$menubar);
|
||||
|
||||
self.$goToPosterButton = Ox.Button({
|
||||
style: 'symbol',
|
||||
title: 'goToPoster',
|
||||
tooltip: 'Go to Poster Frame',
|
||||
type: 'image'
|
||||
})
|
||||
.css({float: 'left'})
|
||||
.css({marginLeft: '16px'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
setPosition(self.options.posterFrame)
|
||||
}
|
||||
})
|
||||
.appendTo(self.$menubar);
|
||||
|
||||
self.$setPosterButton = Ox.Button({
|
||||
disabled: true,
|
||||
style: 'symbol',
|
||||
title: 'setPoster',
|
||||
tooltip: 'Set Poster Frame',
|
||||
type: 'image'
|
||||
})
|
||||
.css({float: 'left'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
self.$goToPosterButton.toggleDisabled();
|
||||
self.$setPosterButton.toggleDisabled();
|
||||
self.$unlockPosterButton.toggleTitle();
|
||||
}
|
||||
})
|
||||
.appendTo(self.$menubar);
|
||||
|
||||
self.$unlockPosterButton = Ox.Button({
|
||||
style: 'symbol',
|
||||
title: [
|
||||
{id: 'lock', title: 'lock'},
|
||||
{id: 'unlock', title: 'unlock', selected: true}
|
||||
],
|
||||
tooltip: ['Lock Poster Frame', 'Unlock Poster Frame'],
|
||||
type: 'image'
|
||||
})
|
||||
.css({float: 'left'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
self.$setPosterButton.toggleDisabled();
|
||||
}
|
||||
})
|
||||
.appendTo(self.$menubar);
|
||||
|
||||
self.$helpButton = Ox.Button({
|
||||
style: 'symbol',
|
||||
title: 'help',
|
||||
tooltip: 'Help',
|
||||
type: 'image'
|
||||
})
|
||||
.css({float: 'right'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
|
||||
}
|
||||
})
|
||||
.appendTo(self.$menubar);
|
||||
|
||||
self.$clearButton = Ox.Button({
|
||||
disabled: true,
|
||||
style: 'symbol',
|
||||
title: 'close',
|
||||
tooltip: 'Clear',
|
||||
type: 'image'
|
||||
})
|
||||
.css({float: 'right'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
self.$findInput.clearInput();
|
||||
submitFindInput('');
|
||||
}
|
||||
})
|
||||
.appendTo(self.$menubar);
|
||||
|
||||
self.$findInput = Ox.Input({
|
||||
changeOnKeypress: true,
|
||||
placeholder: 'Find...',
|
||||
width: 96
|
||||
})
|
||||
.css({float: 'right'})
|
||||
.bindEvent({
|
||||
change: function(data) {
|
||||
submitFindInput(data.value, false);
|
||||
},
|
||||
submit: function(data) {
|
||||
submitFindInput(data.value, true);
|
||||
}
|
||||
})
|
||||
.appendTo(self.$menubar);
|
||||
self.$findInput.find('input').css({background: 'transparent'})
|
||||
|
||||
self.$findButton = Ox.Button({
|
||||
//disabled: true,
|
||||
style: 'symbol',
|
||||
title: 'find',
|
||||
tooltip: 'Find',
|
||||
type: 'image'
|
||||
})
|
||||
.css({float: 'right'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
|
||||
}
|
||||
})
|
||||
//.appendTo(self.$menubar);
|
||||
|
||||
self.$nextButton = Ox.Button({
|
||||
disabled: true,
|
||||
style: 'symbol',
|
||||
title: 'arrowRight',
|
||||
tooltip: 'Next Result',
|
||||
type: 'image'
|
||||
})
|
||||
.css({float: 'right'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
|
||||
}
|
||||
})
|
||||
.appendTo(self.$menubar);
|
||||
|
||||
self.$previousButton = Ox.Button({
|
||||
disabled: true,
|
||||
style: 'symbol',
|
||||
title: 'arrowLeft',
|
||||
tooltip: 'Previous Result',
|
||||
type: 'image'
|
||||
})
|
||||
.css({float: 'right'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
|
||||
}
|
||||
})
|
||||
.appendTo(self.$menubar);
|
||||
|
||||
self.$results = $('<div>')
|
||||
.css({float: 'right', width: '36px', padding: '2px 4px 0 0', fontSize: '9px', textAlign: 'right', cursor: 'default', opacity: 0.25})
|
||||
.html('0')
|
||||
.appendTo(self.$menubar.$element);
|
||||
|
||||
that.$element = Ox.SplitPanel({
|
||||
elements: [
|
||||
{
|
||||
element: self.$editor
|
||||
element: Ox.SplitPanel({
|
||||
elements: [
|
||||
{
|
||||
element: self.$menubar,
|
||||
size: 16
|
||||
},
|
||||
{
|
||||
element: self.$editor
|
||||
}
|
||||
],
|
||||
orientation: 'vertical'
|
||||
})
|
||||
},
|
||||
{
|
||||
collapsed: !self.options.showAnnotations,
|
||||
|
|
@ -316,6 +560,20 @@ Ox.VideoEditor = function(options, self) {
|
|||
});
|
||||
}
|
||||
|
||||
function find(query) {
|
||||
var results = [];
|
||||
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;
|
||||
});
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
function getNextPosition(type, direction) {
|
||||
var found = false,
|
||||
position = 0,
|
||||
|
|
@ -432,10 +690,10 @@ Ox.VideoEditor = function(options, self) {
|
|||
lines = Math.ceil(self.options.duration / size.timeline[1].width);
|
||||
height = getHeight();
|
||||
self.$editor.css({
|
||||
overflowY: (scrollbarIsVisible && height <= self.options.height) ? 'scroll' : 'auto'
|
||||
overflowY: (scrollbarIsVisible && height <= self.options.height - 16) ? 'scroll' : 'auto'
|
||||
});
|
||||
//Ox.print('getSizes', scrollbarIsVisible, height, self.options.height, size)
|
||||
return (!scrollbarIsVisible && height > self.options.height) ? getSizes(true) : size;
|
||||
return (!scrollbarIsVisible && height > self.options.height - 16) ? getSizes(true) : size;
|
||||
function getHeight() {
|
||||
return size.player[0].height + self.controlsHeight +
|
||||
size.timeline[0].height + lines * 16 +
|
||||
|
|
@ -565,6 +823,31 @@ Ox.VideoEditor = function(options, self) {
|
|||
});
|
||||
}
|
||||
|
||||
function submitFindInput(value, hasPressedEnter) {
|
||||
self.options.find = value;
|
||||
self.results = find(self.options.find);
|
||||
self.$results.css({opacity: self.results.length ? 1 : 0.25}).html(self.results.length);
|
||||
self.$previousButton.options({
|
||||
disabled: self.results.length <= 1
|
||||
});
|
||||
self.$nextButton.options({
|
||||
disabled: self.results.length <= 1
|
||||
});
|
||||
self.$clearButton.options({
|
||||
disabled: !self.options.find
|
||||
});
|
||||
self.$timeline[1].options({
|
||||
find: self.options.find,
|
||||
results: self.results
|
||||
});
|
||||
self.$findInput.find('input').css({
|
||||
opacity: self.results.length ? 1 : 0.25
|
||||
});
|
||||
if (hasPressedEnter) {
|
||||
self.results.length ? (function() {})() : self.$findInput.focusInput();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleAnnotations(event, data) {
|
||||
self.options.showAnnotations = !data.collapsed;
|
||||
setSizes();
|
||||
|
|
@ -578,8 +861,8 @@ Ox.VideoEditor = function(options, self) {
|
|||
self.$player[0].togglePaused();
|
||||
}
|
||||
|
||||
function toggleSize(event, data) {
|
||||
self.options.videoSize = data.size
|
||||
function toggleSize() {
|
||||
self.options.videoSize = self.options.videoSize == 'small' ? 'large' : 'small';
|
||||
setSizes();
|
||||
that.triggerEvent('togglesize', {
|
||||
size: self.options.videoSize
|
||||
|
|
|
|||
|
|
@ -999,9 +999,8 @@ Ox.VideoPlayer = function(options, self) {
|
|||
}
|
||||
}
|
||||
|
||||
function find(query, hasPressedEnter) {
|
||||
function find(query) {
|
||||
var results = [];
|
||||
Ox.print(query)
|
||||
if (query.length) {
|
||||
query = query.toLowerCase();
|
||||
results = Ox.map(self.options.subtitles, function(subtitle) {
|
||||
|
|
@ -1010,9 +1009,6 @@ Ox.VideoPlayer = function(options, self) {
|
|||
out: subtitle.out
|
||||
} : null;
|
||||
});
|
||||
if (results.length == 0 && hasPressedEnter) {
|
||||
self.$findInput.focusInput();
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
|
@ -1198,7 +1194,7 @@ Ox.VideoPlayer = function(options, self) {
|
|||
Ox.forEach(self.options.subtitles, function(v) {
|
||||
if (
|
||||
v['in'] <= self.options.position &&
|
||||
v.out > self.options.position
|
||||
v.out >= self.options.position
|
||||
) {
|
||||
subtitle = v.text;
|
||||
return false;
|
||||
|
|
@ -1478,21 +1474,23 @@ Ox.VideoPlayer = function(options, self) {
|
|||
self.options.position >= self.options.out
|
||||
) {
|
||||
togglePaused();
|
||||
setPosition(self.options.out, 'video');
|
||||
setPosition(self.options.out/*, 'video'*/);
|
||||
//ended();
|
||||
self.playInToOut = false;
|
||||
} else {
|
||||
setPosition(self.options.position, 'video');
|
||||
}
|
||||
that.triggerEvent('position', {
|
||||
position: self.options.position
|
||||
});
|
||||
}
|
||||
|
||||
function playInToOut() {
|
||||
if (self.options.out > self.options['in']) {
|
||||
Ox.print('inToOut', self.options['in'])
|
||||
self.playInToOut = true;
|
||||
setPosition(self.options['in']);
|
||||
if (self.options.paused) {
|
||||
togglePaused();
|
||||
}
|
||||
self.options.paused && togglePaused();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1552,10 +1550,12 @@ Ox.VideoPlayer = function(options, self) {
|
|||
}
|
||||
|
||||
function setPosition(position, from) {
|
||||
position = Ox.limit(position, self['in'], self['out']);
|
||||
self.options.position = Ox.limit(position, self['in'], self['out']);
|
||||
/*
|
||||
self.options.position = Math.round(
|
||||
position * self.options.fps
|
||||
) / self.options.fps;
|
||||
*/
|
||||
self.options.paused && self.options.showMarkers && setMarkers();
|
||||
self.$subtitle && setSubtitle();
|
||||
self.$position && self.$position.html(formatPosition());
|
||||
|
|
@ -1582,9 +1582,6 @@ Ox.VideoPlayer = function(options, self) {
|
|||
//showLoadingIcon();
|
||||
loadImage();
|
||||
}
|
||||
that.triggerEvent('position', {
|
||||
position: self.options.position
|
||||
});
|
||||
}
|
||||
|
||||
function setResolution() {
|
||||
|
|
@ -1768,7 +1765,7 @@ Ox.VideoPlayer = function(options, self) {
|
|||
function submitFindInput(value, hasPressedEnter) {
|
||||
Ox.print('submitFindInput', value, hasPressedEnter)
|
||||
self.options.find = value;
|
||||
self.results = find(self.options.find, hasPressedEnter);
|
||||
self.results = find(self.options.find);
|
||||
Ox.print('results', self.results.length);
|
||||
if (self.$find) {
|
||||
self.$results.html(self.results.length);
|
||||
|
|
@ -1787,8 +1784,8 @@ Ox.VideoPlayer = function(options, self) {
|
|||
find: self.options.find,
|
||||
results: self.results
|
||||
});
|
||||
if (hasPressedEnter && self.results.length) {
|
||||
goToNextResult(1);
|
||||
if (hasPressedEnter) {
|
||||
self.results.length ? goToNextResult(1) : self.$findInput.focusInput();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1813,6 +1810,7 @@ Ox.VideoPlayer = function(options, self) {
|
|||
function submitPositionInput() {
|
||||
self.$positionInput.hide();
|
||||
self.$position.html('').show();
|
||||
Ox.print('###', parsePositionInput(self.$positionInput.options('value')))
|
||||
setPosition(parsePositionInput(self.$positionInput.options('value')));
|
||||
if (self.playOnSubmit) {
|
||||
togglePaused();
|
||||
|
|
@ -1823,6 +1821,9 @@ Ox.VideoPlayer = function(options, self) {
|
|||
that.gainFocus();
|
||||
}
|
||||
self.mouseHasLeft && hideControls();
|
||||
that.triggerEvent('position', {
|
||||
position: self.options.position
|
||||
});
|
||||
}
|
||||
|
||||
function toggleFind() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue