From 96d4dfe71df0fc5616a4358d0764d663b475ea30 Mon Sep 17 00:00:00 2001 From: j Date: Wed, 22 Jan 2025 17:42:30 +0530 Subject: [PATCH] allow selecting multiple annotations to get in/out range --- source/UI/css/theme.css | 3 ++ source/UI/js/Form/ArrayEditable.js | 58 ++++++++++++++++++++-- source/UI/js/Video/VideoAnnotationPanel.js | 8 +++ 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/source/UI/css/theme.css b/source/UI/css/theme.css index 83ac746d..d0413cce 100644 --- a/source/UI/css/theme.css +++ b/source/UI/css/theme.css @@ -1398,6 +1398,9 @@ Video .$themeClass .OxAnnotationFolder .OxArrayEditable .OxEditableElement.OxEditable.OxSelected { background-color: $videoAnnotationEditableSelectedBackground; } +.$themeClass .OxAnnotationFolder .OxArrayEditable .OxEditableElement.OxEditable.OxSelected.OxMultiple { + background-color: $videoAnnotationSelectedBackground; +} .$themeClass .OxAnnotationFolder .OxArrayEditable .OxEditableElement.OxSelected .OxHighlight { background-color: transparent; background-image: -moz-repeating-linear-gradient( diff --git a/source/UI/js/Form/ArrayEditable.js b/source/UI/js/Form/ArrayEditable.js index f361569d..e5b2f802 100644 --- a/source/UI/js/Form/ArrayEditable.js +++ b/source/UI/js/Form/ArrayEditable.js @@ -146,12 +146,20 @@ Ox.ArrayEditable = function(options, self) { } } + function getId(position) { + return position > -1 ? self.options.items[position].id : ''; + } + function getSelectedId() { - return self.selected > -1 ? self.options.items[self.selected].id : ''; + return getId(self.selected); + } + + function getPosition(id) { + return Ox.getIndexById(self.options.items, id); } function getSelectedPosition() { - return Ox.getIndexById(self.options.items, self.options.selected); + return getPosition(self.options.selected); } function renderItems(blur) { @@ -267,6 +275,42 @@ Ox.ArrayEditable = function(options, self) { : that.triggerEvent('selectprevious'); } } + function toggleItem(idOrPosition) { + var id, position; + if (Ox.isString(idOrPosition)) { + id = idOrPosition + position = getPosition(id); + } else { + position = idOrPosition + id = getId(position); + } + if (!Ox.isArray(self.options.selected)) { + self.options.selected = [self.options.selected] + } + if (!Ox.isArray(self.selected)) { + self.selected = [self.selected] + } + if (self.options.selected.includes(id)) { + self.options.selected.pop(id) + self.selected.pop(position) + } else { + self.options.selected.push(id) + self.selected.push(position) + } + that.find('.OxSelected').removeClass('OxSelected').removeClass('OxMultiple'); + that.find('.OxGroup').removeClass('OxGroup') + if (self.options.selected.length == 1) { + self.options.selected = self.options.selected[0] + self.selected = self.selected[0] + self.$items[self.selected].addClass('OxSelected'); + self.options.highlightGroup && that.updateItemGroup() + } else { + Ox.forEach(self.selected, function(selected) { + self.$items[selected].addClass('OxSelected').addClass('OxMultiple'); + }) + } + triggerSelectEvent(); + } function selectItem(idOrPosition) { if (Ox.isString(idOrPosition)) { @@ -327,8 +371,14 @@ Ox.ArrayEditable = function(options, self) { position = $element.data('position'); // if clicked on an element if (position != self.selected) { - // select another item - selectItem(position); + if (e.shiftKey) { + // add/remove item from multiple selection + document.getSelection().removeAllRanges(); + toggleItem(position); + } else { + // select another item + selectItem(position); + } } else if (e.metaKey) { // or deselect current item selectNone(); diff --git a/source/UI/js/Video/VideoAnnotationPanel.js b/source/UI/js/Video/VideoAnnotationPanel.js index 5ce19326..c9c22801 100644 --- a/source/UI/js/Video/VideoAnnotationPanel.js +++ b/source/UI/js/Video/VideoAnnotationPanel.js @@ -1350,6 +1350,14 @@ Ox.VideoAnnotationPanel = function(options, self) { if (Ox.isUndefined(data)) { // doubleclick on small timeline data = getAnnotation(); + } else if (Ox.isArray(data.id)) { + var range = data.id.map(id => { + return Ox.getObjectById(self.annotations, id) + }) + data['in'] = Ox.min(range.map(annotation => { return annotation["in"]; })) + data['out'] = Ox.max(range.map(annotation => { return annotation["out"]; })) + setPoint('in', data['in'], true); + setPoint('out', data.out, true); } else if (!data.id && Ox.$elements[that.oxid]) { // focus only if in the dom that.gainFocus();