fix issues with automatically opening annotation folders; add annotations option to video player to make find work for all layers

This commit is contained in:
rlx 2012-02-19 10:49:52 +00:00
parent 61402492c6
commit 94cfbdb45c
7 changed files with 108 additions and 30 deletions

View file

@ -20,6 +20,7 @@ Ox.CollapsePanel = function(options, self) {
self = self || {}; self = self || {};
var that = Ox.Panel({}, self) var that = Ox.Panel({}, self)
.defaults({ .defaults({
animate: true,
collapsed: false, collapsed: false,
extras: [], extras: [],
size: 16, size: 16,
@ -92,11 +93,18 @@ Ox.CollapsePanel = function(options, self) {
!self.options.collapsed && that.$content.css({ !self.options.collapsed && that.$content.css({
marginTop: -that.$content.height() + 'px' marginTop: -that.$content.height() + 'px'
}).show(); }).show();
that.$content.animate({ if (self.options.animate) {
marginTop: marginTop + 'px' that.$content.animate({
}, 250, function() { marginTop: marginTop + 'px'
}, 250, function() {
self.options.collapsed && that.$content.hide();
});
} else {
that.$content.css({
marginTop: marginTop + 'px'
});
self.options.collapsed && that.$content.hide(); self.options.collapsed && that.$content.hide();
}); }
that.triggerEvent('toggle', { that.triggerEvent('toggle', {
collapsed: self.options.collapsed collapsed: self.options.collapsed
}); });
@ -110,7 +118,8 @@ Ox.CollapsePanel = function(options, self) {
if (key == 'collapsed') { if (key == 'collapsed') {
// will be toggled again in toggleCollapsed // will be toggled again in toggleCollapsed
self.options.collapsed = !self.options.collapsed; self.options.collapsed = !self.options.collapsed;
self.$button.trigger('click'); self.$button.toggle();
toggleCollapsed();
} else if (key == 'title') { } else if (key == 'title') {
self.$title.html(self.options.title); self.$title.html(self.options.title);
} }

View file

@ -45,6 +45,10 @@ Ox.AnnotationFolder = function(options, self) {
}) })
.options(options || {}); .options(options || {});
if (self.options.selected) {
self.options.collapsed = false;
}
self.annotations = getAnnotations(); self.annotations = getAnnotations();
self.points = getPoints(); self.points = getPoints();
self.position = self.options.position; self.position = self.options.position;
@ -526,8 +530,11 @@ Ox.AnnotationFolder = function(options, self) {
if (value === '') { if (value === '') {
self.editing = false; self.editing = false;
} }
value && Ox.print('----------------- select item in folder', value, self.options.collapsed)
if (value && self.options.collapsed) { if (value && self.options.collapsed) {
toggleLayer(); self.$panel.options({animate: false});
self.$panel.options({collapsed: false});
self.$panel.options({animate: true});
} }
self.$annotations.options({selected: value}); self.$annotations.options({selected: value});
} else if (key == 'sort') { } else if (key == 'sort') {

View file

@ -110,6 +110,7 @@ Ox.AnnotationPanel = function(options, self) {
that.triggerEvent('submit', Ox.extend({layer: layer.id}, data)); that.triggerEvent('submit', Ox.extend({layer: layer.id}, data));
}, },
togglelayer: function(data) { togglelayer: function(data) {
self.options.showLayers[layer.id] = !data.collapsed;
that.triggerEvent('togglelayer', Ox.extend({layer: layer.id}, data)); that.triggerEvent('togglelayer', Ox.extend({layer: layer.id}, data));
}, },
togglewidget: function(data) { togglewidget: function(data) {

View file

@ -74,6 +74,7 @@ Ox.VideoPanel = function(options, self) {
}); });
self.$video = Ox.VideoPlayer({ self.$video = Ox.VideoPlayer({
annotations: getAnnotations(),
censored: self.options.censored, censored: self.options.censored,
controlsTop: ['fullscreen', 'title', 'find'], controlsTop: ['fullscreen', 'title', 'find'],
controlsBottom: ['play', 'volume', 'scale', 'timeline', 'position', 'settings'], controlsBottom: ['play', 'volume', 'scale', 'timeline', 'position', 'settings'],
@ -127,6 +128,7 @@ Ox.VideoPanel = function(options, self) {
scale: function(data) { scale: function(data) {
that.triggerEvent('scale', data); that.triggerEvent('scale', data);
}, },
select: selectAnnotation,
subtitles: function(data) { subtitles: function(data) {
that.triggerEvent('subtitles', data); that.triggerEvent('subtitles', data);
}, },
@ -269,6 +271,14 @@ Ox.VideoPanel = function(options, self) {
that.triggerEvent('position', {position: self.options.position}); that.triggerEvent('position', {position: self.options.position});
} }
function getAnnotations() {
return Ox.flatten(Ox.merge(self.options.layers.map(function(layer) {
return layer.items.map(function(item) {
return {id: item.id, 'in': item['in'], out: item.out, text: item.value};
});
}))).sort(sortAnnotations);
}
function getPlayerHeight() { function getPlayerHeight() {
return self.options.height - return self.options.height -
self.options.showTimeline * 80 - 1; self.options.showTimeline * 80 - 1;
@ -330,6 +340,7 @@ Ox.VideoPanel = function(options, self) {
setPoint('in', data['in']); setPoint('in', data['in']);
setPoint('out', data.out); setPoint('out', data.out);
} }
self.$annotationPanel.options({selected: self.options.selected});
that.triggerEvent('select', {id: self.options.selected}); that.triggerEvent('select', {id: self.options.selected});
} }
@ -347,6 +358,24 @@ Ox.VideoPanel = function(options, self) {
self.$annotationPanel.options({position: self.options.position}); self.$annotationPanel.options({position: self.options.position});
} }
function sortAnnotations(a, b) {
var ret = 0;
if (a['in'] < b['in']) {
ret = -1;
} else if (a['in'] > b['in']) {
ret = 1;
} else if (a.out < b.out) {
ret = -1;
} else if (a.out > b.out) {
ret = 1;
} else if (a.value < b.value) {
ret = -1;
} else if (a.value > b.value) {
ret = 1;
}
return ret;
}
function toggleAnnotations(data) { function toggleAnnotations(data) {
self.options.showAnnotations = !data.collapsed; self.options.showAnnotations = !data.collapsed;
self.$video.options({ self.$video.options({

View file

@ -6,12 +6,11 @@
Ox.VideoPlayer <f> Generic Video Player Ox.VideoPlayer <f> Generic Video Player
(options, self) -> <o> Video Player (options, self) -> <o> Video Player
options <o> Options options <o> Options
annotation <[o]> Array of annotation tracks annotations <[]> Array of annotations
name <s> Name of the annotation track id <s> Optional id
data <[o]> Annotation data in <n> In point (sec)
in <n> In point (sec) out <n> Out point (sec)
out <n> Out point (sec) text <s> Text
text <s> Text
censored <a|[]> Array of censored ranges censored <a|[]> Array of censored ranges
controlsBottom <[s]|[]> Bottom controls, from left to right controlsBottom <[s]|[]> Bottom controls, from left to right
Can be 'close', fullscreen', 'scale', 'title', 'find', 'open', Can be 'close', fullscreen', 'scale', 'title', 'find', 'open',
@ -60,6 +59,7 @@ Ox.VideoPlayer <f> Generic Video Player
showProgress <|false> If true, show buffering progress showProgress <|false> If true, show buffering progress
sizeIsLarge <b|false> If true, initial state of the size control is large sizeIsLarge <b|false> If true, initial state of the size control is large
subtitles <s|[o]|[]> URL or SRT or array of subtitles subtitles <s|[o]|[]> URL or SRT or array of subtitles
id <s> Optional id
in <n> In point (sec) in <n> In point (sec)
out <n> Out point (sec) out <n> Out point (sec)
text <s> Text text <s> Text
@ -146,6 +146,10 @@ Ox.VideoPlayer = function(options, self) {
} }
}); });
if (Ox.isEmpty(self.options.annotations)) {
self.options.annotations = self.options.subtitles;
}
if (Ox.isObject(self.options.video)) { if (Ox.isObject(self.options.video)) {
self.resolutions = Ox.sort(Object.keys(self.options.video)); self.resolutions = Ox.sort(Object.keys(self.options.video));
if (!(self.options.resolution in self.options.video)) { if (!(self.options.resolution in self.options.video)) {
@ -1160,13 +1164,17 @@ Ox.VideoPlayer = function(options, self) {
var results = []; var results = [];
if (query.length) { if (query.length) {
query = query.toLowerCase(); query = query.toLowerCase();
results = Ox.map(self.options.subtitles, function(subtitle) { results = Ox.map(self.options.annotations, function(annotation) {
return subtitle.text.toLowerCase().indexOf(query) > -1 ? { return Ox.decodeHTML(Ox.stripTags(
'in': subtitle['in'], annotation.text.toLowerCase()
out: subtitle.out )).indexOf(query) > -1 ? {
id: annotation.id,
'in': annotation['in'],
out: annotation.out
} : null; } : null;
}); });
} }
Ox.print('FIND RESULTS:', results);
return results; return results;
} }
@ -1500,24 +1508,29 @@ Ox.VideoPlayer = function(options, self) {
function goToNextResult(direction) { function goToNextResult(direction) {
var found = false, var found = false,
position = 0; result;
if (self.results.length) { if (self.results.length) {
direction == -1 && self.results.reverse(); direction == -1 && self.results.reverse();
Ox.forEach(self.results, function(v) { Ox.forEach(self.results, function(v) {
if (direction == 1 ? v['in'] > self.options.position : v.out < self.options.position) { if (
position = v['in']; direction == 1
? v['in'] > self.options.position
: v.out < self.options.position
) {
result = v
found = true; found = true;
return false; return false;
} }
}); });
direction == -1 && self.results.reverse(); direction == -1 && self.results.reverse();
if (!found) { if (!found) {
position = self.results[direction == 1 ? 0 : self.results.length - 1]['in']; result = self.results[direction == 1 ? 0 : self.results.length - 1];
} }
setPosition(position + self.secondsPerFrame); setPosition(result['in'] + self.secondsPerFrame);
that.triggerEvent('position', { that.triggerEvent('position', {
position: self.options.position position: self.options.position
}); });
result.id && that.triggerEvent('select', result);
} }
} }
@ -2132,7 +2145,12 @@ Ox.VideoPlayer = function(options, self) {
results: self.results results: self.results
}); });
if (hasPressedEnter) { if (hasPressedEnter) {
self.results.length ? goToNextResult(1) : self.$findInput.focusInput(true); if (self.results.length) {
goToNextResult(1);
that.gainFocus();
} else {
self.$findInput.focusInput(true);
}
} }
that.triggerEvent('find', {find: self.options.find}); that.triggerEvent('find', {find: self.options.find});
} }

View file

@ -794,21 +794,21 @@ Video
.OxThemeClassic .OxAnnotationFolder .OxArrayEditable .OxEditableElement.OxSelected .OxHighlight { .OxThemeClassic .OxAnnotationFolder .OxArrayEditable .OxEditableElement.OxSelected .OxHighlight {
background-color: transparent; background-color: transparent;
background-image: -moz-repeating-linear-gradient( background-image: -moz-repeating-linear-gradient(
-45deg, rgb(192, 192, 255) 0, rgb(192, 192, 255) 25%, -45deg, transparent 0%, transparent 25%,
rgb(255, 255, 0) 25%, rgb(255, 255, 0) 50%, rgb(255, 255, 0) 25%, rgb(255, 255, 0) 50%,
rgb(192, 192, 255) 50%, rgb(192, 192, 255) 75%, transparent 50%, transparent 75%,
rgb(255, 255, 0) 75%, rgb(255, 255, 0) 100% rgb(255, 255, 0) 75%, rgb(255, 255, 0) 100%
); );
background-image: -o-repeating-linear-gradient( background-image: -o-repeating-linear-gradient(
-45deg, rgb(192, 192, 255) 0, rgb(192, 192, 255) 25%, -45deg, transparent 0%, transparent 25%,
rgb(255, 255, 0) 25%, rgb(255, 255, 0) 50%, rgb(255, 255, 0) 25%, rgb(255, 255, 0) 50%,
rgb(192, 192, 255) 50%, rgb(192, 192, 255) 75%, transparent 50%, transparent 75%,
rgb(255, 255, 0) 75%, rgb(255, 255, 0) 100% rgb(255, 255, 0) 75%, rgb(255, 255, 0) 100%
); );
background-image: -webkit-repeating-linear-gradient( background-image: -webkit-repeating-linear-gradient(
-45deg, rgb(192, 192, 255) 0, rgb(192, 192, 255) 25%, -45deg, transparent 0%, transparent 25%,
rgb(255, 255, 0) 25%, rgb(255, 255, 0) 50%, rgb(255, 255, 0) 25%, rgb(255, 255, 0) 50%,
rgb(192, 192, 255) 50%, rgb(192, 192, 255) 75%, transparent 50%, transparent 75%,
rgb(255, 255, 0) 75%, rgb(255, 255, 0) 100% rgb(255, 255, 0) 75%, rgb(255, 255, 0) 100%
); );
background-size: 4px 4px; background-size: 4px 4px;

View file

@ -75,7 +75,9 @@ Ox.highlightHTML <f> Highlight matches in an HTML string
> Ox.highlightHTML('AT&amp;T', 'amp', 'h') > Ox.highlightHTML('AT&amp;T', 'amp', 'h')
'AT&amp;T' 'AT&amp;T'
> Ox.highlightHTML('a &lt;b&gt; c', '<b>', 'h') > Ox.highlightHTML('a &lt;b&gt; c', '<b>', 'h')
'<span class="h">a <span class="h">&lt;b&gt;</span> c' 'a <span class="h">&lt;b&gt;</span> c'
> Ox.highlightHTML('a <br> c', 'b', 'h')
'a <br> c'
@*/ @*/
Ox.highlightHTML = function(html, str, classname, tags) { Ox.highlightHTML = function(html, str, classname, tags) {
var count = 0, var count = 0,
@ -83,7 +85,19 @@ Ox.highlightHTML = function(html, str, classname, tags) {
isTag = false, isTag = false,
position, position,
positions = []; positions = [];
tags = Ox.merge(tags || [], ['a', 'b', 'code', 'i', 's', 'sub', 'sup', 'u']); //fixme: default tags should be same as in parseHTML
tags = Ox.merge(tags || [], [
// inline formatting
'b', 'code', 'i', 's', 'sub', 'sup', 'u',
// block formatting
'blockquote', 'h1', 'h2', 'h3', 'p', 'pre',
// lists
'li', 'ol', 'ul',
// tables
'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'tr',
// other
'a', 'br', 'img',
]);
str = Ox.encodeHTML(str).toLowerCase(); str = Ox.encodeHTML(str).toLowerCase();
Ox.forEach(html.toLowerCase(), function(chr, i) { Ox.forEach(html.toLowerCase(), function(chr, i) {
// check for entity or tag start // check for entity or tag start