diff --git a/cvat/apps/engine/static/engine/js/annotationUI.js b/cvat/apps/engine/static/engine/js/annotationUI.js index f0c5fab4..e2bfce72 100644 --- a/cvat/apps/engine/static/engine/js/annotationUI.js +++ b/cvat/apps/engine/static/engine/js/annotationUI.js @@ -137,7 +137,7 @@ function buildAnnotationUI(job, shapeData, loadJobEvent) { playerModel.subscribe(shapeBufferView); playerModel.subscribe(shapeGrouperView); playerModel.subscribe(polyshapeEditorView); - playerModel.shift(0); + playerModel.shift(getURISearchParameter('frame') || 0, true); let shortkeys = window.cvat.config.shortkeys; diff --git a/cvat/apps/engine/static/engine/js/base.js b/cvat/apps/engine/static/engine/js/base.js index dc9fb1ef..e5d59c99 100644 --- a/cvat/apps/engine/static/engine/js/base.js +++ b/cvat/apps/engine/static/engine/js/base.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: MIT */ -/* exported confirm showMessage showOverlay dumpAnnotationRequest */ +/* exported confirm showMessage showOverlay dumpAnnotationRequest getURISearchParameter setURISearchParameter */ "use strict"; Math.clamp = function(x, min, max) { @@ -161,6 +161,44 @@ function dumpAnnotationRequest(dumpButton, taskID) { } +function setURISearchParameter(name, value) { + let searchParams = new URLSearchParams(window.location.search); + if (typeof value === 'undefined' || value === null) { + if (searchParams.has(name)) { + searchParams.delete(name); + } + } + else searchParams.set(name, value); + + window.history.replaceState(null, null, `?${searchParams.toString()}`); +} + + +function resetURISearchParameters() { + let searchParams = new URLSearchParams(); + searchParams.set('id', window.cvat.job.id); + window.history.replaceState(null, null, `?${searchParams.toString()}`); +} + + +function getURISearchParameter(name) { + let decodedURI = ''; + try { + decodedURI = decodeURIComponent(window.location.search); + } + catch (error) { + showMessage('Bad URL has been found'); + resetURISearchParameters(); + } + + let urlSearchParams = new URLSearchParams(decodedURI); + if (urlSearchParams.has(name)) { + return urlSearchParams.get(name); + } + else return null; +} + + /* These HTTP methods do not require CSRF protection */ function csrfSafeMethod(method) { return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); diff --git a/cvat/apps/engine/static/engine/js/player.js b/cvat/apps/engine/static/engine/js/player.js index 3c859f54..70731b60 100644 --- a/cvat/apps/engine/static/engine/js/player.js +++ b/cvat/apps/engine/static/engine/js/player.js @@ -778,7 +778,10 @@ class PlayerView { } this._loadingUI.addClass('hidden'); - this._playerBackgroundUI.css('background-image', 'url(' + '"' + image.src + '"' + ')'); + if (this._playerBackgroundUI.css('background-image').slice(5,-2) != image.src) { + this._playerBackgroundUI.css('background-image', 'url(' + '"' + image.src + '"' + ')'); + setURISearchParameter('frame', frames.current); + } if (model.playing) { this._playButtonUI.addClass('hidden'); diff --git a/cvat/apps/engine/static/engine/js/polyshapeEditor.js b/cvat/apps/engine/static/engine/js/polyshapeEditor.js index 2f5c61fb..4ed27168 100644 --- a/cvat/apps/engine/static/engine/js/polyshapeEditor.js +++ b/cvat/apps/engine/static/engine/js/polyshapeEditor.js @@ -52,7 +52,10 @@ class PolyshapeEditorModel extends Listener { cancel() { if (this._active) { this._active = false; - if (window.cvat.mode === this._modeName) { + if (window.cvat.mode != this._modeName) { + throw Error(`Inconsistent behaviour has been detected. Edit mode is activated, but mode variable is '${window.cvat.mode}'`); + } + else { window.cvat.mode = null; } diff --git a/cvat/apps/engine/static/engine/js/shapeCreator.js b/cvat/apps/engine/static/engine/js/shapeCreator.js index eebcb878..6a04c406 100644 --- a/cvat/apps/engine/static/engine/js/shapeCreator.js +++ b/cvat/apps/engine/static/engine/js/shapeCreator.js @@ -268,7 +268,7 @@ class ShapeCreatorView { let lastPoint = { x: null, y: null, - } + }; if (this._polyShapeSize) { let size = this._polyShapeSize; @@ -296,14 +296,14 @@ class ShapeCreatorView { lastPoint = { x: e.detail.event.clientX, y: e.detail.event.clientY, - } + }; }); this._drawInstance.on('drawpoint', (e) => { lastPoint = { x: e.detail.event.clientX, y: e.detail.event.clientY, - } + }; }); this._frameContent.on('mousedown.shapeCreator', (e) => { diff --git a/cvat/apps/engine/static/engine/js/shapeFilter.js b/cvat/apps/engine/static/engine/js/shapeFilter.js index 9781812b..be030fc6 100644 --- a/cvat/apps/engine/static/engine/js/shapeFilter.js +++ b/cvat/apps/engine/static/engine/js/shapeFilter.js @@ -64,9 +64,15 @@ class FilterModel { } } - updateFilter(value) { + updateFilter(value, silent) { this._filter = value; - this._update(); + if (!silent) { + this._update(); + } + } + + get filterRow() { + return this._filter; } } @@ -75,27 +81,31 @@ class FilterController { this._model = filterModel; } - updateFilter(value) { + updateFilter(value, silent) { if (value.length) { + value = value.split('|').map(x => '/d:data/' + x).join('|').toLowerCase().replace(/-/g, "_"); try { document.evaluate(value, document, () => 'ns'); } catch (error) { return false; } - this._model.updateFilter(value); + this._model.updateFilter(value, silent); return true; } else { - this._model.updateFilter(value); + this._model.updateFilter('', silent); return true; } - } deactivate() { this._model.active = false; } + + get filterRow() { + return this._model.filterRow; + } } @@ -109,14 +119,14 @@ class FilterView { this._filterString.on('keypress keydown keyup', (e) => e.stopPropagation()); this._filterString.on('change', (e) => { let value = $.trim(e.target.value); - if (value.length) { - value = value.split('|').map(x => '/d:data/' + x).join('|').toLowerCase().replace(/-/g, "_"); - } - if (this._controller.updateFilter(value)) { + + if (this._controller.updateFilter(value, false)) { this._filterString.css('color', 'green'); + setURISearchParameter('filter', value || null); } else { this._filterString.css('color', 'red'); + setURISearchParameter('filter', null); } }); @@ -127,9 +137,21 @@ class FilterView { this._resetFilterButton.on('click', () => { this._filterString.prop('value', ''); - this._controller.updateFilter(''); + this._controller.updateFilter('', false); + setURISearchParameter('filter', null); }); - } - + if (getURISearchParameter('filter')) { + let value = getURISearchParameter('filter'); + this._filterString.prop('value', value); + if (this._controller.updateFilter(value, true)) { + this._filterString.css('color', 'green'); + } + else { + setURISearchParameter('filter', null); + this._filterString.prop('value', ''); + this._filterString.css('color', 'red'); + } + } + } } diff --git a/tests/eslintrc.conf.js b/tests/eslintrc.conf.js index 7771a024..cd8affdc 100644 --- a/tests/eslintrc.conf.js +++ b/tests/eslintrc.conf.js @@ -49,6 +49,8 @@ module.exports = { 'showOverlay': true, 'confirm': true, 'dumpAnnotationRequest': true, + 'getURISearchParameter': true, + 'setURISearchParameter': true, // from shapeCollection.js 'ShapeCollectionModel': true, 'ShapeCollectionController': true,