// vim: et:ts=4:sw=4:sts=4:ft=javascript 'use strict'; /*@ Ox.VideoEditor VideoEditor Object () -> VideoEditor Object (options) -> VideoEditor Object (options, self) -> VideoEditor Object options Options object self shared private variable @*/ // fixme: should be VideoAnnotationEditor Ox.VideoEditor = function(options, self) { self = self || {}; var that = Ox.Element({}, self) .defaults({ annotationsFont: 'small', annotationsRange: 'all', annotationsSize: 0, annotationsSort: 'position', censored: [], cuts: [], duration: 0, enableSubtitles: false, find: '', fps: 25, getFrameURL: null, getLargeTimelineImageURL: null, getSmallTimelineImageURL: null, 'in': 0, height: 0, layers: [], muted: false, out: 0, position: 0, posterFrame: 0, posterFrameControls: false, resolution: 0, showAnnotations: false, showLargeTimeline: true, subtitles: [], tooltips: false, videoRatio: 16/9, videoSize: 'small', video: '', volume: 1, width: 0 }) .options(options || {}) .mousedown(function() { that.gainFocus(); }) .bindEvent({ key_0: toggleMuted, key_shift_0: function() { movePositionBy(-self.options.position); }, key_alt_left: function() { }, key_alt_right: function() { }, key_alt_shift_left: function() { }, key_alt_shift_right: function() { }, key_backslash: function() { select('subtitle'); }, key_closebracket: function() { movePositionTo('subtitle', 1); }, key_comma: function() { movePositionTo('cut', -1); }, key_dot: function() { movePositionTo('cut', 1); }, key_down: function() { movePositionBy(self.sizes.timeline[0].width); }, key_f: function() { setTimeout(function() { self.$findInput.focusInput(true); }); }, key_g: function() { self.results.length && setPosition(getNextPosition('result', 1)); }, key_i: function() { setPoint('in', self.options.position); }, key_left: function() { movePositionBy(-0.04); }, key_o: function() { setPoint('out', self.options.position); }, key_openbracket: function() { movePositionTo('subtitle', -1); }, key_p: playInToOut, key_right: function() { movePositionBy(0.04); }, key_s: function() { // toggleSize }, key_shift_comma: function() { movePositionTo('match', -1); }, key_shift_dot: function() { movePositionTo('match', 1); }, key_shift_down: function() { movePositionBy(self.options.duration); }, key_shift_g: function() { self.results.length && setPosition(getNextPosition('result', -1)); }, key_shift_left: function() { movePositionBy(-1); }, key_shift_i: function() { goToPoint('in'); }, key_shift_o: function() { goToPoint('out'); }, key_shift_p: function() { // go to poster frame }, key_shift_right: function() { movePositionBy(1); }, key_shift_up: function() { movePositionBy(-self.options.position); }, key_slash: function() { select('cut'); }, key_space: togglePaused, key_up: function() { movePositionBy(-self.sizes.timeline[0].width); } }); Ox.extend(self, { $player: [], $timeline: [], controlsHeight: 16, margin: 8, }); self.words = []; Ox.forEach(Ox.count(Ox.words(self.options.subtitles.map(function(subtitle) { return subtitle.text; }).join(' '))), function(count, word) { self.words.push({count: count, word: word}); }); self.words = self.words.sort(function(a, b) { return b.count - a.count; }).map(function(obj) { return obj.word; }); self.$editor = Ox.Element() .addClass('OxVideoEditor') .click(function(e) { var $target = $(e.target); !$target.is('.OxPosition') && !$target.is('input') && that.gainFocus(); }); self.sizes = getSizes(); ['play', 'in', 'out'].forEach(function(type, i) { self.$player[i] = Ox.VideoPlayer({ censored: self.options.censored, controlsBottom: type == 'play' ? ['play', 'playInToOut', 'volume', 'size', 'space', 'position'] : ['goto', 'set', 'space', 'position'], duration: self.options.duration, enableMouse: true, enablePosition: true, enableSubtitles: self.options.enableSubtitles, externalControls: true, find: self.options.find, height: self.sizes.player[i].height, id: 'player' + Ox.toTitleCase(type), 'in': self.options['in'], muted: self.options.muted, out: self.options.out, paused: true, position: type == 'play' ? self.options.position : self.options[type], posterFrame: self.options.posterFrame, resolution: self.options.resolution, showMarkers: true, showMilliseconds: 3, sizeIsLarge: self.options.videoSize == 'large', subtitles: self.options.subtitles, type: type, video: type == 'play' ? self.options.video : self.options.getFrameURL, volume: self.options.volume, width: self.sizes.player[i].width }) .css({ left: self.sizes.player[i].left + 'px', top: self.sizes.player[i].top + 'px' }) .bindEvent(type == 'play' ? { muted: function(data) { that.triggerEvent('muted', data); }, paused: function(data) { that.triggerEvent('paused', data); }, playing: function(data) { setPosition(data.position, true); }, position: function(data) { setPosition(data.position); }, resolution: function(data) { that.triggerEvent('resolution', data); }, size: toggleSize, subtitles: function(data) { that.triggerEvent('subtitles', data); }, volume: function(data) { that.triggerEvent('volume', data); } } : { gotopoint: function() { goToPoint(type); }, position: function(data) { setPoint(type, data.position); }, setpoint: function() { setPoint(type, self.options.position); } }) .appendTo(self.$editor); }); self.$timeline[0] = Ox.LargeVideoTimeline({ cuts: self.options.cuts, duration: self.options.duration, find: self.options.find, getImageURL: self.options.getLargeTimelineImageURL, id: 'timelineLarge', 'in': self.options['in'], //matches: self.options.matches, out: self.options.out, position: self.options.position, subtitles: self.options.subtitles, type: 'editor', width: self.sizes.timeline[0].width }) .css({ left: self.sizes.timeline[0].left + 'px', top: self.sizes.timeline[0].top + 'px' }) .bindEvent({ position: function(data) { setPosition(data.position); } }) .appendTo(self.$editor); self.$timeline[1] = Ox.BlockVideoTimeline({ cuts: self.options.cuts, duration: self.options.duration, find: self.options.find, getImageURL: self.options.getSmallTimelineImageURL, id: 'timelineSmall', 'in': self.options['in'], out: self.options.out, position: self.options.position, results: find(self.options.find), showPointMarkers: true, showSubtitles: true, subtitles: self.options.subtitles, videoId: self.options.videoId, width: self.sizes.timeline[1].width }) .css({ left: self.sizes.timeline[1].left + 'px', top: self.sizes.timeline[1].top + 'px', }) .bindEvent({ position: function(data) { setPosition(data.position); } }) .appendTo(self.$editor); self.$annotations = Ox.Element() .css({ overflowY: 'auto' }); self.$annotationPanel = []; self.options.layers.forEach(function(layer, i) { self.$annotationPanel[i] = Ox.AnnotationPanel( Ox.extend({ font: self.options.annotationsFont, 'in': self.options['in'], out: self.options.out, position: self.options.position, range: self.options.annotationsRange, sort: self.options.annotationsSort, width: self.options.annotationsSize - Ox.UI.SCROLLBAR_SIZE }, layer) ) .bindEvent({ add: function(data) { data.layer = layer.id; data['in'] = self.options['in']; data.out = self.options.out; that.triggerEvent('addannotation', data); }, remove: function(data) { that.triggerEvent('removeannotation', { id: data.id, layer: layer.id }); }, select: function(data) { self.options.layers.forEach(function(layer_, i_) { if (i_ != i) { // FIXME: the way AnnotationPanel is set up, // it does not actually have that method // self.$annotationPanel[i_].deselectItems(); } }); selectAnnotation(data); }, submit: editAnnotation }) .appendTo(self.$annotations); }); self.$videobar = Ox.Bar({ size: 16 }).addClass('OxVideoPlayer'); self.resolutions = []; Ox.forEach(self.options.video, function(url, resolution) { Ox.Log('Video', url, resolution); self.resolutions.push( {id: resolution + '', title: resolution + 'p', checked: self.options.resolution == resolution} ); }); self.$keyboardShortcuts = $('
').css({margin: '16px'}); [ {key: Ox.UI.symbols.space, action: 'Play/Pause'}, {key: 'P', action: 'Play In to Out'}, {key: '0', action: 'Mute/Unmute'}, {key: '-', action: 'Turn Volume Down'}, {key: '+', action: 'Turn Volume Up'}, {key: Ox.UI.symbols.arrow_left, action: 'Go One Frame Back'}, {key: Ox.UI.symbols.arrow_right, action: 'Go One Frame Forward'}, {key: Ox.UI.symbols.shift + Ox.UI.symbols.arrow_left, action: 'Go One Second Back'}, {key: Ox.UI.symbols.shift + Ox.UI.symbols.arrow_right, action: 'Go One Second Forward'}, {key: Ox.UI.symbols.arrow_up, action: 'Go One Line Up'}, {key: Ox.UI.symbols.arrow_down, action: 'Go One Line Down'}, {key: Ox.UI.symbols.shift + Ox.UI.symbols.arrow_up, action: 'Go to First Frame'}, {key: Ox.UI.symbols.shift + Ox.UI.symbols.arrow_down, action: 'Go to Last Frame'}, {key: 'I', action: 'Set In Point'}, {key: 'O', action: 'Set Out Point'}, {key: Ox.UI.symbols.shift + 'I', action: 'Go to Out Point'}, {key: Ox.UI.symbols.shift + 'O', action: 'Go to Out Point'}, {key: '[', action: 'Go to Previous Annotation'}, {key: ']', action: 'Go to Next Annotation'}, {key: '\\', action: 'Select Current Annotation'}, {key: '<', action: 'Go to Previous Cut'}, {key: '>', action: 'Go to Next Cut'}, {key: '/', action: 'Select Current Cut'}, {key: 'F', action: 'Find'}, {key: Ox.UI.symbols.shift + 'G', action: 'Go to Previous Result'}, {key: 'G', action: 'Go to Next Result'}, {key: 'S', action: 'Select Current Annotation'}, {key: 'E', action: 'Edit Selected Annotation'}, {key: Ox.UI.symbols['return'], action: 'Submit'}, {key: Ox.UI.symbols.escape, action: 'Cancel'}, ].forEach(function(shortcut) { self.$keyboardShortcuts.append( $('
').css({display: 'table-row'}) .append( $('
').css({ display: 'table-cell', height: '16px', paddingRight: '16px', //fontWeight: 'bold', textAlign: 'right' }) .html(shortcut.key) ) .append( $('
').css({display: 'table-cell'}) .html(shortcut.action) ) ); }); self.$videoMenuButton = Ox.MenuButton({ items: [ {id: 'toggleSize', title: 'Large Player', checked: self.options.playerSize == 'large', keyboard: 'shift +'}, {}, {group: 'resolution', min: 1, max: 1, items: self.resolutions}, {}, {id: 'largeTimeline', title: 'Hide Large Timeline', disabled: true}, {id: 'subtitlesTimeline', title: 'Hide Subtitles on Large Timeline', disabled: true}, {}, {id: 'downloadVideo', title: 'Download Video...', disabled: true}, {id: 'downloadSelection', title: 'Download Selection...', disabled: true}, {id: 'embedSelection', title: 'Embed Selection...', disabled: true}, {}, {id: 'keyboard', title: 'Keyboard Shortcuts...', keyboard: 'h'} ], style: 'square', title: 'set', tooltip: 'Actions and Settings', type: 'image' }) .css({float: 'left'}) .bindEvent({ click: function(data) { var id = data.id; if (id == 'keyboard') { var dialog = Ox.Dialog({ buttons: [ Ox.Button({id: 'close', title: 'Close'}) .bindEvent({click: function() { dialog.close(); }}) ], content: self.$keyboardShortcuts, height: 384, keys: {enter: 'close', escape: 'close'}, title: 'Keyboard Shortcuts', width: 256 }).open(); } }, change: function(data) { var id = data.id; if (id == 'toggleSize') { toggleSize(); } else if (data.id == 'resolution') { self.options.resolution = parseInt(data.checked[0].id); self.$player[0].options({resolution: self.options.resolution}); } } }) .appendTo(self.$videobar); self.$selectButton = Ox.Button({ style: 'symbol', title: 'select', type: 'image' }) .css({float: 'left'}) .bindEvent({ click: function() { self.$menuButton.find('input').trigger('click') } }); //.appendTo(self.$videobar); self.$resolutionSelect = Ox.Select({ items: self.resolutions, width: 48, }) .css({float: 'left'}) .bindEvent({ change: function(data) { } }); //.appendTo(self.$videobar); if (self.options.posterFrameControls) { self.$goToPosterButton = Ox.Button({ style: 'symbol', title: 'goToPoster', tooltip: 'Go to Poster Frame', type: 'image' }) .css({float: 'left'}) .bindEvent({ click: function() { setPosition(self.options.posterFrame); } }) .appendTo(self.$videobar); self.$setPosterButton = Ox.Button({ disabled: true, style: 'symbol', title: 'setPoster', tooltip: 'Set Poster Frame', type: 'image' }) .css({float: 'left'}) .bindEvent({ click: function() { self.$goToPosterButton.toggleOption('disabled'); self.$setPosterButton.toggleOption('disabled'); self.$unlockPosterButton.toggle(); } }) .appendTo(self.$videobar); 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.toggleOption('disabled'); } }) .appendTo(self.$videobar); } self.$clearButton = Ox.Button({ disabled: self.options.find === '', style: 'symbol', title: 'close', tooltip: 'Clear', type: 'image' }) .css({float: 'right'}) .bindEvent({ click: function() { self.$findInput.clearInput(); submitFindInput(''); } }) .appendTo(self.$videobar); self.$findInput = Ox.Input({ autocomplete: self.words, autocompleteReplace: true, autocompleteSelect: true, autocompleteSelectHighlight: true, autocompleteSelectMax: 10, autocompleteSelectSubmit: true, changeOnKeypress: true, placeholder: 'Find...', value: self.options.find, width: 96 }) .css({float: 'right', background: 'transparent'}) .bindEvent({ change: function(data) { submitFindInput(data.value, false); }, submit: function(data) { submitFindInput(data.value, true); } }) .appendTo(self.$videobar); self.$findButton = Ox.Button({ //disabled: true, style: 'symbol', title: 'find', tooltip: 'Find', type: 'image' }) .css({float: 'right'}) .bindEvent({ click: function() { } }); //.appendTo(self.$videobar); self.$nextButton = Ox.Button({ disabled: true, style: 'symbol', title: 'arrowRight', tooltip: 'Next Result', type: 'image' }) .css({float: 'right'}) .bindEvent({ click: function() { setPosition(getNextPosition('result', 1)); } }) .appendTo(self.$videobar); self.$previousButton = Ox.Button({ disabled: true, style: 'symbol', title: 'arrowLeft', tooltip: 'Previous Result', type: 'image' }) .css({float: 'right'}) .bindEvent({ click: function() { setPosition(getNextPosition('result', -1)); } }) .appendTo(self.$videobar); self.$results = $('
') .css({float: 'right', width: '36px', padding: '2px 4px 0 0', fontSize: '9px', textAlign: 'right', cursor: 'default', opacity: 0.25}) .html('0') .appendTo(self.$videobar.$element); self.$annotationsbar = Ox.Bar({ size: 16 }).addClass('OxVideoPlayer'); self.$annotationsMenuButton = Ox.MenuButton({ items: [ {id: 'showannotations', title: 'Show Annotations', disabled: true}, {group: 'range', min: 1, max: 1, items: [ {id: 'position', title: 'At Current Position', checked: self.options.annotationsRange == 'position'}, {id: 'selection', title: 'In Current Selection', checked: self.options.annotationsRange == 'selection'}, {id: 'all', title: 'All', checked: self.options.annotationsRange == 'all'} ]}, {}, {id: 'sortannotations', title: 'Sort Annotations', disabled: true}, {group: 'sort', min: 1, max: 1, items: [ {id: 'position', title: 'By Position', checked: self.options.annotationsSort == 'position'}, {id: 'duration', title: 'By Duration', checked: self.options.annotationsSort == 'duration'}, {id: 'text', title: 'By Text', checked: self.options.annotationsSort == 'text'} ]}, {}, {id: 'fontsize', title: 'Font Size', disabled: true}, {group: 'font', min: 1, max: 1, items: [ {id: 'small', title: 'Small', checked: self.options.annotationsFont == 'small'}, {id: 'medium', title: 'Medium', checked: self.options.annotationsFont == 'medium'}, {id: 'large', title: 'Large', checked: self.options.annotationsFont == 'large'} ]} ], style: 'square', title: 'set', tooltip: 'Actions and Settings', type: 'image' }) .css({float: 'left'}) .bindEvent({ change: function(data) { var set = {}; set[data.id] = data.checked[0].id; self.$annotationPanel.forEach(function($panel) { $panel.options(set); }); that.triggerEvent('annotations' + Ox.toTitleCase(data.id), set); } }) .appendTo(self.$annotationsbar); that.$element = Ox.SplitPanel({ elements: [ { element: Ox.SplitPanel({ elements: [ { element: self.$videobar, size: 16 }, { element: self.$editor } ], orientation: 'vertical' }) }, { collapsed: !self.options.showAnnotations, collapsible: true, element: Ox.SplitPanel({ elements: [ { element: self.$annotationsbar, size: 16 }, { element: self.$annotations, } ], orientation: 'vertical' }) .bindEvent({ resize: resizeAnnotations, resizeend: resizeendAnnotations, toggle: toggleAnnotations }), resizable: true, resize: [192, 256, 320, 384], size: self.options.annotationsSize, tooltip: self.options.tooltips ? 'annotations' : false } ], orientation: 'horizontal' }); // we need a timeout so that a chained bindEvent // actually catches the event self.options.find && setTimeout(function() { submitFindInput(self.options.find, true); }, 0); function editAnnotation(data) { data['in'] = self.options['in']; data.out = self.options.out; that.triggerEvent('editannotation', data); } 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; } // fixme: why not goToNextPosition()? function getNextPosition(type, direction) { var found = false, position = 0, positions; if (type == 'cut') { positions = self.options.cuts; } else if (type == 'result') { positions = self.results.map(function(v) { return v['in']; }); } else if (type == 'subtitle') { positions = self.options.subtitles.map(function(v) { return v['in']; }); } direction == -1 && positions.reverse(); Ox.forEach(positions, function(v) { if (direction == 1 ? v > self.options.position : v < self.options.position) { position = v; found = true; return false; } }); direction == -1 && positions.reverse(); if (!found) { position = positions[direction == 1 ? 0 : positions.length - 1]; } return position; } function getPoints(type) { var found = false, points, positions = []; if (type == 'cut') { positions = self.options.cuts; } else if (type == 'match') { // ... } else if (type == 'subtitle') { self.options.subtitles.forEach(function(v, i) { positions.push(v['in']); positions.push(v.out); }); } positions.indexOf(0) == -1 && positions.unshift(0); positions.indexOf(self.options.duration) == -1 && positions.push(self.options.duration); Ox.forEach(positions, function(v, i) { if (v > self.options.position) { points = [positions[i - 1], positions[i]]; found = true; return false; } }); return points; } function getSizes(scrollbarIsVisible) { //Ox.Log('Video', 'getSizes', scrollbarIsVisible) var scrollbarWidth = Ox.UI.SCROLLBAR_SIZE, contentWidth = self.options.width - (self.options.showAnnotations * self.options.annotationsSize) - 1 - (scrollbarIsVisible ? scrollbarWidth : 0), height, lines, size = { player: [], timeline: [] }, width, widths; if (self.options.videoSize == 'small') { width = 0; widths = Ox.divideInt(contentWidth - 4 * self.margin, 3); [1, 0, 2].forEach(function(v, i) { size.player[v] = { left: (i + 0.5) * self.margin + width, top: self.margin / 2, width: widths[i], height: Math.round(widths[1] / self.options.videoRatio) }; width += widths[i]; }); } else { size.player[0] = { left: self.margin / 2, top: self.margin / 2, width: Math.round((contentWidth - 3 * self.margin + (self.controlsHeight + self.margin) / 2 * self.options.videoRatio) * 2/3), }; size.player[0].height = Math.round(size.player[0].width / self.options.videoRatio); size.player[1] = { left: size.player[0].left + size.player[0].width + self.margin, top: size.player[0].top, width: contentWidth - 3 * self.margin - size.player[0].width }; size.player[1].height = Math.ceil(size.player[1].width / self.options.videoRatio); size.player[2] = { left: size.player[1].left, top: size.player[0].top + size.player[1].height + self.controlsHeight + self.margin, width: size.player[1].width, height: size.player[0].height - size.player[1].height - self.controlsHeight - self.margin }; } size.timeline[0] = { left: self.margin / 2, top: size.player[0].height + self.controlsHeight + 1.5 * self.margin, width: contentWidth - 2 * self.margin, height: 64 }; size.timeline[1] = { left: size.timeline[0].left, top: size.timeline[0].top + size.timeline[0].height + self.margin, width: size.timeline[0].width }; lines = Math.ceil(self.options.duration / size.timeline[1].width); height = getHeight(); self.$editor.css({ overflowY: (scrollbarIsVisible && height <= self.options.height - 16) ? 'scroll' : 'auto' }); //Ox.Log('Video', 'getSizes', scrollbarIsVisible, height, self.options.height, 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 + (lines + 3) * self.margin; } } function goToPoint(point) { setPosition(self.options[point]); } function movePositionBy(sec) { setPosition(Ox.limit(self.options.position + sec, 0, self.options.duration)); } function movePositionTo(type, direction) { setPosition(getNextPosition(type, direction)); } function playInToOut() { self.$player[0].playInToOut(); } function resizeAnnotations(data) { self.options.annotationsSize = data.size; setSizes(); } function resizeendAnnotations(data) { that.triggerEvent('annotationsSize', {size: data.size}); } function resizeEditor(data) { var width = data.size - 2 * margin + 100; resizeVideoPlayers(width); $timelineLarge.options({ width: width }); $timelineSmall.options({ width: width }); } function resizePlayers() { self.$player.forEach(function(v, i) { v.options({ width: size[i].width, height: size[i].height }) .css({ left: size[i].left + 'px', top: size[i].top + 'px', }); }); } function selectAnnotation(data) { //setPosition(data['in']); setPoint('in', data['in']); setPoint('out', data.out); } function select(type) { self.options.points = getPoints(type); setPoints(); } function setPoint(point, position) { var otherPoint = point == 'in' ? 'out' : 'in'; self.options[point] = position; self.$player.forEach(function($player) { $player.options(point, self.options[point]); }); self.$player[point == 'in' ? 1 : 2].options({ position: self.options[point] }); self.$timeline.forEach(function($timeline) { $timeline.options(point, self.options[point]); }); if (self.options['in'] > self.options.out) { setPoint(point == 'in' ? 'out' : 'in', position); } self.$annotationPanel.forEach(function($panel) { $panel.options({ 'in': self.options['in'], out: self.options.out }); }); that.triggerEvent('points', { 'in': self.options['in'], out: self.options.out }); } function setPosition(position, playing) { self.options.position = position; !playing && self.$player[0].options({ position: self.options.position }); self.$timeline.forEach(function($timeline) { $timeline.options({ position: self.options.position }); }); self.$annotationPanel.forEach(function($panel) { $panel.options({ position: self.options.position }); }); !playing && that.triggerEvent('position', { position: self.options.position }); } function setSizes() { self.sizes = getSizes(); self.$player.forEach(function($player, i) { $player.options({ height: self.sizes.player[i].height, width: self.sizes.player[i].width }) .css({ left: self.sizes.player[i].left + 'px', top: self.sizes.player[i].top + 'px' }); }); self.$timeline.forEach(function($timeline, i) { $timeline.options({ width: self.sizes.timeline[i].width }) .css({ left: self.sizes.timeline[i].left + 'px', top: self.sizes.timeline[i].top + 'px' }); }); } 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.$player.forEach(function($player) { $player.options({find: self.options.find}); }); self.$timeline.forEach(function($timeline) { $timeline.options({find: self.options.find}); }); self.$timeline[1].options({results: self.results}); if (hasPressedEnter) { that.triggerEvent('find', {find: self.options.find}); if (self.results.length) { setPosition(getNextPosition('result', 1)); } else { self.$findInput.focusInput(true); } } } function toggleAnnotations(data) { self.options.showAnnotations = !data.collapsed; setSizes(); that.triggerEvent('toggleannotations', { showAnnotations: self.options.showAnnotations }); } function toggleMuted() { self.$player[0].toggleMuted(); } function togglePaused() { self.$player[0].togglePaused(); /* fixme self.$player[0].options('paused') && that.triggerEvent('position', { }); */ } function toggleSize() { self.options.videoSize = self.options.videoSize == 'small' ? 'large' : 'small'; setSizes(); that.triggerEvent('togglesize', { size: self.options.videoSize }); } self.setOption = function(key, value) { if (key == 'width' || key == 'height') { Ox.Log('Video', 'XXXX setSizes', key, value, self.options.width, self.options.height) setSizes(); } else if (key == 'position') { setPosition(value); } else if (key == 'showAnnotations') { that.$element.toggle(1); } }; /*@ addAnnotation add annotation (layer, item) -> add annotation to layer layer layer id item annotation to add @*/ that.addAnnotation = function(layer, item) { var i = Ox.getIndexById(self.options.layers, layer); self.$annotationPanel[i].addItem(item); }; /*@ removeAnnotation remove annotation (layer, ids) -> remove annotation from layer layer layer id ids array of item ids to remove @*/ that.removeAnnotation = function(layer, id) { var i = Ox.getIndexById(self.options.layers, layer); self.$annotationPanel[i].removeItem(id); }; return that; };