Skip to content

Commit

Permalink
List: Add group header to focus order if collapsibleGroups is true
Browse files Browse the repository at this point in the history
  • Loading branch information
marker-dao authored Nov 8, 2024
1 parent a45c8d4 commit b6e3868
Show file tree
Hide file tree
Showing 15 changed files with 322 additions and 60 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
87 changes: 52 additions & 35 deletions e2e/testcafe-devextreme/tests/editors/list/grouping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,17 @@ test('Grouped list appearance', async (t) => {

const list = new List('#container');

await t.click(list.getGroup(0).header);
await t.click(list.getGroup(2).header);
await t
.click(list.getItem(2).element)
.pressKey('down');

await testScreenshot(t, takeScreenshot, 'Grouped list with focused header.png', { element: '#container' });

await t
.click(list.getGroup(0).header)
.click(list.getGroup(2).header)
.click(list.getItem(4).element)
.hover(list.getGroup(1).header);

await testScreenshot(t, takeScreenshot, 'Grouped list appearance.png', { element: '#container' });

Expand All @@ -55,23 +64,28 @@ test('Grouped list appearance', async (t) => {
}).before(async () => createWidget('dxList', {
width: 300,
height: 800,
dataSource: [{
key: 'group_1',
items: ['item_1_1', 'item_1_2', 'item_1_3'],
expanded: false,
}, {
key: 'group_2',
items: [
{ text: 'item_2_1', disabled: true },
{ text: 'item_2_2', icon: 'home' },
{ text: 'item_2_3', showChevron: true, badge: 'item_2_3' },
{ text: 'item_2_4', badge: 'item_2_4' },
'item_2_5'],
}, {
key: 'group_3',
items: ['item_3_1', 'item_3_2', 'item_3_3'],
expanded: false,
}],
dataSource: [
{
key: 'group_1',
items: ['item_1_1', 'item_1_2', 'item_1_3'],
expanded: false,
},
{
key: 'group_2',
items: [
{ text: 'item_2_1', disabled: true },
{ text: 'item_2_2', icon: 'home' },
{ text: 'item_2_3', showChevron: true, badge: 'item_2_3' },
{ text: 'item_2_4', badge: 'item_2_4' },
'item_2_5',
],
},
{
key: 'group_3',
items: ['item_3_1', 'item_3_2', 'item_3_3'],
expanded: false,
},
],
collapsibleGroups: true,
grouped: true,
allowItemDeleting: true,
Expand All @@ -89,7 +103,9 @@ test('Grouped list appearance', async (t) => {

await t
.click(list.getGroup(0).header)
.click(list.getGroup(2).header);
.click(list.getGroup(2).header)
.click(list.getItem(4).element)
.hover(list.getGroup(1).header);

await testScreenshot(t, takeScreenshot, `Grouped list appearance with template. rtlEnabled=${rtlEnabled}.png`, { element: '#container' });

Expand All @@ -102,24 +118,25 @@ test('Grouped list appearance', async (t) => {
groupTemplate(data) {
const wrapper = $('<div>');

$(`<span>${data.key}</span>`)
.appendTo(wrapper);

$('<div>second row</div>')
.appendTo(wrapper);
$(`<span>${data.key}</span>`).appendTo(wrapper);
$('<div>second row</div>').appendTo(wrapper);

return wrapper;
},
dataSource: [{
key: 'One',
items: ['1_1', '1_2', '1_3'],
}, {
key: 'Two',
items: ['2_1', '2_2', '2_3'],
}, {
key: 'Three',
items: ['3_1', '3_2', '3_3'],
}],
dataSource: [
{
key: 'One',
items: ['1_1', '1_2', '1_3'],
},
{
key: 'Two',
items: ['2_1', '2_2', '2_3'],
},
{
key: 'Three',
items: ['3_1', '3_2', '3_3'],
},
],
collapsibleGroups: true,
grouped: true,
rtlEnabled,
Expand Down
9 changes: 9 additions & 0 deletions packages/devextreme-scss/scss/widgets/fluent/list/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,15 @@ $fluent-list-item-border: $fluent-list-item-border-width solid $list-border-colo
.dx-list-item {
@include item-states();
}

.dx-list-group-header {
@include item-states();

&.dx-state-hover {
background-color: $list-item-hover-bg;
color: $list-item-hover-color;
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ $generic-list-search-editor-height: round($generic-base-line-height * $generic-b
.dx-list-item {
@include item-states();
}

.dx-list-group-header {
@include item-states();
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,15 @@ $material-list-searchbox-padding-top: $material-list-searchbox-vertical-padding
.dx-list-item {
@include item-states();
}

.dx-list-group-header {
@include item-states();

&.dx-state-hover {
background-color: $list-item-hover-bg;
color: $list-item-hover-color;
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ const CollectionWidget = Widget.inherit({
});
},

_getHandlerExtendedParams(e, target) {
const params = extend({}, e, {
target: target.get(0),
currentTarget: target.get(0),
});

return params;
},

_enterKeyHandler(e) {
const $itemElement = $(this.option('focusedElement'));

Expand All @@ -99,10 +108,7 @@ const CollectionWidget = Widget.inherit({
});
}

this._itemClickHandler(extend({}, e, {
target: $itemElement.get(0),
currentTarget: $itemElement.get(0),
}));
this._itemClickHandler(this._getHandlerExtendedParams(e, $itemElement));
},

_getDefaultOptions() {
Expand Down
116 changes: 95 additions & 21 deletions packages/devextreme/js/__internal/ui/list/m_list.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,16 +286,40 @@ export const ListBase = CollectionWidget.inherit({
},

_refreshItemElements() {
if (!this.option('grouped')) {
this._itemElementsCache = this._getItemsContainer().children(this._itemSelector());
} else {
this._itemElementsCache = this._getItemsContainer()
const { grouped } = this.option();
const $itemsContainer = this._getItemsContainer();

if (grouped) {
this._itemElementsCache = $itemsContainer
.children(`.${LIST_GROUP_CLASS}`)
.children(`.${LIST_GROUP_BODY_CLASS}`)
.children(this._itemSelector());
} else {
this._itemElementsCache = $itemsContainer.children(this._itemSelector());
}
},

_getItemAndHeaderElements() {
const itemSelector = `> .${LIST_GROUP_BODY_CLASS} > ${this._itemSelector()}`;
const itemAndHeaderSelector = `${itemSelector}, > .${LIST_GROUP_HEADER_CLASS}`;

const $listGroup = this._getItemsContainer().children(`.${LIST_GROUP_CLASS}`);

const $items = $listGroup.find(itemAndHeaderSelector).filter(':visible');

return $items;
},

_getAvailableItems($itemElements) {
const { collapsibleGroups } = this.option();

if (collapsibleGroups) {
return this._getItemAndHeaderElements();
}

return this.callBase($itemElements);
},

_modifyByChanges() {
this.callBase.apply(this, arguments);

Expand Down Expand Up @@ -344,7 +368,23 @@ export const ListBase = CollectionWidget.inherit({
return true;
},

_updateActiveStateUnit(): void {
const { collapsibleGroups } = this.option();

const selectors = [
LIST_ITEM_SELECTOR,
SELECT_ALL_ITEM_SELECTOR,
];

if (collapsibleGroups) {
selectors.push(`.${LIST_GROUP_HEADER_CLASS}`);
}

this._activeStateUnit = selectors.join(',');
},

_init() {
this._updateActiveStateUnit();
this.callBase();
this._dataController.resetDataSourcePageIndex();
this._$container = this.$element();
Expand Down Expand Up @@ -605,31 +645,62 @@ export const ListBase = CollectionWidget.inherit({
},

_attachGroupCollapseEvent() {
const eventName = addNamespace(clickEventName, this.NAME);
const selector = `.${LIST_GROUP_HEADER_CLASS}`;
const { collapsibleGroups } = this.option();

const eventNameClick = addNamespace(clickEventName, this.NAME);
const headerSelector = `.${LIST_GROUP_HEADER_CLASS}`;

const $element = this.$element();
const collapsibleGroups = this.option('collapsibleGroups');

$element.toggleClass(LIST_COLLAPSIBLE_GROUPS_CLASS, collapsibleGroups);

eventsEngine.off($element, eventName, selector);
eventsEngine.off($element, eventNameClick, headerSelector);

if (collapsibleGroups) {
eventsEngine.on($element, eventName, selector, (e) => {
this._createAction((e) => {
const $group = $(e.event.currentTarget).parent();
this._collapseGroupHandler($group);
if (this.option('focusStateEnabled')) {
this.option('focusedElement', getPublicElement($group.find(`.${LIST_ITEM_CLASS}`).eq(0)));
}
}, {
validatingTargetName: 'element',
})({
event: e,
});
eventsEngine.on($element, eventNameClick, headerSelector, (e) => {
this._processGroupCollapse(e);
});
}
},

_processGroupCollapse(e): void {
const actionCallback = (e) => {
const { focusStateEnabled } = this.option();
const $group = $(e.event.currentTarget).parent();

this._collapseGroupHandler($group);

if (focusStateEnabled) {
const listItemElement = getPublicElement($group.find(`.${LIST_ITEM_CLASS}`).eq(0));

this.option({ focusedElement: listItemElement });
}
};

const actionParams = {
validatingTargetName: 'element',
};

const action = this._createAction(actionCallback, actionParams);

action({ event: e });
},

_enterKeyHandler(e): void {
const { collapsibleGroups, focusedElement } = this.option();
const isGroupHeader = $(focusedElement).hasClass(LIST_GROUP_HEADER_CLASS);

if (collapsibleGroups && isGroupHeader) {
const params = this._getHandlerExtendedParams(e, $(focusedElement));

this._processGroupCollapse(params);

return;
}

this.callBase(e);
},

_collapseGroupHandler($group, toggle) {
const deferred = Deferred();

Expand Down Expand Up @@ -978,10 +1049,13 @@ export const ListBase = CollectionWidget.inherit({
this._createScrollViewActions();
break;
case 'grouped':
case 'collapsibleGroups':
case 'groupTemplate':
this._invalidate();
break;
case 'collapsibleGroups':
this._updateActiveStateUnit();
this._invalidate();
break;
case 'wrapItemText':
this._toggleWrapItemText(args.value);
break;
Expand Down
Loading

0 comments on commit b6e3868

Please sign in to comment.