Skip to content

Commit 59a2480

Browse files
committed
issue-171 many-to-one replacement, increase option
1 parent 35f7695 commit 59a2480

File tree

5 files changed

+80
-33
lines changed

5 files changed

+80
-33
lines changed

src/component/inputs/adapter.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ const INSERT_METHOD_PARAMS: ICommonProps<AdapterInsertParams> = {
121121
enum AdapterReplaceParams {
122122
items = 'items',
123123
predicate = 'predicate',
124+
increase = 'increase',
124125
}
125126

126127
const REPLACE_METHOD_PARAMS: ICommonProps<AdapterReplaceParams> = {
@@ -129,7 +130,11 @@ const REPLACE_METHOD_PARAMS: ICommonProps<AdapterReplaceParams> = {
129130
mandatory: true
130131
},
131132
[AdapterReplaceParams.predicate]: {
132-
validators: [FUNC_WITH_X_ARGUMENTS(1)]
133+
validators: [FUNC_WITH_X_ARGUMENTS(1)],
134+
mandatory: true
135+
},
136+
[AdapterReplaceParams.increase]: {
137+
validators: [BOOLEAN]
133138
}
134139
};
135140

src/component/interfaces/adapter.ts

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export interface AdapterInsertOptions {
6060
export interface AdapterReplaceOptions {
6161
items: any[];
6262
predicate: ItemsPredicate;
63+
increase?: boolean;
6364
}
6465

6566
export interface AdapterFixOptions {
+22-10
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import { getBaseAdapterProcess } from './_base';
22
import { Scroller } from '../../scroller';
3-
import { AdapterProcess, ProcessStatus, AdapterReplaceOptions, AdapterInsertOptions } from '../../interfaces/index';
43
import Remove from './remove';
54
import Insert from './insert';
5+
import {
6+
AdapterProcess, ProcessStatus, AdapterReplaceOptions, AdapterInsertOptions, AdapterRemoveOptions
7+
} from '../../interfaces/index';
68

79
export default class Replace extends getBaseAdapterProcess(AdapterProcess.replace) {
810

@@ -12,22 +14,15 @@ export default class Replace extends getBaseAdapterProcess(AdapterProcess.replac
1214
return;
1315
}
1416

15-
const shouldRemove = Remove.doRemove(scroller, params, true);
16-
if (!shouldRemove) {
17+
if (!Replace.doRemove(scroller, params)) {
1718
scroller.logger.log(() => 'no items to replace (not found)');
1819
return scroller.workflow.call({
1920
process: Replace.process,
2021
status: ProcessStatus.done
2122
});
2223
}
2324

24-
const insertOptions: AdapterInsertOptions = {
25-
items: params.items,
26-
before: params.predicate,
27-
decrease: false
28-
};
29-
const shouldInsert = Insert.doInsert(scroller, insertOptions);
30-
if (!shouldInsert) {
25+
if (!Replace.doInsert(scroller, params)) {
3126
return scroller.workflow.call({
3227
process: Replace.process,
3328
status: ProcessStatus.done
@@ -40,4 +35,21 @@ export default class Replace extends getBaseAdapterProcess(AdapterProcess.replac
4035
});
4136
}
4237

38+
static doRemove(scroller: Scroller, params: AdapterReplaceOptions) {
39+
const removeOptions: AdapterRemoveOptions = {
40+
predicate: params.predicate,
41+
increase: params.increase
42+
};
43+
return Remove.doRemove(scroller, removeOptions, true);
44+
}
45+
46+
static doInsert(scroller: Scroller, params: AdapterReplaceOptions) {
47+
const insertOptions: AdapterInsertOptions = {
48+
items: params.items,
49+
after: params.predicate,
50+
decrease: params.increase
51+
};
52+
return Insert.doInsert(scroller, insertOptions);
53+
}
54+
4355
}

tests/adapter.replace.spec.ts

+46-17
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ const baseSettings = {
1111
itemSize: 20
1212
};
1313

14+
interface ICustom {
15+
token: 'first' | 'last' | 'middle';
16+
indexToReplace?: number;
17+
indexesToReplace?: number[];
18+
increase?: boolean;
19+
}
20+
1421
const configList: TestBedConfig[] = [{
1522
datasourceSettings: { ...baseSettings },
1623
custom: {
@@ -22,19 +29,19 @@ const configList: TestBedConfig[] = [{
2229
custom: {
2330
indexToReplace: baseSettings.minIndex,
2431
token: 'first'
25-
}
32+
} as ICustom
2633
}, {
2734
datasourceSettings: { ...baseSettings, startIndex: baseSettings.maxIndex },
2835
custom: {
2936
indexToReplace: baseSettings.maxIndex,
3037
token: 'last'
31-
}
38+
} as ICustom
3239
}].map(config => ({
3340
...config,
3441
datasourceClass: getDatasourceReplacementsClass(config.datasourceSettings)
3542
}));
3643

37-
const someToOneConfigList: TestBedConfig[] = [{
44+
const manyToOneConfigList: TestBedConfig[] = [{
3845
datasourceSettings: { ...baseSettings },
3946
custom: {
4047
indexesToReplace: [
@@ -43,7 +50,7 @@ const someToOneConfigList: TestBedConfig[] = [{
4350
baseSettings.minIndex + 3
4451
],
4552
token: 'middle'
46-
}
53+
} as ICustom
4754
}, {
4855
datasourceSettings: { ...baseSettings },
4956
custom: {
@@ -53,7 +60,7 @@ const someToOneConfigList: TestBedConfig[] = [{
5360
baseSettings.minIndex + 2
5461
],
5562
token: 'first'
56-
}
63+
} as ICustom
5764
}, {
5865
datasourceSettings: { ...baseSettings, startIndex: baseSettings.maxIndex },
5966
custom: {
@@ -63,36 +70,47 @@ const someToOneConfigList: TestBedConfig[] = [{
6370
baseSettings.maxIndex
6471
],
6572
token: 'last'
66-
}
73+
} as ICustom
6774
}].map(config => ({
6875
...config,
6976
datasourceClass: getDatasourceReplacementsClass(config.datasourceSettings)
7077
}));
7178

79+
const manyToOneIncreaseConfigList = manyToOneConfigList.map(config => ({
80+
...config,
81+
custom: {
82+
...config.custom,
83+
increase: true
84+
}
85+
}));
7286

7387
const shouldReplace = (config: TestBedConfig) => (misc: Misc) => async (done: Function) => {
7488
await misc.relaxNext();
7589
const { adapter } = misc;
76-
const { custom: { indexToReplace: index, indexesToReplace: indexes, token } } = config;
90+
const { indexToReplace: index, indexesToReplace: indexes, token, increase } = config.custom;
7791
const { datasourceSettings: { minIndex, itemSize } } = config;
7892
const diff = indexes ? indexes.length : 1;
79-
const maxScrollPosition = misc.getMaxScrollPosition() - (diff - 1) * misc.getItemSize();
80-
const newIndex = indexes ? indexes[0] : index;
81-
const position = token === 'last' ? maxScrollPosition : (newIndex - 1 + minIndex - 1) * itemSize;
93+
const viewportSize = misc.getScrollableSize();
94+
const sizeToRemove = (diff - 1) * misc.getItemSize();
95+
const maxScrollPosition = misc.getMaxScrollPosition() - sizeToRemove;
96+
const newIndex = indexes ? indexes[increase ? indexes.length - 1 : 0] : index;
97+
const newMinIndex = increase ? minIndex + diff - 1 : minIndex;
98+
const position = token === 'last' ? maxScrollPosition : (newIndex - newMinIndex) * itemSize;
8299
const newItem = generateItem(newIndex);
83100
newItem.text += '*';
84101

85102
// replace at the Datasource level (component)
86103
if (index) {
87104
(misc.datasource as any).replaceOneToOne(index, newItem);
88105
} else if (indexes) {
89-
(misc.datasource as any).replaceManyToOne(indexes, newItem);
106+
(misc.datasource as any).replaceManyToOne(indexes, newItem, increase);
90107
}
91108

92109
// replace at the Viewport level (scroller)
93110
await adapter.replace({
94111
predicate: ({ $index }) => (indexes || [index]).includes($index),
95-
items: [newItem]
112+
items: [newItem],
113+
increase
96114
});
97115

98116
await misc.scrollMinMax();
@@ -113,17 +131,18 @@ const shouldReplace = (config: TestBedConfig) => (misc: Misc) => async (done: Fu
113131

114132
// check the next item
115133
if (token === 'last') {
116-
expect(misc.checkElementContent(newIndex - 1, newIndex - 1)).toEqual(true);
134+
expect(misc.checkElementContent(newIndex - 1, newIndex - (increase ? diff : 1))).toEqual(true);
117135
} else {
118-
expect(misc.checkElementContent(newIndex + 1, newIndex + diff)).toEqual(true);
136+
expect(misc.checkElementContent(newIndex + 1, newIndex + (increase ? 1 : diff))).toEqual(true);
119137
}
120138

139+
expect(misc.getScrollableSize()).toBe(viewportSize - sizeToRemove);
121140
done();
122141
};
123142

124143
describe('Adapter Replace Spec', () => {
125144

126-
describe('single replacement', () =>
145+
describe('one-to-ne replacement', () =>
127146
configList.forEach(config =>
128147
makeTest({
129148
title: `should work (${config.custom.token})`,
@@ -133,8 +152,18 @@ describe('Adapter Replace Spec', () => {
133152
)
134153
);
135154

136-
describe('some-to-one replacement', () =>
137-
someToOneConfigList.forEach(config =>
155+
describe('many-to-one replacement', () =>
156+
manyToOneConfigList.forEach(config =>
157+
makeTest({
158+
title: `should work (${config.custom.token})`,
159+
config,
160+
it: shouldReplace(config)
161+
})
162+
)
163+
);
164+
165+
describe('many-to-one increase replacement', () =>
166+
manyToOneIncreaseConfigList.forEach(config =>
138167
makeTest({
139168
title: `should work (${config.custom.token})`,
140169
config,

tests/scaffolding/datasources/class.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export const getDatasourceReplacementsClass = (settings: Settings) =>
7575
}
7676
}
7777

78-
replaceManyToOne(idsToReplace: number[], item: Item) {
78+
replaceManyToOne(idsToReplace: number[], item: Item, increase: boolean) {
7979
idsToReplace.sort((a, b) => a - b);
8080
const minId = idsToReplace[0];
8181
const maxId = idsToReplace.slice(1).reduce((acc, id) =>
@@ -84,12 +84,12 @@ export const getDatasourceReplacementsClass = (settings: Settings) =>
8484
);
8585
const diff = maxId - minId;
8686
this.data = this.data.reduce((acc, _item: Item) => {
87-
if (_item.id < minId) {
87+
if ((!increase && _item.id < minId) || (increase && _item.id > maxId)) {
8888
acc.push(_item);
89-
} else if (_item.id === minId) {
89+
} else if ((increase && _item.id === minId) || (!increase && _item.id === maxId)) {
9090
acc.push(item);
91-
} else if (_item.id > maxId) {
92-
acc.push({ ..._item, id: _item.id - diff });
91+
} else if ((!increase && _item.id > maxId) || (increase && _item.id < minId)) {
92+
acc.push({ ..._item, id: _item.id + (increase ? 1 : -1) * diff });
9393
}
9494
return acc;
9595
}, [] as Item[]);

0 commit comments

Comments
 (0)