diff --git a/source/Ox.UI/css/Ox.UI.css b/source/Ox.UI/css/Ox.UI.css index 763e38c2..bc333c9d 100644 --- a/source/Ox.UI/css/Ox.UI.css +++ b/source/Ox.UI/css/Ox.UI.css @@ -806,10 +806,10 @@ OxEditable } .OxEditableElement div.OxInput { padding: 0 1px 0 0; - //margin-bottom: -3px; } .OxEditableElement input.OxInput { padding: 0 1px 0 0; + //padding: 0; border: 0; } .OxEditableElement textarea.OxInput { diff --git a/source/Ox.UI/js/Form/Ox.ArrayEditable.js b/source/Ox.UI/js/Form/Ox.ArrayEditable.js index 395dfeae..a9adcc11 100644 --- a/source/Ox.UI/js/Form/Ox.ArrayEditable.js +++ b/source/Ox.UI/js/Form/Ox.ArrayEditable.js @@ -28,7 +28,9 @@ Ox.ArrayEditable = function(options, self) { anyclick: anyclick, doubleclick: doubleclick, key_delete: deleteItem, - key_enter: editItem, + key_enter: function() { + that.editItem(); + }, key_escape: selectNone, key_down: self.options.type == 'input' ? selectLast : selectNext, key_left: self.options.type == 'input' ? selectPrevious : selectFirst, @@ -81,23 +83,12 @@ Ox.ArrayEditable = function(options, self) { var $target = $(e.target), $parent = $target.parent(); if ($parent.is('.OxEditableElement')) { - that.editItem(self.options.selected); + that.editItem(); } else if(!$target.is('.OxInput')) { that.triggerEvent('add'); } } - function editItem() { - if (self.selected > -1) { - Ox.forEach(self.$items, function($item) { - if ($item.data('position') == self.selected) { - $item.triggerEvent('doubleclick'); - return false; - } - }); - } - } - function getSelectedId() { return self.selected > -1 ? self.options.items[self.selected].id : ''; } @@ -131,18 +122,21 @@ Ox.ArrayEditable = function(options, self) { .data({position: i}) .bindEvent({ blur: function(data) { + that.gainFocus(); that.triggerEvent('blur', data); }, cancel: function(data) { - + that.gainFocus(); + Ox.print("GAINING FOCUS!") + that.triggerEvent('blur', data); }, edit: function(data) { self.editing = true; that.triggerEvent('edit', data); }, submit: function(data) { - Ox.Log("AE", "SUBMIT", data); - submit(i, data.value); + that.gainFocus(); + submitItem(i, data.value); } }) .appendTo(that); @@ -161,6 +155,7 @@ Ox.ArrayEditable = function(options, self) { self.selected = idOrPosition; self.options.selected = getSelectedId(); } + Ox.print('SELECT ITEM', self.options.selected, self.selected); that.find('.OxSelected').removeClass('OxSelected'); self.selected > -1 && self.$items[self.selected].addClass('OxSelected'); triggerSelectEvent(); @@ -191,14 +186,13 @@ Ox.ArrayEditable = function(options, self) { } } - function submit(position, value) { + function submitItem(position, value) { var item = self.options.items[position]; if (value === '') { - deleteItem(); - } /*else if (item.value === value) { + } else if (item.value === value) { that.triggerEvent('blur'); - } else*/ { + } else { that.triggerEvent('submit', { id: item.id, value: value @@ -246,15 +240,24 @@ Ox.ArrayEditable = function(options, self) { }; that.blurItem = function() { - Ox.Log('AE', 'bI', self.selected); - self.selected > -1 && self.$items[self.selected].options({editing: false}); + self.options.selected && self.$items[self.selected].options({ + editing: false + }); }; - that.editItem = function(id) { - Ox.Log('AE', 'editItem', id); - self.options.selected = id; - self.selected = getSelectedPosition(); - editItem(); + that.editItem = function() { + if (self.options.selected) { + Ox.forEach(self.$items, function($item) { + if ($item.data('position') == self.selected) { + $item.triggerEvent('doubleclick'); + return false; + } + }); + } + }; + + that.reloadItems = function() { + renderItems(); }; that.removeItem = function(position) { diff --git a/source/Ox.UI/js/Video/Ox.AnnotationFolder.js b/source/Ox.UI/js/Video/Ox.AnnotationFolder.js new file mode 100644 index 00000000..4ff22721 --- /dev/null +++ b/source/Ox.UI/js/Video/Ox.AnnotationFolder.js @@ -0,0 +1,229 @@ +// vim: et:ts=4:sw=4:sts=4:ft=javascript + +'use strict'; + +/*@ +Ox.AnnotationFolder AnnotationFolder Object + () -> AnnotationFolder Object + (options) -> AnnotationFolder Object + (options, self) -> AnnotationFolder Object + options Options object + editable If true, annotations can be added + id id + items items + title title + type panel type + width + self shared private variable +@*/ + +Ox.AnnotationFolder = function(options, self) { + + self = self || {}; + var that = Ox.Element({}, self) + .defaults({ + collapsed: false, + editable: false, + id: '', + 'in': 0, + item: '', + items: [], + out: 0, + position: 0, + range: 'all', + selected: '', + sort: 'position', + title: '', + type: 'text', + users: 'all', + width: 0 + }) + .options(options || {}); + + self.sort = getSort(); + + that.setElement( + Ox.CollapsePanel({ + collapsed: self.options.collapsed, + extras: self.options.editable ? [ + Ox.Button({ + id: 'add', + style: 'symbol', + title: 'add', + tooltip: 'Add ' + self.options.item, + type: 'image' + }).bindEvent({ + click: function(data) { + that.triggerEvent('add', {value: ''}); + } + }) + ] : [], + size: 16, + title: self.options.title + }) + .addClass('OxAnnotationFolder') + .bindEvent({ + toggle: togglePanel + }) + ); + that.$content = that.$element.$content; + + if (self.options.type == 'event') { + self.$annotations = Ox.Element(); + } else if (self.options.type == 'place') { + self.$annotations = Ox.Element(); + } else if (['string', 'text'].indexOf(self.options.type) > -1) { + self.$annotations = Ox.ArrayEditable({ + editable: self.options.editable, + items: getAnnotations(), + selected: self.options.selected, + sort: self.sort, + submitOnBlur: false, + width: self.options.type == 'text' ? self.options.width + 8 : self.options.width, + type: self.options.type == 'text' ? 'textarea' : 'input' + }) + .bindEvent({ + add: function(data) { + that.triggerEvent('add', {value: data.value || ''}); + }, + blur: function() { + that.triggerEvent('blur'); + }, + 'delete': function(data) { + that.triggerEvent('remove', {id: data.id}); + }, + edit: function() { + self.editing = true; + that.triggerEvent('edit'); + }, + select: selectAnnotation, + submit: submitAnnotation, + key_space: function() { + that.triggerEvent('paused'); + } + }); + } + self.$annotations.appendTo(that.$content); + + self.options.selected && setTimeout(function() { + selectAnnotation({id: self.options.selected}); + }, 0); + + function getAnnotations() { + return self.options.items.filter(function(item) { + return self.editing && item.id == self.options.selected || ( + ( + self.options.range == 'all' || ( + self.options.range == 'selection' + && item['in'] < self.options.out + && item.out > self.options['in'] + ) || ( + self.options.range == 'position' + && item['in'] <= self.options.position + && item.out >= self.options.position + ) + ) && ( + self.options.users == 'all' + || self.options.users.indexOf(item.user) > -1 + ) + ); + }); + } + + function getSort() { + return ({ + duration: ['-duration', '+in', '+value'], + position: ['+in', '-duration', '+value'], + text: ['+value', '+in', '-duration'] + })[self.options.sort]; + } + + function selectAnnotation(data) { + var item = Ox.getObjectById(self.options.items, data.id); + self.options.selected = item ? data.id : ''; + that.triggerEvent('select', Ox.extend(data, item ? { + 'in': item['in'], + out: item.out, + layer: self.options.id + } : {})); + } + + function submitAnnotation(data) { + var item = Ox.getObjectById(self.options.items, data.id); + item.value = data.value; + self.editing = false; + Ox.print('??:', self.options.items[0], self.$annotations.options('items')[0]) + //self.$annotations.options({items: self.options.items}); + self.options.sort == 'text' && self.$annotations.reloadItems(); + that.triggerEvent('submit', item); + } + + function togglePanel() { + self.options.collapsed = !self.options.collapsed; + that.triggerEvent('toggle', {collapsed: self.options.collapsed}); + } + + self.setOption = function(key, value) { + if (['in', 'out'].indexOf(key) > -1 && self.editing) { + var index = Ox.getIndexById(self.options.items, self.options.selected); + self.options.items[index][key] = value; + self.options.items[index].duration = self.options.out - self.options['in']; + } + if (key == 'in') { + //fixme: array editable should support item updates while editing + self.editing || self.options.range == 'selection' && self.$annotations.options({ + items: getAnnotations() + }); + } else if (key == 'out') { + self.editing || self.options.range == 'selection' && self.$annotations.options({ + items: getAnnotations() + }); + } else if (key == 'position') { + self.editing || self.options.range == 'position' && self.$annotations.options({ + items: getAnnotations() + }); + } else if (key == 'range') { + self.$annotations.options({items: getAnnotations()}); + } else if (key == 'selected') { + self.$annotations.options({selected: value}); + } else if (key == 'sort') { + self.sort = getSort(); + self.$annotations.options({sort: self.sort}); + } else if (key == 'users') { + Ox.print('USERS ->', value) + self.$annotations.options({items: getAnnotations()}); + } + }; + + /*@ + addItem addItem + @*/ + that.addItem = function(item) { + var pos = 0; + self.options.items.splice(pos, 0, item); + self.$annotations.addItem(pos, item); + self.$annotations.editItem(item.id); + }; + + that.blurItem = function() { + self.$annotations.blurItem(); + }; + + that.editItem = function() { + self.$annotations.editItem(); + }; + + /*@ + removeItems removeItems + @*/ + /* + that.removeItem = function(id) { + var pos = Ox.getIndexById(self.options.items, id); + self.options.items.splice(pos, 1); + self.$annotations.removeItems && self.$annotations.removeItems([id]); + }; + */ + + return that; + +}; diff --git a/source/Ox.UI/js/Video/Ox.AnnotationPanel.js b/source/Ox.UI/js/Video/Ox.AnnotationPanel.js index 61b4280d..74cf3b93 100644 --- a/source/Ox.UI/js/Video/Ox.AnnotationPanel.js +++ b/source/Ox.UI/js/Video/Ox.AnnotationPanel.js @@ -1,20 +1,7 @@ -// vim: et:ts=4:sw=4:sts=4:ft=javascript - 'use strict'; /*@ -Ox.AnnotationPanel AnnotationPanel Object - () -> AnnotationPanel Object - (options) -> AnnotationPanel Object - (options, self) -> AnnotationPanel Object - options Options object - editable If true, annotations can be added - id id - items items - title title - type panel type - width - self shared private variable +Ox.AnnotationPanel Video Annotation Panel @*/ Ox.AnnotationPanel = function(options, self) { @@ -22,195 +9,287 @@ Ox.AnnotationPanel = function(options, self) { self = self || {}; var that = Ox.Element({}, self) .defaults({ - collapsed: false, editable: false, - id: '', - 'in': 0, - item: '', - items: [], - out: 0, - position: 0, + font: 'small', + layers: [], range: 'all', selected: '', + showFonts: false, + showLayers: {}, + showUsers: false, sort: 'position', - title: '', - type: 'text', - width: 0 + width: 256 }) - .options(options || {}); + .options(options || {}) + .addClass('OxAnnotationPanel'); - self.sort = getSort(); - - that.setElement( - Ox.CollapsePanel({ - collapsed: self.options.collapsed, - extras: self.options.editable ? [ - Ox.Button({ - id: 'add', - style: 'symbol', - title: 'add', - tooltip: 'Add ' + self.options.item, - type: 'image' - }).bindEvent({ - click: function(data) { - that.triggerEvent('add', {value: ''}); - } - }) - ] : [], - size: 16, - title: self.options.title - }) - .addClass('OxAnnotationPanel') - .bindEvent({ - toggle: togglePanel - }) - ); - that.$content = that.$element.$content; - - if (self.options.type == 'event') { - self.$annotations = Ox.Element(); - } else if (self.options.type == 'place') { - self.$annotations = Ox.Element(); - } else if (['string', 'text'].indexOf(self.options.type) > -1) { - self.$annotations = Ox.ArrayEditable({ - editable: self.options.editable, - items: getAnnotations(), - selected: self.options.selected, - sort: self.sort, - submitOnBlur: false, - width: self.options.type == 'text' ? self.options.width + 8 : self.options.width, - type: self.options.type == 'text' ? 'textarea' : 'input' + if (self.options.showUsers) { + self.users = Ox.sort(Ox.unique(Ox.flatten( + self.options.layers.map(function(layer) { + return layer.items.map(function(item) { + return item.user; + }); }) + ))); + self.enabledUsers = 'all'; + } + + self.$menubar = Ox.Bar({ + size: 16 + }) + .addClass('OxVideoPlayer'); + + self.$optionsMenuButton = Ox.MenuButton({ + items: Ox.merge( + [ + {id: 'showannotations', title: 'Show Annotations', disabled: true}, + {group: 'range', min: 1, max: 1, items: [ + {id: 'all', title: 'All', checked: self.options.range == 'all'}, + {id: 'selection', title: 'In Current Selection', checked: self.options.range == 'selection'}, + {id: 'position', title: 'At Current Position', checked: self.options.range == 'position'} + ]}, + {}, + {id: 'sortannotations', title: 'Sort Annotations', disabled: true}, + {group: 'sort', min: 1, max: 1, items: [ + {id: 'position', title: 'By Position', checked: self.options.sort == 'position'}, + {id: 'duration', title: 'By Duration', checked: self.options.sort == 'duration'}, + {id: 'text', title: 'By Text', checked: self.options.sort == 'text'} + ]} + ], + self.options.showFonts ? [ + {}, + {id: 'fontsize', title: 'Font Size', disabled: true}, + {group: 'font', min: 1, max: 1, items: [ + {id: 'small', title: 'Small', checked: self.options.font == 'small'}, + {id: 'medium', title: 'Medium', checked: self.options.font == 'medium'}, + {id: 'large', title: 'Large', checked: self.options.font == 'large'} + ]} + ] : [], + self.options.showUsers ? [ + {}, + {id: 'users', title: 'Show Users', disabled: true}, + {group: 'users', min: 1, max: -1, items: self.users.map(function(user) { + return {id: user, title: user, checked: true}; + })} + ] : [] + ), + style: 'square', + title: 'set', + tooltip: 'Actions and Settings', + type: 'image' + }) + .css({float: 'left'}) + .bindEvent({ + change: function(data) { + var set = {}; + if (data.id == 'users') { + self.enabledUsers = data.checked.length == self.users.length + ? 'all' + : data.checked.map(function(checked) { + return checked.id; + }); + self.$folder.forEach(function($folder) { + $folder.options({users: self.enabledUsers}); + }); + } else { + set[data.id] = data.checked[0].id; + self.$folder.forEach(function($folder) { + $folder.options(set); + }); + that.triggerEvent('annotations' + data.id, set); + } + } + }) + .appendTo(self.$menubar); + + if (self.options.editable) { + self.$editMenuButton = Ox.MenuButton({ + items: [ + {id: 'edit', title: 'Edit Annotation', disabled: !self.options.selected, keyboard: 'return'}, + {id: 'delete', title: 'Delete Annotation', disabled: !self.options.selected, keyboard: 'delete'}, + {id: 'deselect', title: 'Deselect Annotation', disabled: !self.options.selected, keyboard: 'escape'}, + {}, + {id: 'save', title: 'Save Changes', disabled: true, keyboard: 'shift return'}, + {id: 'undo', title: 'Undo Changes', disabled: true, keyboard: 'escape'} + ], + style: 'square', + title: 'edit', + tooltip: 'Editing Options', + type: 'image' + }) + .css({float: 'right'}) + .bindEvent({ + click: function(data) { + if (data.id == 'delete') { + + } else if (data.id == 'deselect') { + + } else if (data.id == 'edit') { + + } + } + }) + .appendTo(self.$menubar); + } + + self.$folders = Ox.Element().css({overflowY: 'auto'}); + self.$folder = []; + + self.options.layers.forEach(function(layer, i) { + var item = Ox.getObjectById(layer.items, self.options.selected), + selected = item ? item.id : ''; + self.$folder[i] = Ox.AnnotationFolder( + Ox.extend({ + collapsed: !self.options.showLayers[layer.id], + editable: self.options.editable, + font: self.options.font, + 'in': self.options['in'], + out: self.options.out, + position: self.options.position, + range: self.options.range, + selected: selected, + sort: self.options.sort, + width: self.options.width - Ox.UI.SCROLLBAR_SIZE + }, layer) + ) .bindEvent({ add: function(data) { - that.triggerEvent('add', {value: data.value || ''}); + that.triggerEvent('add', Ox.extend({layer: layer.id}, data)); }, blur: function() { that.triggerEvent('blur'); }, - 'delete': function(data) { - that.triggerEvent('remove', {id: data.id}); - }, edit: function() { - self.editing = true; - that.triggerEvent('edit'); + that.triggerEvent('edit') }, - select: selectAnnotation, - submit: submitAnnotation, - key_space: function() { - that.triggerEvent('paused'); + paused: function() { + that.triggerEvent('paused') + }, + 'remove': function(data) { + that.triggerEvent('remove', Ox.extend({layer: layer.id}, data)); + }, + select: function(data) { + selectAnnotation(data, i); + }, + submit: function(data) { + that.triggerEvent('submit', data); + }, + toggle: function(data) { + that.triggerEvent('toggle', Ox.extend({layer: layer.id}, data)); + } + }) + .appendTo(self.$folders); + }); + + that.setElement( + Ox.SplitPanel({ + elements: [ + { + element: self.$menubar, + size: 16 + }, + { + element: self.$folders + } + ], + orientation: 'vertical' + }) + .bindEvent({ + resize: resizeAnnotations, + resizeend: resizeendAnnotations, + toggle: toggleAnnotations + }) + ); + + function getFolder(annotationId) { + var found = false, folder; + Ox.forEach(self.options.layers, function(layer, i) { + Ox.forEach(layer.items, function(item) { + if (item.id == annotationId) { + folder = self.$folder[i]; + found = true; + return false; } }); - } - self.$annotations.appendTo(that.$content); - - self.options.selected && setTimeout(function() { - selectAnnotation({id: self.options.selected}); - }, 0); - - function getAnnotations() { - return self.options.items.filter(function(item) { - return self.options.range == 'all' || ( - self.options.range == 'selection' - && item['in'] < self.options.out - && item.out > self.options['in'] - ) || ( - self.options.range == 'position' - && item['in'] <= self.options.position - && item.out >= self.options.position - ) || self.editing && item.id == self.options.selected + return !found; }); + return folder; } - function getSort() { - return ({ - duration: ['-duration', '+in', '+value'], - position: ['+in', '-duration', '+value'], - text: ['+value', '+in', '-duration'] - })[self.options.sort]; + function selectAnnotation(data, index) { + var height, scrollTop; + if (data.id) { + self.$folder.forEach(function($folder, i) { + i != index && $folder.options({selected: ''}); + }); + } + if (data.top) { + height = self.$folders.height(); + scrollTop = self.$folders.scrollTop(); + data.top -= 60; // 20 + 24 + 16 + Ox.print('HEIGHT', height, 'SCROLLTOP', scrollTop, 'TOP', data.top); + if (data.top < 0 || data.top > height - 16) { + if (data.top < 0) { + scrollTop += data.top - 3; + } else if (data.top > height - 16) { + scrollTop += data.top - height + 14; + } + self.$folders.animate({ + scrollTop: scrollTop + 'px' + }, 0); + } + } + that.triggerEvent('select', data); } - function selectAnnotation(data) { - var item = Ox.getObjectById(self.options.items, data.id); - self.options.selected = item ? data.id : ''; - that.triggerEvent('select', Ox.extend(data, item ? { - 'in': item['in'], - out: item.out, - layer: self.options.id - } : {})); + function resizeAnnotations() { + } - function submitAnnotation(data) { - var item = Ox.getObjectById(self.options.items, data.id); - item.value = data.value; - self.editing = false; - self.$annotations.options({items: self.options.items}); - that.triggerEvent('submit', item); + function resizeendAnnotations() { + } - function togglePanel() { - self.options.collapsed = !self.options.collapsed; - that.triggerEvent('toggle', {collapsed: self.options.collapsed}); + function toggleAnnotations() { + + } + + function updateEditMenu() { + var action = self.options.selected ? 'enableItem' : 'disableItem'; + self.$editMenuButton[action]('edit'); + self.$editMenuButton[action]('delete'); } self.setOption = function(key, value) { - if (['in', 'out'].indexOf(key) > -1 && self.editing) { - var index = Ox.getIndexById(self.options.items, self.options.selected); - self.options.items[index][key] = value; - self.options.items[index].duration = self.options.out - self.options['in']; - } - if (key == 'in') { - //fixme: array editable should support item updates while editing - self.editing || self.options.range == 'selection' && self.$annotations.options({ - items: getAnnotations() - }); - } else if (key == 'out') { - self.editing || self.options.range == 'selection' && self.$annotations.options({ - items: getAnnotations() - }); - } else if (key == 'position') { - self.editing || self.options.range == 'position' && self.$annotations.options({ - items: getAnnotations() - }); - } else if (key == 'range') { - self.$annotations.options({ - items: getAnnotations() + if (['in', 'out', 'position'].indexOf(key) > -1) { + self.$folder.forEach(function($folder) { + $folder.options(key, value); }); } else if (key == 'selected') { - self.$annotations.options({selected: value}); - } else if (key == 'sort') { - self.sort = getSort(); - self.$annotations.options({sort: self.sort}); + self.options.editable && updateEditMenu(); + if (value) { + getFolder(value).options({selected: value}); + } else { + self.$folder.forEach(function($folder) { + $folder.options({selected: ''}); + }) + } } }; - /*@ - addItem addItem - @*/ - that.addItem = function(item) { - var pos = 0; - self.options.items.splice(pos, 0, item); - self.$annotations.addItem(pos, item); - self.$annotations.editItem(item.id); + that.addItem = function(layer, item) { + var i = Ox.getIndexById(self.options.layers, layer); + self.$folder[i].addItem(item); }; that.blurItem = function() { - self.$annotations.blurItem(); + getFolder(self.options.selected).blurItem(); }; - that.editItem = function(id) { - self.$annotations.editItem(id); - }; - - /*@ - removeItems removeItems - @*/ - that.removeItem = function(id) { - var pos = Ox.getIndexById(self.options.items, id); - self.options.items.splice(pos, 1); - self.$annotations.removeItems && self.$annotations.removeItems([id]); + that.editItem = function() { + getFolder(self.options.selected).editItem(); }; return that; - -}; + +}; \ No newline at end of file diff --git a/source/Ox.UI/js/Video/Ox.VideoEditor.js b/source/Ox.UI/js/Video/Ox.VideoEditor.js index b382b192..d58a21b8 100644 --- a/source/Ox.UI/js/Video/Ox.VideoEditor.js +++ b/source/Ox.UI/js/Video/Ox.VideoEditor.js @@ -20,7 +20,7 @@ Ox.VideoEditor = function(options, self) { .defaults({ annotationsFont: 'small', annotationsRange: 'all', - annotationsSize: 0, + annotationsSize: 256, annotationsSort: 'position', censored: [], cuts: [], @@ -44,6 +44,7 @@ Ox.VideoEditor = function(options, self) { showAnnotations: false, showLargeTimeline: true, showLayers: {}, + showUsers: false, subtitles: [], tooltips: false, videoRatio: 16/9, @@ -98,7 +99,7 @@ Ox.VideoEditor = function(options, self) { if (self.editing) { blurAnnotation(); } else if (self.options.selected) { - deselectAnnotation(); + selectAnnotation({id: ''}); } }, key_f: function() { @@ -343,87 +344,19 @@ Ox.VideoEditor = function(options, self) { }) .appendTo(self.$editor); - self.$annotations = Ox.Element() - .css({ - overflowY: 'auto' - }); - self.$annotationPanel = []; - - self.options.layers.forEach(function(layer, i) { - var item = Ox.getObjectById(layer.items, self.options.selected), - selected = item ? item.id : ''; - self.$annotationPanel[i] = Ox.AnnotationPanel( - Ox.extend({ - collapsed: !self.options.showLayers[layer.id], - font: self.options.annotationsFont, - 'in': self.options['in'], - out: self.options.out, - position: self.options.position, - range: self.options.annotationsRange, - selected: selected, - sort: self.options.annotationsSort, - width: self.options.annotationsSize - Ox.UI.SCROLLBAR_SIZE - }, layer) - ) - .bindEvent({ - add: function(data) { - addAnnotation(layer.id); - }, - blur: function() { - //Ox.print('VIDEO EDITOR BLUR FOCUSED?', self.focused) - if (self.focused) { - // ... - } else { - self.editing = false; - setTimelineState(); - this.blurItem(); - } - }, - edit: function() { - self.editing = true; - setTimelineState(); - }, - paused: togglePaused, - remove: function(data) { - that.triggerEvent('removeannotation', { - id: data.id, - layer: layer.id - }); - }, - select: function(data) { - if (data.id) { - self.options.layers.forEach(function(layer_, i_) { - if (i_ != i) { - self.$annotationPanel[i_].options({selected: ''}); - } - }); - } else { - that.gainFocus(); - } - selectAnnotation(data); - }, - submit: submitAnnotation, - toggle: function(data) { - that.triggerEvent('togglelayer', { - collapsed: data.collapsed, - layer: layer.id - }); - } - }) - .appendTo(self.$annotations); - }); - - self.$videobar = Ox.Bar({ - size: 16 - }).addClass('OxVideoPlayer'); + self.$menubar = 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.resolutions.push({ + id: resolution + '', + title: resolution + 'p', + checked: self.options.resolution == resolution + }); }); self.$keyboardShortcuts = $('
').css({margin: '16px'}); @@ -526,32 +459,7 @@ Ox.VideoEditor = function(options, self) { } } }) - .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); + .appendTo(self.$menubar); if (self.options.posterFrameControls) { @@ -567,7 +475,7 @@ Ox.VideoEditor = function(options, self) { setPosition(self.options.posterFrame); } }) - .appendTo(self.$videobar); + .appendTo(self.$menubar); self.$setPosterButton = Ox.Button({ disabled: true, @@ -584,7 +492,7 @@ Ox.VideoEditor = function(options, self) { self.$unlockPosterButton.toggle(); } }) - .appendTo(self.$videobar); + .appendTo(self.$menubar); self.$unlockPosterButton = Ox.Button({ style: 'symbol', @@ -601,7 +509,7 @@ Ox.VideoEditor = function(options, self) { self.$setPosterButton.toggleOption('disabled'); } }) - .appendTo(self.$videobar); + .appendTo(self.$menubar); } @@ -619,7 +527,7 @@ Ox.VideoEditor = function(options, self) { submitFindInput(''); } }) - .appendTo(self.$videobar); + .appendTo(self.$menubar); self.$findInput = Ox.Input({ autocomplete: self.words, @@ -642,22 +550,7 @@ Ox.VideoEditor = function(options, self) { 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); + .appendTo(self.$menubar); self.$nextButton = Ox.Button({ disabled: true, @@ -672,7 +565,7 @@ Ox.VideoEditor = function(options, self) { setPosition(getNextPosition('result', 1)); } }) - .appendTo(self.$videobar); + .appendTo(self.$menubar); self.$previousButton = Ox.Button({ disabled: true, @@ -687,83 +580,68 @@ Ox.VideoEditor = function(options, self) { setPosition(getNextPosition('result', -1)); } }) - .appendTo(self.$videobar); + .appendTo(self.$menubar); 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); + .appendTo(self.$menubar.$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' + self.$annotationPanel = Ox.AnnotationPanel({ + editable: true, + font: self.options.annotationsFont, + 'in': self.options['in'], + layers: self.options.layers, + out: self.options.out, + position: self.options.position, + range: self.options.annotationsRange, + selected: self.options.selected, + sort: self.options.annotationsSort, + showLayers: self.options.showLayers, + showUsers: self.options.showUsers, + width: self.options.annotationsSize }) - .css({float: 'left'}) .bindEvent({ - change: function(data) { - var set = {}; - set[data.id] = data.checked[0].id; - self.$annotationPanel.forEach(function($panel) { - $panel.options(set); + add: function(data) { + addAnnotation(data.layer); + }, + annotationsfont: function(data) { + that.triggerEvent('annotationsfont', data); + }, + annotationsrange: function(data) { + that.triggerEvent('annotationsrange', data); + }, + annotationssort: function(data) { + that.triggerEvent('annotationssort', data); + }, + blur: function() { + Ox.print('VE-BLUR') + self.editing = false; + setTimelineState(); + }, + edit: function() { + self.editing = true; + setTimelineState(); + }, + paused: togglePaused, + remove: function(data) { + that.triggerEvent('removeannotation', { + id: data.id, + layer: data.layer + }); + }, + select: function(data) { + !data.id && that.gainFocus(); + selectAnnotation(data); + }, + submit: submitAnnotation, + toggle: function(data) { + that.triggerEvent('togglelayer', { + collapsed: data.collapsed, + layer: data.layer }); - that.triggerEvent('annotations' + Ox.toTitleCase(data.id), set); } - }) - .appendTo(self.$annotationsbar); - - self.$editMenuButton = Ox.MenuButton({ - items: [ - {id: 'edit', title: 'Edit Annotation', disabled: !self.options.selected, keyboard: 'return'}, - {id: 'delete', title: 'Delete Annotation', disabled: !self.options.selected, keyboard: 'delete'}, - {id: 'deselect', title: 'Deselect Annotation', disabled: !self.options.selected, keyboard: 'escape'}, - {}, - {id: 'save', title: 'Save Changes', disabled: true, keyboard: 'shift return'}, - {id: 'undo', title: 'Undo Changes', disabled: true, keyboard: 'escape'} - ], - style: 'square', - title: 'edit', - tooltip: 'Editing Options', - type: 'image' - }) - .css({float: 'right'}) - .bindEvent({ - click: function(data) { - if (data.id == 'delete') { - - } else if (data.id == 'edit') { - editAnnotation(); - } - } - }) - .appendTo(self.$annotationsbar); + }); that.setElement( Ox.SplitPanel({ @@ -772,7 +650,7 @@ Ox.VideoEditor = function(options, self) { element: Ox.SplitPanel({ elements: [ { - element: self.$videobar, + element: self.$menubar, size: 16 }, { @@ -785,23 +663,7 @@ Ox.VideoEditor = function(options, self) { { 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 - }), + element: self.$annotationPanel, resizable: true, resize: [192, 256, 320, 384], size: self.options.annotationsSize, @@ -830,19 +692,13 @@ Ox.VideoEditor = function(options, self) { function blurAnnotation() { self.editing = false; setTimelineState(); - getPanel(self.options.selected).blurItem(self.options.selected); - } - - function deselectAnnotation() { - // FIXME: there is selectAnnotation({id: ''}) - self.options.selected = ''; - setTimelineState(); + self.$annotationPanel.blurItem(); } function editAnnotation() { self.editing = true; setTimelineState(); - getPanel(self.options.selected).editItem(self.options.selected); + self.$annotationPanel.editItem(); } function find(query) { @@ -929,21 +785,6 @@ Ox.VideoEditor = function(options, self) { return position; } - function getPanel(annotationId) { - var found = false, panel; - Ox.forEach(self.options.layers, function(layer, i) { - Ox.forEach(layer.items, function(item) { - if (item.id == annotationId) { - panel = self.$annotationPanel[i]; - found = true; - return false; - } - }); - return !found; - }); - return panel; - } - /* function getPoints(type) { var found = false, @@ -1092,36 +933,21 @@ Ox.VideoEditor = function(options, self) { function selectAnnotation(data) { //Ox.print('VE.sA') if (Ox.isUndefined(data)) { + // doubleclick on small timeline data = getAnnotation(); } self.editing = false; self.options.selected = data.id; + // fixme: what is the following supposed to do? if (self.options.selected && self.options.annotationsRange != 'position') { setPosition(data['in']); } if (self.options.selected) { setPoint('in', data['in']); setPoint('out', data.out); - getPanel(self.options.selected).options({selected: self.options.selected}); } + self.$annotationPanel.options({selected: self.options.selected}); setTimelineState(); - updateEditMenu(); - if (data.top) { - var height = self.$annotations.height(), - scrollTop = self.$annotations.scrollTop(); - data.top -= 60; // 20 + 24 + 16 - Ox.print('HEIGHT', height, 'SCROLLTOP', scrollTop, 'TOP', data.top); - if (data.top < 0 || data.top > height - 16) { - if (data.top < 0) { - scrollTop += data.top - 3; - } else if (data.top > height - 16) { - scrollTop += data.top - height + 14; - } - self.$annotations.animate({ - scrollTop: scrollTop + 'px' - }, 0); - } - } that.triggerEvent('select', { id: self.options.selected }); @@ -1169,11 +995,9 @@ Ox.VideoEditor = function(options, self) { 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 - }); + self.$annotationPanel.options({ + 'in': self.options['in'], + out: self.options.out }); that.triggerEvent('points', { 'in': self.options['in'], @@ -1198,10 +1022,8 @@ Ox.VideoEditor = function(options, self) { position: self.options.position }); }); - self.$annotationPanel.forEach(function($panel) { - $panel.options({ - position: self.options.position - }); + self.$annotationPanel.options({ + position: self.options.position }); !playing && that.triggerEvent('position', { position: self.options.position @@ -1307,15 +1129,8 @@ Ox.VideoEditor = function(options, self) { }); } - function updateEditMenu() { - var action = self.options.selected ? 'enableItem' : 'disableItem'; - self.$editMenuButton[action]('edit'); - self.$editMenuButton[action]('delete'); - } - 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); @@ -1328,11 +1143,10 @@ Ox.VideoEditor = function(options, self) { addAnnotation add annotation (layer, item) -> add annotation to layer layer layer id - item annotation to add + annotation annotation to add @*/ - that.addAnnotation = function(layer, item) { - var i = Ox.getIndexById(self.options.layers, layer); - self.$annotationPanel[i].addItem(item); + that.addAnnotation = function(layer, annotation) { + self.$annotationPanel.addItem(layer, annotation); }; /*@ @@ -1341,10 +1155,12 @@ Ox.VideoEditor = function(options, self) { 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; diff --git a/source/Ox.UI/js/Video/Ox.VideoPanelPlayer.js b/source/Ox.UI/js/Video/Ox.VideoPanel.js similarity index 91% rename from source/Ox.UI/js/Video/Ox.VideoPanelPlayer.js rename to source/Ox.UI/js/Video/Ox.VideoPanel.js index 8710b334..971cac2b 100644 --- a/source/Ox.UI/js/Video/Ox.VideoPanelPlayer.js +++ b/source/Ox.UI/js/Video/Ox.VideoPanel.js @@ -11,20 +11,25 @@ Ox.VideoPanelPlayer VideoPanelPlayer Object self shared private variable @*/ -Ox.VideoPanelPlayer = function(options, self) { +Ox.VideoPanel = function(options, self) { self = self || {}; var that = Ox.Element({}, self) .defaults({ + annotationsFont: 'small', + annotationsRange: 'all', annotationsSize: 256, + annotationsSort: 'position', censored: [], + cuts: [], duration: 0, enableSubtitles: false, find: '', fullscreen: false, height: 0, 'in': 0, - loop: false, + layers: [], + loop: false, // fixme: used? muted: false, out: 0, paused: false, @@ -33,7 +38,7 @@ Ox.VideoPanelPlayer = function(options, self) { poster: '', resolution: 0, scaleToFill: false, - showAnnotations: true, + showAnnotations: false, showTimeline: true, subtitles: [], tooltips: false, @@ -54,7 +59,6 @@ Ox.VideoPanelPlayer = function(options, self) { }); self.fullscreen = false; - //alert(JSON.stringify([self.playerHeight, self.playerWidth, self.videoCSS])) self.$player = Ox.Element() .css({ @@ -142,7 +146,7 @@ Ox.VideoPanelPlayer = function(options, self) { }) .appendTo(self.$controls); - self.$panel = Ox.SplitPanel({ + self.$videoPanel = Ox.SplitPanel({ elements: [ { element: self.$player @@ -161,7 +165,14 @@ Ox.VideoPanelPlayer = function(options, self) { resize: resizePanel }); - self.$annotations = Ox.Element() + self.$annotationPanel = Ox.AnnotationPanel({ + font: self.options.annotationsFont, + layers: self.options.layers, + range: self.options.annotationsRange, + showFonts: true, + showLayers: self.options.showLayers, + sort: self.options.annotationsSort + }) .bindEvent({ resize: resizeAnnotations, resizeend: resizeendAnnotations, @@ -171,12 +182,12 @@ Ox.VideoPanelPlayer = function(options, self) { that.$element = Ox.SplitPanel({ elements: [ { - element: self.$panel + element: self.$videoPanel }, { collapsed: !self.options.showAnnotations, collapsible: true, - element: self.$annotations, + element: self.$annotationPanel, resizable: true, resize: [192, 256, 320, 384], size: self.options.annotationsSize, @@ -292,7 +303,7 @@ Ox.VideoPanelPlayer = function(options, self) { } else if (key == 'showAnnotations') { that.$element.toggle(1); } else if (key == 'showTimeline') { - self.$panel.toggle(1); + self.$videoPanel.toggle(1); } else if (key == 'width') { self.$video.options({ width: getPlayerWidth() @@ -318,7 +329,7 @@ Ox.VideoPanelPlayer = function(options, self) { () -> toggle visibility of timeline @*/ that.toggleTimeline = function() { - self.$panel.toggle(1); + self.$videoPanel.toggle(1); }; return that; diff --git a/source/Ox.UI/themes/classic/css/classic.css b/source/Ox.UI/themes/classic/css/classic.css index d345dc03..23f9d53a 100644 --- a/source/Ox.UI/themes/classic/css/classic.css +++ b/source/Ox.UI/themes/classic/css/classic.css @@ -739,16 +739,16 @@ Video background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 1), rgba(192, 192, 192, 1)); } -.OxThemeClassic .OxAnnotationPanel .OxEditableElement.OxSelected { +.OxThemeClassic .OxAnnotationFolder .OxEditableElement.OxSelected { background: rgb(192, 192, 255); box-shadow: 0 0 1px rgb(64, 64, 64); } -.OxThemeClassic .OxAnnotationPanel .OxEditableElement input { +.OxThemeClassic .OxAnnotationFolder .OxEditableElement input { background: rgb(160, 224, 160); color: rgb(0, 0, 0); box-shadow: 0 0 1px rgb(64, 64, 64); } -.OxThemeClassic .OxAnnotationPanel .OxEditableElement textarea { +.OxThemeClassic .OxAnnotationFolder .OxEditableElement textarea { background: rgb(160, 224, 160); color: rgb(0, 0, 0); } diff --git a/source/Ox.UI/themes/modern/css/modern.css b/source/Ox.UI/themes/modern/css/modern.css index 5299d67a..68e519fe 100644 --- a/source/Ox.UI/themes/modern/css/modern.css +++ b/source/Ox.UI/themes/modern/css/modern.css @@ -760,16 +760,16 @@ Video //display: none; } -.OxThemeModern .OxAnnotationPanel .OxEditableElement.OxSelected { +.OxThemeModern .OxAnnotationFolder .OxEditableElement.OxSelected { background: rgb(64, 64, 192); box-shadow: 0 0 1px rgb(255, 255, 255); } -.OxThemeModern .OxAnnotationPanel .OxEditableElement input { +.OxThemeModern .OxAnnotationFolder .OxEditableElement input { background: rgb(64, 128, 64); color: rgb(255, 255, 255); box-shadow: 0 0 1px rgb(255, 255, 255); } -.OxThemeModern .OxAnnotationPanel .OxEditableElement textarea { +.OxThemeModern .OxAnnotationFolder .OxEditableElement textarea { background: rgb(64, 128, 64); color: rgb(255, 255, 255); } diff --git a/source/Ox/js/Array.js b/source/Ox/js/Array.js index d93e36c3..4e2a8a04 100644 --- a/source/Ox/js/Array.js +++ b/source/Ox/js/Array.js @@ -103,7 +103,7 @@ Ox.range = function() { ? Ox.pad(matches[val], len) + val.toString().substr(matches[val].length) : val - ).toLowerCase(); + ).toLowerCase().replace(/^\W+/, ''); }); return sort; } @@ -114,8 +114,8 @@ Ox.range = function() { (arr, fn) -> Sorted array arr Array fn Optional map function that returns the value for the array element - > Ox.sort(['10', '9', 'B', 'a']) - ['9', '10', 'a', 'B'] + > Ox.sort(['"z"', '10', '9', 'B', 'a']) + ['9', '10', 'a', 'B', '"z"'] > Ox.sort([{id: 0, name: '80 Days'}, {id: 1, name: '8 Women'}], function(v) {return v.name}) [{id: 1, name: '8 Women'}, {id: 0, name: '80 Days'}] @*/ @@ -153,7 +153,7 @@ Ox.range = function() { }; }); by.map(function(v) { - return v.key + return v.key; }).forEach(function(key) { values[key] = getSortValues(arr.map(function(v) { return v[key];