diff --git a/addon-test-support/pages/-private/ember-table-body.js b/addon-test-support/pages/-private/ember-table-body.js index 6bb3835fb..60cd7054e 100644 --- a/addon-test-support/pages/-private/ember-table-body.js +++ b/addon-test-support/pages/-private/ember-table-body.js @@ -75,6 +75,7 @@ export default PageObject.extend({ checkbox: { scope: '[data-test-select-row]', isChecked: property('checked'), + isIndeterminate: property('indeterminate'), async clickWith(options) { await click(findElement(this), options); @@ -98,6 +99,8 @@ export default PageObject.extend({ isSelected: hasClass('is-selected'), + isGroupIndeterminate: hasClass('is-group-indeterminate'), + /** Helper function to click with options like the meta key and ctrl key set diff --git a/addon/-private/collapse-tree.js b/addon/-private/collapse-tree.js index 4410b0584..3c60fed2f 100644 --- a/addon/-private/collapse-tree.js +++ b/addon/-private/collapse-tree.js @@ -83,6 +83,36 @@ export const TableRowMeta = EmberObject.extend({ } ), + isGroupIndeterminate: computed( + '_tree.{selection.[],selectionMatchFunction,selectingChildrenSelectsParent}', + function() { + let rowValue = get(this, '_rowValue'); + let selection = get(this, '_tree.selection'); + let selectionMatchFunction = get(this, '_tree.selectionMatchFunction'); + let selectingChildrenSelectsParent = get(this, '_tree.selectingChildrenSelectsParent'); + + if (!rowValue.children || !isArray(rowValue.children)) { + return false; + } + + if (!selection || !isArray(selection)) { + return false; + } + + if (!selectingChildrenSelectsParent) { + return false; + } + + if (selectionMatchFunction) { + return rowValue.children.some(child => + selection.some(item => selectionMatchFunction(item, child)) + ); + } + + return rowValue.children.some(child => selection.includes(child)); + } + ), + canCollapse: computed( '_tree.{enableTree,enableCollapse}', '_rowValue.{children.[],disableCollapse}', diff --git a/addon/components/ember-td/template.hbs b/addon/components/ember-td/template.hbs index 4cbab5045..01f22d169 100644 --- a/addon/components/ember-td/template.hbs +++ b/addon/components/ember-td/template.hbs @@ -7,6 +7,7 @@ > { assert.ok(row.isSelected, 'the row is selected'); assert.ok(!row.checkbox.isChecked, 'the row checkbox is checked'); }); + + test('Selecting a child row causes parent checkbox to be indeterminate', async function(assert) { + await generateTable(this, { rowCount: 3, rowDepth: 2 }); + + let parentRow = table.rows.objectAt(0); + let childRow = table.rows.objectAt(1); + + assert.ok(!parentRow.isSelected, 'parent row is not selected'); + assert.ok(!parentRow.isGroupIndeterminate, 'parent row is not indeterminate'); + + assert.ok(!parentRow.checkbox.isChecked, 'parent row checkbox is not checked'); + assert.ok(!parentRow.checkbox.isIndeterminate, 'parent row checkbox is not indeterminate'); + + assert.ok(!childRow.isSelected, 'child row is not selected'); + + await childRow.checkbox.click(); + + assert.ok(childRow.isSelected, 'child row is selected'); + + assert.ok(!parentRow.isSelected, 'parent row is not selected'); + assert.ok(parentRow.isGroupIndeterminate, 'parent row is indeterminate'); + + assert.ok(!parentRow.checkbox.isChecked, 'parent row checkbox is not checked'); + assert.ok(parentRow.checkbox.isIndeterminate, 'parent row checkbox is indeterminate'); + }); }); componentModule('single', function() { @@ -532,6 +556,31 @@ module('Integration | selection', () => { await table.selectRow(0); }); + + test('Selecting a child row causes parent checkbox to be indeterminate', async function(assert) { + await generateTable(this, { rowCount: 3, rowDepth: 2, checkboxSelectionMode: 'single' }); + + let parentRow = table.rows.objectAt(0); + let childRow = table.rows.objectAt(1); + + assert.ok(!parentRow.isSelected, 'parent row is not selected'); + assert.ok(!parentRow.isGroupIndeterminate, 'parent row is not indeterminate'); + + assert.ok(!parentRow.checkbox.isChecked, 'parent row checkbox is not checked'); + assert.ok(!parentRow.checkbox.isIndeterminate, 'parent row checkbox is not indeterminate'); + + assert.ok(!childRow.isSelected, 'child row is not selected'); + + await childRow.checkbox.click(); + + assert.ok(childRow.isSelected, 'child row is selected'); + + assert.ok(!parentRow.isSelected, 'parent row is not selected'); + assert.ok(parentRow.isGroupIndeterminate, 'parent row is indeterminate'); + + assert.ok(!parentRow.checkbox.isChecked, 'parent row checkbox is not checked'); + assert.ok(parentRow.checkbox.isIndeterminate, 'parent row checkbox is indeterminate'); + }); }); componentModule('none', function() { diff --git a/types/index.d.ts b/types/index.d.ts index a17acb908..a679d6d9b 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -23,6 +23,7 @@ export interface TableRowMeta { isCollapsed: boolean; isSelected: boolean; isGroupSelected: boolean; + isGroupIndeterminate: boolean; canCollapse: boolean; depth: number; first: unknown | null;