2013-07-13 23:07:25 +00:00
'use strict' ;
Ox . ClipPanel = function ( options , self ) {
self = self || { } ;
var that = Ox . Element ( { } , self )
. defaults ( {
2014-01-22 18:22:12 +00:00
annotationsCalendarSize : 256 ,
annotationsFont : 'small' ,
annotationsMapSize : 256 ,
annotationsRange : 'all' ,
annotationsSort : 'position' ,
2014-02-06 10:27:57 +00:00
clipRatio : 16 / 9 ,
2013-07-13 23:07:25 +00:00
clips : [ ] ,
2014-01-22 18:22:12 +00:00
clickLink : null ,
2013-07-14 18:58:31 +00:00
duration : 0 ,
2013-07-13 23:07:25 +00:00
editable : false ,
2013-07-15 11:34:11 +00:00
getClipImageURL : null ,
2013-07-13 23:07:25 +00:00
'in' : 0 ,
2014-02-07 06:19:48 +00:00
itemName : '' ,
2014-01-22 18:22:12 +00:00
layers : [ ] ,
2013-07-13 23:07:25 +00:00
out : 0 ,
position : 0 ,
2013-07-18 13:56:50 +00:00
selected : [ ] ,
2013-07-13 23:07:25 +00:00
sort : [ ] ,
sortOptions : [ ] ,
2014-01-22 18:22:12 +00:00
showAnnotationsCalendar : false ,
showAnnotationsMap : false ,
showLayers : { } ,
showUsers : false ,
2013-07-13 23:07:25 +00:00
view : 'list' ,
width : 0
} )
. options ( options || { } )
. update ( {
clips : function ( ) {
2013-07-14 14:56:41 +00:00
self . $list . options ( {
2013-08-09 18:38:47 +00:00
items : self . options . clips ,
2014-02-06 10:27:57 +00:00
sort : getListSort ( ) ,
2013-07-14 14:56:41 +00:00
sortable : isSortable ( )
} ) ;
2013-07-14 18:58:31 +00:00
updateStatus ( ) ;
2013-07-14 14:56:41 +00:00
} ,
2013-07-14 18:58:31 +00:00
duration : updateStatus ,
2013-07-15 10:04:56 +00:00
height : function ( ) {
self . $list . size ( ) ;
} ,
2014-01-22 18:22:12 +00:00
position : function ( ) {
if ( self . options . view == 'annotations' ) {
self . $list . options ( {
position : self . options . position
} ) ;
}
} ,
2013-08-09 12:52:18 +00:00
selected : selectClips ,
2013-07-14 14:56:41 +00:00
sort : function ( ) {
updateSortElement ( ) ;
self . $list . options ( {
2014-02-06 10:27:57 +00:00
sort : getListSort ( ) ,
2013-07-14 14:56:41 +00:00
sortable : isSortable ( ) ,
} ) ;
2013-07-13 23:07:25 +00:00
}
2013-07-15 12:03:31 +00:00
} )
. bindEvent ( {
2014-02-06 10:27:57 +00:00
resize : function ( data ) {
self . $sortSelect . options ( { width : getSortSelectWidth ( data . size ) } ) ;
2013-07-15 12:03:31 +00:00
self . $list . size ( ) ;
}
2013-07-13 23:07:25 +00:00
} ) ;
2014-02-06 10:27:57 +00:00
self . columns = [
{
align : 'right' ,
id : 'index' ,
operator : '+' ,
title : Ox . _ ( 'Index' ) ,
visible : false ,
width : 60
} ,
{
2014-02-07 06:19:48 +00:00
addable : false ,
2014-02-06 10:27:57 +00:00
id : 'id' ,
operator : '+' ,
unique : true ,
} ,
{
2014-02-07 06:19:48 +00:00
addable : false ,
2014-02-06 10:27:57 +00:00
id : 'item' ,
operator : '+' ,
2014-02-07 06:19:48 +00:00
} ,
{
id : 'title' ,
format : function ( value , data ) {
return value + (
data . director ? ' (' + data . director . join ( ', ' ) + ')' : ''
) ;
} ,
operator : '+' ,
title : self . options . itemName ,
2014-02-06 10:27:57 +00:00
visible : true ,
2014-02-07 06:19:48 +00:00
width : 120
2014-02-06 10:27:57 +00:00
} ,
{
align : 'right' ,
editable : isEditable ,
format : function ( value , data ) {
return (
isEditable ( data ) ? [ '' , '' ]
: [ '<span class="OxLight">' , '</span>' ]
) . join ( Ox . formatDuration ( value , 3 ) ) ;
} ,
id : 'in' ,
operator : '+' ,
title : Ox . _ ( 'In' ) ,
visible : true ,
width : 90
} ,
{
align : 'right' ,
editable : isEditable ,
format : function ( value , data ) {
return (
isEditable ( data ) ? [ '' , '' ]
: [ '<span class="OxLight">' , '</span>' ]
) . join ( Ox . formatDuration ( value , 3 ) ) ;
} ,
id : 'out' ,
operator : '+' ,
title : Ox . _ ( 'Out' ) ,
visible : true ,
width : 90
} ,
{
align : 'right' ,
editable : isEditable ,
format : function ( value , data ) {
return (
isEditable ( data ) ? [ '' , '' ]
: [ '<span class="OxLight">' , '</span>' ]
) . join ( Ox . formatDuration ( value , 3 ) ) ;
} ,
id : 'duration' ,
operator : '+' ,
title : Ox . _ ( 'Duration' ) ,
visible : true ,
width : 90
} ,
{
2014-02-07 06:19:48 +00:00
addable : false ,
2014-02-06 10:27:57 +00:00
id : 'sort' ,
operator : '+' ,
2014-02-07 06:19:48 +00:00
// title: Ox._('Sort'),
visible : false
2014-02-06 10:27:57 +00:00
}
] ;
2013-07-13 23:07:25 +00:00
self . $menubar = Ox . Bar ( {
size : 24
} )
. bindEvent ( {
doubleclick : function ( e ) {
if ( $ ( e . target ) . is ( '.OxBar' ) ) {
self . $list . animate ( { scrollTop : 0 } , 250 ) ;
}
}
} ) ;
2013-07-14 10:24:38 +00:00
self . $menu = Ox . MenuButton ( {
items : [
{ group : 'view' , min : 1 , max : 1 , items : [
2014-02-03 05:22:25 +00:00
{ id : 'list' , title : Ox . _ ( 'View Clips as List' ) , checked : self . options . view == 'list' } ,
{ id : 'grid' , title : Ox . _ ( 'View Clips as Grid' ) , checked : self . options . view == 'grid' } ,
2014-01-22 18:22:12 +00:00
{ id : 'annotations' , title : Ox . _ ( 'View Annotations' ) , checked : self . options . view == 'annotations' } ,
2013-07-14 10:24:38 +00:00
] } ,
{ } ,
2014-02-06 10:27:57 +00:00
{ id : 'split' , title : Ox . _ ( 'Split Selected Clips at Cuts' ) , disabled : ! self . options . editable || ! self . options . selected . length || self . options . view == 'annotations' } ,
{ id : 'join' , title : Ox . _ ( 'Join Selected Clips at Cuts' ) , disabled : ! self . options . editable || ! self . options . selected . length || self . options . view == 'annotations' } ,
{ id : 'replace' , title : Ox . _ ( 'Make Selected Clips Editable' ) , disabled : ! self . options . editable || ! self . options . selected . length || self . options . view == 'annotations' }
2013-07-13 23:07:25 +00:00
] ,
2013-07-14 10:24:38 +00:00
title : 'set' ,
tooltip : Ox . _ ( 'Options' ) ,
type : 'image'
2013-07-13 23:07:25 +00:00
} )
. css ( {
float : 'left' ,
margin : '4px 2px 4px 4px'
} )
. bindEvent ( {
change : function ( data ) {
2013-07-14 10:24:38 +00:00
if ( data . id == 'view' ) {
2014-02-06 10:27:57 +00:00
var action = self . options . editable
&& self . options . selected . length
&& self . options . view != 'annotations'
? 'enableItem' : 'disableItem' ;
2013-07-14 11:39:20 +00:00
self . options . view = data . checked [ 0 ] . id ;
2014-02-06 10:27:57 +00:00
self . $menu [ action ] ( 'split' ) ;
self . $menu [ action ] ( 'join' ) ;
self . $menu [ action ] ( 'replace' ) ;
2013-07-14 11:39:20 +00:00
self . $panel . replaceElement ( 1 , self . $list = getList ( ) ) ;
2013-07-18 09:57:51 +00:00
that . triggerEvent ( 'view' , { view : self . options . view } ) ;
2013-07-14 10:24:38 +00:00
}
} ,
click : function ( data ) {
2013-08-09 12:52:18 +00:00
if ( data . id == 'split' ) {
2013-08-10 11:09:12 +00:00
splitClips ( ) ;
2013-08-09 12:52:18 +00:00
} else if ( data . id == 'join' ) {
2013-08-10 11:09:12 +00:00
joinClips ( ) ;
2013-08-09 12:52:18 +00:00
}
2013-07-13 23:07:25 +00:00
}
} )
2013-07-14 10:24:38 +00:00
. appendTo ( self . $menubar ) ,
2013-07-13 23:07:25 +00:00
self . $sortSelect = Ox . Select ( {
items : self . options . sortOptions ,
value : self . options . sort [ 0 ] . key ,
2014-02-06 10:27:57 +00:00
width : getSortSelectWidth ( self . options . width )
2013-07-13 23:07:25 +00:00
} )
. bindEvent ( {
change : function ( data ) {
2013-07-14 14:56:41 +00:00
self . options . sort = [ {
2013-07-13 23:07:25 +00:00
key : data . value ,
operator : Ox . getObjectById (
self . options . sortOptions , data . value
) . operator
2013-07-14 14:56:41 +00:00
} ] ;
updateSortElement ( ) ;
that . triggerEvent ( 'sort' , self . options . sort ) ;
2013-07-13 23:07:25 +00:00
}
} ) ;
self . $orderButton = Ox . Button ( {
overlap : 'left' ,
title : getButtonTitle ( ) ,
tooltip : getButtonTooltip ( ) ,
type : 'image'
} )
. bindEvent ( {
click : function ( ) {
2013-07-14 14:56:41 +00:00
self . options . sort = [ {
2013-07-13 23:07:25 +00:00
key : self . options . sort [ 0 ] . key ,
operator : self . options . sort [ 0 ] . operator == '+' ? '-' : '+'
2013-07-14 14:56:41 +00:00
} ] ;
updateSortElement ( ) ;
that . triggerEvent ( 'sort' , self . options . sort ) ;
2013-07-13 23:07:25 +00:00
}
} ) ;
self . $sortElement = Ox . FormElementGroup ( {
elements : [ self . $sortSelect , self . $orderButton ] ,
float : 'right'
} )
. css ( {
float : 'right' ,
margin : '4px 4px 4px 2px'
} )
. appendTo ( self . $menubar ) ;
2013-07-14 10:24:38 +00:00
self . $list = getList ( ) ;
self . $statusbar = Ox . Bar ( {
size : 16
} ) ;
2013-07-14 18:58:31 +00:00
self . $status = Ox . Element ( )
. css ( {
marginTop : '2px' ,
fontSize : '9px' ,
textAlign : 'center' ,
textOverflow : 'ellipsis'
} )
. appendTo ( self . $statusbar ) ;
2013-07-14 10:24:38 +00:00
that . setElement (
2013-07-14 11:39:20 +00:00
self . $panel = Ox . SplitPanel ( {
2013-07-14 10:24:38 +00:00
elements : [
{
element : self . $menubar ,
size : 24
} ,
{
element : self . $list
} ,
{
element : self . $statusbar ,
size : 16
}
] ,
orientation : 'vertical'
} )
) ;
2013-07-14 18:58:31 +00:00
updateStatus ( ) ;
2013-07-14 10:24:38 +00:00
function editClip ( data ) {
var value = self . $list . value ( data . id , data . key ) ;
if ( data . value != value && ! ( data . value === '' && value === null ) ) {
self . $list . value ( data . id , data . key , data . value || null ) ;
that . triggerEvent ( 'edit' , data ) ;
}
}
function getButtonTitle ( ) {
return self . options . sort [ 0 ] . operator == '+' ? 'up' : 'down' ;
}
function getButtonTooltip ( ) {
return Ox . _ ( self . options . sort [ 0 ] . operator == '+' ? 'Ascending' : 'Descending' ) ;
}
2013-08-09 12:52:18 +00:00
function getEditable ( ids ) {
return ids . filter ( function ( id ) {
return isEditable ( Ox . getObjectById ( self . options . clips , id ) ) ;
} ) ;
}
2013-07-14 10:24:38 +00:00
function getList ( ) {
2013-07-15 11:34:11 +00:00
var $list ;
2014-01-22 18:22:12 +00:00
if ( self . options . view == 'annotations' ) {
$list = Ox . AnnotationPanel ( {
calendarSize : self . options . annotationsCalendarSize ,
clickLink : self . options . clickLink ,
editable : false ,
font : self . options . annotationsFont ,
//highlight: self.options.find,
//'in': self.options['in'],
//itemName: self.options.itemName,
layers : self . options . layers ,
mapSize : self . options . annotationsMapSize ,
//out: self.options.out,
position : self . options . position ,
range : self . options . annotationsRange ,
showCalendar : self . options . showAnnotationsCalendar ,
showLayers : Ox . clone ( self . options . showLayers ) ,
showMap : self . options . showAnnotationsMap ,
showUsers : self . options . showUsers ,
sort : self . options . annotationsSort ,
2014-01-22 18:42:28 +00:00
width : self . options . width
2014-01-22 18:22:12 +00:00
} ) ;
2014-01-22 18:42:28 +00:00
$list . size = function ( ) {
$list . options ( {
width : self . options . width
} ) ;
} ;
2014-01-22 18:22:12 +00:00
return $list ;
} else if ( self . options . view == 'list' ) {
2013-07-15 11:34:11 +00:00
$list = Ox . TableList ( {
2014-02-06 10:27:57 +00:00
columns : self . columns ,
2013-07-15 11:34:11 +00:00
columnsMovable : true ,
columnsRemovable : true ,
columnsResizable : true ,
columnsVisible : true ,
2013-08-09 18:38:47 +00:00
items : self . options . clips ,
2014-02-07 06:19:48 +00:00
keys : [ 'director' ] ,
2013-07-15 11:34:11 +00:00
scrollbarVisible : true ,
2013-08-11 07:44:35 +00:00
selected : self . options . selected ,
2014-02-06 10:27:57 +00:00
sort : getListSort ( ) ,
2013-07-15 11:34:11 +00:00
sortable : isSortable ( ) ,
unique : 'id'
} ) ;
} else {
$list = Ox . IconList ( {
2013-07-18 09:57:51 +00:00
draggable : true ,
2014-02-06 10:27:57 +00:00
fixedRatio : self . options . clipRatio ,
2013-07-15 11:34:11 +00:00
item : function ( data , sort , size ) {
size = size || 128 ; // fixme: is this needed?
2013-07-15 14:46:51 +00:00
var ratio = data . videoRatio ,
2014-02-06 10:27:57 +00:00
fixedRatio = self . options . clipRatio ,
2013-07-15 11:34:11 +00:00
width = ratio > fixedRatio ? size : Math . round ( size * ratio / fixedRatio ) ,
height = Math . round ( width / ratio ) ,
info ,
2013-07-15 14:46:51 +00:00
title = data . title + (
data . director ? ' (' + data . director . join ( ', ' ) + ')' : ''
) ,
2013-07-15 11:34:11 +00:00
url = self . options . getClipImageURL ( data . id , width , height ) ;
if ( [ 'text' , 'position' , 'duration' , 'random' ] . indexOf ( sort [ 0 ] . key ) > - 1 ) {
info = Ox . formatDuration ( data [ 'in' ] ) + ' - '
+ Ox . formatDuration ( data . out ) ;
} else {
info = Ox . formatDuration ( data [ 'in' ] ) + ' - '
+ Ox . formatDuration ( data . out ) ;
}
return {
height : height ,
id : data . id ,
info : info ,
title : title ,
url : url ,
width : width
} ;
} ,
items : self . options . clips ,
keys : [ 'id' , 'in' , 'out' ] ,
orientation : 'both' ,
2014-02-06 10:27:57 +00:00
sort : getListSort ( ) ,
2013-07-15 11:34:11 +00:00
unique : 'id'
} ) ;
}
2013-07-14 11:39:20 +00:00
$list . bindEvent ( {
copy : function ( data ) {
that . triggerEvent ( 'copy' , data ) ;
} ,
2013-07-15 10:04:56 +00:00
copyadd : function ( data ) {
that . triggerEvent ( 'copyadd' , data ) ;
2013-07-14 11:39:20 +00:00
} ,
2013-08-03 13:56:27 +00:00
cut : function ( data ) {
2013-08-09 12:52:18 +00:00
self . options . editable && that . triggerEvent ( 'cut' , data ) ;
2013-08-03 13:56:27 +00:00
} ,
cutadd : function ( data ) {
2013-08-09 12:52:18 +00:00
self . options . editable && that . triggerEvent ( 'cutadd' , data ) ;
2013-08-03 13:56:27 +00:00
} ,
2013-07-14 11:39:20 +00:00
'delete' : function ( data ) {
2013-08-09 12:52:18 +00:00
self . options . editable && that . triggerEvent ( 'delete' , data ) ;
2013-07-14 11:39:20 +00:00
} ,
move : function ( data ) {
data . ids . forEach ( function ( id , index ) {
self . $list . value ( id , 'index' , index ) ;
} ) ;
that . triggerEvent ( 'move' , data ) ;
} ,
open : function ( data ) {
that . triggerEvent ( 'open' , data ) ;
} ,
paste : function ( ) {
2013-08-09 12:52:18 +00:00
self . options . editable && that . triggerEvent ( 'paste' ) ;
2013-07-14 11:39:20 +00:00
} ,
select : function ( data ) {
2013-08-09 12:52:18 +00:00
self . options . selected = data . ids ;
selectClips ( ) ;
2013-07-14 11:39:20 +00:00
that . triggerEvent ( 'select' , data ) ;
} ,
sort : function ( data ) {
2013-07-14 14:56:41 +00:00
self . options . sort = [ data ] ;
updateSortElement ( ) ;
2013-07-14 11:39:20 +00:00
self . $list . options ( { sortable : isSortable ( ) } ) ;
2013-07-14 14:56:41 +00:00
that . triggerEvent ( 'sort' , self . options . sort ) ;
2013-07-14 11:39:20 +00:00
} ,
submit : function ( data ) {
2013-08-09 16:05:52 +00:00
var value = self . $list . value ( data . id ) ;
2013-07-14 11:39:20 +00:00
data . value = Ox . parseDuration ( data . value ) ;
2013-08-09 16:05:52 +00:00
if (
( data . key == 'in' && data . value < value . out )
|| ( data . key == 'out' && data . value > value [ 'in' ] )
|| ( data . key == 'duration' && data . value > 0 )
) {
self . $list . value ( data . id , data . key , data . value ) ;
if ( data . key == 'in' ) {
self . $list . value ( data . id , 'duration' , value . out - data . value ) ;
} else if ( data . key == 'out' ) {
self . $list . value ( data . id , 'duration' , data . value - value [ 'in' ] ) ;
} else if ( data . key == 'duration' ) {
self . $list . value ( data . id , 'out' , value [ 'in' ] + data . value ) ;
}
that . triggerEvent ( 'edit' , data ) ;
} else {
self . $list . value ( data . id , data . key , value [ data . key ] ) ;
}
2013-07-14 11:39:20 +00:00
}
} ) ;
return $list ;
2013-07-13 23:07:25 +00:00
}
2014-02-06 10:27:57 +00:00
function getListSort ( ) {
var sort = [ { key : 'index' , operator : '+' } ]
if ( self . options . sort && self . options . sort . length ) {
sort [ 0 ] . operator = self . options . sort [ 0 ] . operator ;
sort [ 0 ] . key = Ox . getObjectById ( self . columns , self . options . sort [ 0 ] . key )
? self . options . sort [ 0 ] . key
: 'sort' ;
}
return sort ;
}
function getSortSelectWidth ( width ) {
return Math . min ( 144 , width - 52 + Ox . UI . SCROLLBAR _SIZE ) ;
}
2013-07-13 23:07:25 +00:00
function isEditable ( data ) {
return self . options . editable && ! data . annotation ;
}
function isSortable ( ) {
2013-07-14 13:48:41 +00:00
return self . options . editable
&& self . options . sort && self . options . sort . length
&& self . options . sort [ 0 ] . key == 'index'
&& self . options . sort [ 0 ] . operator == '+' ;
2013-07-13 23:07:25 +00:00
}
2013-08-10 11:09:12 +00:00
function joinClips ( ) {
var clips = getEditable ( self . options . selected ) . map ( function ( id ) {
return Ox . clone ( Ox . getObjectById ( self . options . clips , id ) ) ;
} ) ,
ids = [ ] , join = [ ] , joined ;
do {
joined = false ;
Ox . forEach ( clips , function ( outClip ) {
var outPoint = outClip . item + '/' + outClip . out ;
Ox . forEach ( clips , function ( inClip , index ) {
var inPoint = inClip . item + '/' + inClip [ 'in' ] ;
if ( inPoint == outPoint ) {
2013-08-10 11:22:38 +00:00
ids = Ox . unique ( ids . concat ( [ outClip . id , inClip . id ] ) ) ;
join = Ox . unique ( join . concat ( [ outClip . id ] ) ) ;
2013-08-10 11:09:12 +00:00
outClip . out = inClip . out ;
2013-08-10 11:22:38 +00:00
if ( Ox . contains ( join , inClip . id ) ) {
join . splice ( join . indexOf ( inClip . id ) , 1 ) ;
}
2013-08-10 11:09:12 +00:00
clips . splice ( index , 1 ) ;
joined = true ;
return false ; // break
}
} ) ;
if ( joined ) {
return false ; // brea;
}
} ) ;
} while ( joined ) ;
2013-08-10 11:22:38 +00:00
join = join . map ( function ( id ) {
2013-08-10 11:09:12 +00:00
var clip = Ox . getObjectById ( clips , id ) ;
return { 'in' : clip [ 'in' ] , item : clip . item , out : clip . out } ;
} ) ;
if ( ids . length ) {
that . triggerEvent ( 'join' , { ids : ids , join : join } ) ;
}
}
2013-08-09 12:52:18 +00:00
function selectClips ( ) {
var action ;
if ( self . options . editable ) {
action = self . options . selected . length ? 'enableItem' : 'disableItem' ;
self . $menu [ action ] ( 'split' ) ;
self . $menu [ action ] ( 'join' ) ;
}
self . $list . options ( { selected : self . options . selected } ) ;
}
2013-08-10 11:09:12 +00:00
function splitClips ( ) {
var ids = getEditable ( self . options . selected ) . filter ( function ( id ) {
var clip = Ox . getObjectById ( self . options . clips , id ) ;
return clip . cuts . length ;
} ) ,
split = Ox . flatten ( ids . map ( function ( id ) {
var clip = Ox . getObjectById ( self . options . clips , id ) ,
cuts = [ clip [ 'in' ] ] . concat ( clip . cuts ) . concat ( [ clip . out ] ) ;
return Ox . range ( 0 , cuts . length - 1 ) . map ( function ( i ) {
return { 'in' : cuts [ i ] , item : clip . item , out : cuts [ i + 1 ] } ;
} ) ;
} ) ) ;
if ( split . length > ids . length ) {
that . triggerEvent ( 'split' , { ids : ids , split : split } ) ;
}
}
2013-07-13 23:07:25 +00:00
function updateSortElement ( ) {
2013-07-14 14:56:41 +00:00
self . $sortSelect . options ( {
value : self . options . sort [ 0 ] . key ,
} ) ;
self . $orderButton . options ( {
title : getButtonTitle ( ) ,
tooltip : getButtonTooltip ( ) ,
} ) ;
2013-07-13 23:07:25 +00:00
}
2013-07-14 18:58:31 +00:00
function updateStatus ( ) {
self . $status . html (
Ox . toTitleCase ( Ox . formatCount ( self . options . clips . length , 'Clip' ) )
+ ', ' + Ox . formatDuration ( self . options . duration , 3 )
) ;
}
2013-08-12 10:34:46 +00:00
that . invertSelection = function ( ) {
self . $list . invertSelection ( ) ;
} ;
that . selectAll = function ( ) {
self . $list . selectAll ( ) ;
} ;
2013-07-13 23:07:25 +00:00
that . updateItem = function ( id , data ) {
2013-08-09 12:52:18 +00:00
self . options . clips [ Ox . getIndexById ( self . options . clips , id ) ] = data ;
2013-07-13 23:07:25 +00:00
[ 'in' , 'out' , 'duration' ] . forEach ( function ( key ) {
self . $list . value ( id , key , data [ key ] ) ;
} ) ;
} ;
return that ;
} ;