Skip to content

Commit b029181

Browse files
committed
update list.base and add tests for new behavior
1 parent f547ea3 commit b029181

2 files changed

Lines changed: 78 additions & 70 deletions

File tree

packages/devextreme/js/__internal/ui/list/list.base.ts

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,24 +1067,23 @@ export class ListBase extends CollectionWidget<ListBaseProperties, Item> {
10671067
_postprocessRenderItem(args: PostprocessRenderItemInfo<Item>): void {
10681068
this._refreshItemElements();
10691069
super._postprocessRenderItem(args);
1070-
1071-
if (this.hasActionSubscription('onItemSwipe')) {
1072-
this._attachSwipeEvent($(args.itemElement));
1073-
}
1070+
this._updateSwipeEventSubscription($(args.itemElement));
10741071
}
10751072

10761073
_getElementClassToSkipRefreshId(): string {
10771074
return LIST_GROUP_HEADER_CLASS;
10781075
}
10791076

1080-
_attachSwipeEvent($itemElement: dxElementWrapper): void {
1077+
_updateSwipeEventSubscription($itemElement: dxElementWrapper = this._itemElements()): void {
10811078
// @ts-expect-error ts-error
10821079
const endEventName = addNamespace(swipeEventEnd, this.NAME);
1083-
10841080
eventsEngine.off($itemElement, endEventName);
1085-
eventsEngine.on($itemElement, endEventName, (e) => {
1086-
this._itemSwipeEndHandler(e);
1087-
});
1081+
1082+
if (this.hasActionSubscription('onItemSwipe')) {
1083+
eventsEngine.on($itemElement, endEventName, (e) => {
1084+
this._itemSwipeEndHandler(e);
1085+
});
1086+
}
10881087
}
10891088

10901089
_itemSwipeEndHandler(e: DxEvent & { offset: number }): void {
@@ -1093,32 +1092,14 @@ export class ListBase extends CollectionWidget<ListBaseProperties, Item> {
10931092
});
10941093
}
10951094

1096-
_onItemSwipeSubscriptionChanged(): void {
1097-
const $items = this._itemElements();
1098-
1099-
// @ts-expect-error ts-error
1100-
const endEventName = addNamespace(swipeEventEnd, this.NAME);
1101-
1102-
$items.each((_index, item) => {
1103-
const $item = $(item);
1104-
1105-
eventsEngine.off($item, endEventName);
1106-
1107-
if (this.hasActionSubscription('onItemSwipe')) {
1108-
this._attachSwipeEvent($item);
1109-
}
1110-
return true;
1111-
});
1112-
}
1113-
11141095
on(eventName: string | { [key: string]: Function }, eventHandler?: Function): this {
11151096
const result = super.on(eventName, eventHandler);
11161097

1117-
const isItemSwipe = eventName === 'itemSwipe'
1098+
const isItemSwipeOn = eventName === 'itemSwipe'
11181099
|| (isPlainObject(eventName) && Object.prototype.hasOwnProperty.call(eventName, 'itemSwipe'));
11191100

1120-
if (isItemSwipe) {
1121-
this._onItemSwipeSubscriptionChanged();
1101+
if (isItemSwipeOn) {
1102+
this._updateSwipeEventSubscription();
11221103
}
11231104

11241105
return result;
@@ -1127,12 +1108,8 @@ export class ListBase extends CollectionWidget<ListBaseProperties, Item> {
11271108
off(eventName: string, eventHandler?: Function): this {
11281109
const result = super.off(eventName, eventHandler);
11291110

1130-
const isItemSwipe = eventName === undefined
1131-
|| eventName === 'itemSwipe'
1132-
|| (isPlainObject(eventName) && Object.prototype.hasOwnProperty.call(eventName, 'itemSwipe'));
1133-
1134-
if (isItemSwipe) {
1135-
this._onItemSwipeSubscriptionChanged();
1111+
if (eventName === 'itemSwipe') {
1112+
this._updateSwipeEventSubscription();
11361113
}
11371114

11381115
return result;

packages/devextreme/testing/tests/DevExpress.ui.widgets/listParts/commonTests.js

Lines changed: 65 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import eventsEngine from 'common/core/events/core/events_engine';
2424
import ariaAccessibilityTestHelper from '../../../helpers/ariaAccessibilityTestHelper.js';
2525

2626
const LIST_ITEM_CLASS = 'dx-list-item';
27+
const LIST_ITEM_CONTENT_CLASS = 'dx-list-item-content';
2728
const LIST_ITEMS_CLASS = 'dx-list-items';
2829
const LIST_GROUP_CLASS = 'dx-list-group';
2930
const LIST_GROUP_HEADER_CLASS = 'dx-list-group-header';
@@ -1187,7 +1188,7 @@ QUnit.module('options changed', moduleSetup, () => {
11871188
list.off('itemSwipe');
11881189
swipeItem();
11891190

1190-
list.on('itemSwipe', swipeHandler);
1191+
list.on({ 'itemSwipe': swipeHandler });
11911192
swipeItem();
11921193
});
11931194

@@ -4791,67 +4792,97 @@ QUnit.module('Search', () => {
47914792
});
47924793
});
47934794

4794-
QUnit.module('Highlighting', () => {
4795+
QUnit.module('Highlighting/selecting', moduleSetup, () => {
47954796

47964797
const selectTextNodePart = (textNode, startOffset, endOffset) => {
47974798
const selection = window.getSelection();
47984799
const range = document.createRange();
4799-
48004800
selection.removeAllRanges();
48014801
range.setStart(textNode, startOffset);
48024802
range.setEnd(textNode, endOffset);
48034803
selection.addRange(range);
4804-
48054804
return selection;
48064805
};
48074806

4808-
QUnit.test('list item should not block native text selection events', function(assert) {
4807+
const getFirstListItemAndTextNode = ($list) => {
4808+
const $item = $list.find(`.${LIST_ITEM_CLASS}`).eq(0);
4809+
const textNode = $list.find(`.${LIST_ITEM_CONTENT_CLASS}`).eq(0).get(0).firstChild;
4810+
4811+
return { $item, textNode };
4812+
};
4813+
4814+
QUnit.test('text selection should not be cleared when dragging on list item without onItemSwipe', function(assert) {
48094815
const $list = $('#list').dxList({
4810-
items: ['Item 1', 'Item 2']
4816+
items: ['Item 1', 'Item 2'],
48114817
});
48124818

4813-
const item = $list.find(`.${LIST_ITEM_CLASS}`).eq(0).get(0);
4819+
const { $item, textNode } = getFirstListItemAndTextNode($list);
48144820

4815-
const mouseDownEvent = new MouseEvent('mousedown', {
4816-
bubbles: true,
4817-
cancelable: true,
4818-
clientX: 10,
4819-
clientY: 10,
4820-
});
4821+
assert.ok(!!textNode, 'text node found in list item');
4822+
if(!textNode) return;
48214823

4822-
const selectStartEvent = new Event('selectstart', {
4823-
bubbles: true,
4824-
cancelable: true,
4824+
selectTextNodePart(textNode, 0, 4);
4825+
assert.strictEqual(window.getSelection().toString(), textNode.nodeValue.slice(0, 4), 'text selection exists before drag');
4826+
4827+
pointerMock($item).start().down(0, 0).move(50, 0).up();
4828+
4829+
assert.strictEqual(window.getSelection().toString(), textNode.nodeValue.slice(0, 4), 'text selection is preserved after horizontal drag');
4830+
window.getSelection().removeAllRanges();
4831+
});
4832+
4833+
QUnit.test('text selection should be preserved after onItemSwipe handler is removed from options', function(assert) {
4834+
const $list = $('#list').dxList({
4835+
items: ['Item 1', 'Item 2'],
4836+
onItemSwipe: sinon.spy(),
48254837
});
4838+
const list = $list.dxList('instance');
48264839

4827-
const mouseDownNotCanceled = item.dispatchEvent(mouseDownEvent);
4828-
const selectStartNotCanceled = item.dispatchEvent(selectStartEvent);
4840+
list.option('onItemSwipe', null);
48294841

4830-
assert.ok(mouseDownNotCanceled, 'mousedown is not canceled');
4831-
assert.notOk(mouseDownEvent.defaultPrevented, 'mousedown default is not prevented');
4832-
assert.ok(selectStartNotCanceled, 'selectstart is not canceled');
4833-
assert.notOk(selectStartEvent.defaultPrevented, 'selectstart default is not prevented');
4842+
const { $item, textNode } = getFirstListItemAndTextNode($list);
4843+
assert.ok(!!textNode, 'text node found in list item');
4844+
if(!textNode) return;
4845+
4846+
selectTextNodePart(textNode, 0, 4);
4847+
assert.strictEqual(window.getSelection().toString(), textNode.nodeValue.slice(0, 4), 'text selection exists before drag');
4848+
4849+
pointerMock($item).start().down(0, 0).move(50, 0).up();
4850+
4851+
assert.strictEqual(window.getSelection().toString(), textNode.nodeValue.slice(0, 4), 'text selection is preserved after drag when swipe handler is removed');
4852+
window.getSelection().removeAllRanges();
48344853
});
48354854

4836-
QUnit.test('text node should be selectable via Selection API', function(assert) {
4855+
QUnit.test('text selection should reflect itemSwipe on/off subscription state', function(assert) {
48374856
const $list = $('#list').dxList({
4838-
items: ['Item 1', 'Item 2']
4857+
items: ['Item 1', 'Item 2'],
48394858
});
48404859

4841-
const $item = $list.find('.dx-list-item-content').eq(0);
4842-
const textNode = $item.get(0).firstChild;
4860+
const list = $list.dxList('instance');
48434861

4844-
assert.ok(!!textNode, 'text node exists');
4862+
const { $item, textNode } = getFirstListItemAndTextNode($list);
48454863

4846-
if(!textNode) {
4847-
return;
4848-
}
4864+
assert.ok(!!textNode, 'text node found in list item');
48494865

4850-
const expected = textNode.textContent.slice(0, 4);
4851-
const selection = selectTextNodePart(textNode, 0, 4);
4866+
if(!textNode) return;
48524867

4853-
assert.strictEqual(selection.toString(), expected, 'text is selected');
4854-
selection.removeAllRanges();
4868+
list.on('itemSwipe', sinon.spy());
4869+
4870+
selectTextNodePart(textNode, 0, 4);
4871+
assert.strictEqual(window.getSelection().toString(), textNode.nodeValue.slice(0, 4), 'text selection exists before drag with subscribed swipe handler');
4872+
4873+
pointerMock($item).start().down(0, 0).move(50, 0).up();
4874+
4875+
assert.strictEqual(window.getSelection().toString(), '', 'text selection is cleared while swipe handler is attached');
4876+
4877+
list.off('itemSwipe');
4878+
4879+
selectTextNodePart(textNode, 0, 4);
4880+
assert.strictEqual(window.getSelection().toString(), textNode.nodeValue.slice(0, 4), 'text selection exists before drag');
4881+
4882+
pointerMock($item).start().down(0, 0).move(50, 0).up();
4883+
4884+
assert.strictEqual(window.getSelection().toString(), textNode.nodeValue.slice(0, 4), 'text selection is preserved after drag when swipe handler is removed');
4885+
window.getSelection().removeAllRanges();
48554886
});
48564887
});
48574888

0 commit comments

Comments
 (0)