From a7de10a516b68d6f38b17169dd096e4954217f86 Mon Sep 17 00:00:00 2001 From: volnyagin Date: Thu, 3 Aug 2017 18:51:09 +0300 Subject: [PATCH] Fix T539632: dxDataGrid - The header's "Select All" checkbox becomes frozen after several clicks when the deferred selection mode is used --- .../selection/selection.strategy.deferred.js | 20 ++--- .../DevExpress.ui.widgets/selection.test.js | 75 ++++++++++++++++++- 2 files changed, 82 insertions(+), 13 deletions(-) diff --git a/js/ui/selection/selection.strategy.deferred.js b/js/ui/selection/selection.strategy.deferred.js index 99eb56615416..425bc484d69e 100644 --- a/js/ui/selection/selection.strategy.deferred.js +++ b/js/ui/selection/selection.strategy.deferred.js @@ -117,10 +117,6 @@ module.exports = SelectionStrategy.inherit({ } }, - _hasSameFilter: function(selectionFilter, currentFilter) { - return this._findSubFilter(selectionFilter, currentFilter) >= 0; - }, - _findSubFilter: function(selectionFilter, filter) { if(!selectionFilter) return -1; var filterString = JSON.stringify(filter); @@ -137,7 +133,7 @@ module.exports = SelectionStrategy.inherit({ _isLastSubFilter: function(selectionFilter, filter) { if(selectionFilter && filter) { - return this._findSubFilter(selectionFilter, filter) === selectionFilter.length - 1; + return this._findSubFilter(selectionFilter, filter) === selectionFilter.length - 1 || this._findSubFilter([selectionFilter], filter) === 0; } return false; }, @@ -168,11 +164,9 @@ module.exports = SelectionStrategy.inherit({ selectionFilter = that._denormalizeFilter(selectionFilter); if(selectionFilter && selectionFilter.length) { - if(that._hasSameFilter(selectionFilter, currentFilter)) { - return; - } + that._removeSameFilter(selectionFilter, filter, isDeselect, true); - if(that._removeInvertedFilter(selectionFilter, isDeselect, filter)) { + if(that._removeSameFilter(selectionFilter, filter, !isDeselect, !isUnique)) { needAddFilter = !isUnique; } @@ -197,8 +191,8 @@ module.exports = SelectionStrategy.inherit({ return filter; }, - _removeInvertedFilter: function(selectionFilter, isDeselect, filter) { - filter = isDeselect ? filter : ["!", filter]; + _removeSameFilter: function(selectionFilter, filter, inverted, forceRemove) { + filter = inverted ? ["!", filter] : filter; var filterIndex = this._findSubFilter(selectionFilter, filter); @@ -207,7 +201,9 @@ module.exports = SelectionStrategy.inherit({ return true; } - if(filterIndex >= 0) { + var isLastItem = filterIndex === selectionFilter.length - 1; + + if(filterIndex >= 0 && (forceRemove || isLastItem)) { if(filterIndex > 0) { selectionFilter.splice(filterIndex - 1, 2); } else { diff --git a/testing/tests/DevExpress.ui.widgets/selection.test.js b/testing/tests/DevExpress.ui.widgets/selection.test.js index 429ec7ce8faf..b1d9ec4e999e 100644 --- a/testing/tests/DevExpress.ui.widgets/selection.test.js +++ b/testing/tests/DevExpress.ui.widgets/selection.test.js @@ -1024,7 +1024,7 @@ QUnit.test("changeItemSelection with shift key should add several expressions wi selection.changeItemSelection(4, { shift: true }); //assert - assert.deepEqual(selection.selectionFilter(), [["id", "=", 2], "or", ["id", "=", 5], "or", ["id", "=", 4], "or", ["id", "=", 3]], "selection filter"); + assert.deepEqual(selection.selectionFilter(), [["id", "=", 5], "or", ["id", "=", 4], "or", ["id", "=", 3], "or", ["id", "=", 2]], "selection filter"); }); QUnit.test("selectAll when filter is empty", function(assert) { @@ -1266,6 +1266,79 @@ QUnit.test("changeItemSelection after selectAll", function(assert) { assert.strictEqual(selection.getSelectAllState(), undefined, "select all is undefined"); }); +QUnit.test("selectAll when filter with 'or' operation is defined", function(assert) { + var selection = this.createDeferredSelection(this.data); + + //act + this.dataSource.filter([["age", "=", 15], "or", ["age", "=", 20]]); + selection.selectAll(); + + //assert + assert.deepEqual(selection.selectionFilter(), [["age", "=", 15], "or", ["age", "=", 20]], "selection filter"); + assert.strictEqual(selection.getSelectAllState(), true, "select all is true"); +}); + +QUnit.test("selectAll after deselect one item", function(assert) { + var selection = this.createDeferredSelection(this.data); + + //act + this.dataSource.filter(["age", ">", 18]); + selection.selectAll(); + selection.changeItemSelection(1, { control: true }); + selection.selectAll(); + + //assert + assert.deepEqual(selection.selectionFilter(), [["!", ["id", "=", 2]], "or", ["age", ">", 18]], "selection filter"); + assert.strictEqual(selection.getSelectAllState(), true, "select all is true"); +}); + +QUnit.test("Deselect one item after selectAll", function(assert) { + var selection = this.createDeferredSelection(this.data); + + //act + this.dataSource.filter(["age", ">", 18]); + selection.changeItemSelection(1, { control: true }); + selection.selectAll(); + selection.changeItemSelection(1, { control: true }); + + //assert + assert.deepEqual(selection.selectionFilter(), [[["id", "=", 2], "or", ["age", ">", 18]], "and", ["!", ["id", "=", 2]]], "selection filter"); + assert.strictEqual(selection.getSelectAllState(), undefined, "select all is true"); + assert.strictEqual(selection.isItemSelected(this.data[1]), false, "item 1 should not be selected"); +}); + +QUnit.test("Deselect one item after selectAll when filter contains 'or' operation", function(assert) { + var selection = this.createDeferredSelection(this.data); + + //act + this.dataSource.filter([["age", "=", 15], "or", ["age", "=", 20]]); + selection.changeItemSelection(1, { control: true }); + selection.selectAll(); + selection.changeItemSelection(1, { control: true }); + + //assert + assert.deepEqual(selection.selectionFilter(), [[["id", "=", 2], "or", [["age", "=", 15], "or", ["age", "=", 20]]], "and", ["!", ["id", "=", 2]]], "selection filter"); + assert.strictEqual(selection.getSelectAllState(), undefined, "select all is true"); + assert.strictEqual(selection.isItemSelected(this.data[1]), false, "item 1 should not be selected"); +}); + +QUnit.test("select and deselect several items", function(assert) { + var selection = this.createDeferredSelection(this.data); + + //act + this.dataSource.filter(["age", ">", 0]); + selection.changeItemSelection(0, { control: true }); + selection.changeItemSelection(1, { control: true }); + selection.changeItemSelection(0, { control: true }); + selection.changeItemSelection(1, { control: true }); + + //assert + assert.strictEqual(selection.getSelectAllState(), undefined, "select all is undefined"); + assert.strictEqual(selection.isItemSelected(this.data[0]), false, "item 0 should not be selected"); + assert.strictEqual(selection.isItemSelected(this.data[1]), false, "item 1 should not be selected"); + assert.strictEqual(selection.isItemSelected(this.data[2]), false, "item 2 should not be selected"); +}); + QUnit.test("getSelectedItems returns deferred", function(assert) { var selectedItems, selection = this.createDeferredSelection(this.data, {