Skip to content

Commit 1da5484

Browse files
committed
Fixed sorting in chained extenders by keeping track of chages.
Todo think about a more peformant way to keep track of the changes, instead of reevaluating all conntection after each step.
1 parent 8450a98 commit 1da5484

File tree

1 file changed

+60
-31
lines changed

1 file changed

+60
-31
lines changed

src/query/ExtenderHelper.js

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ define([
33
'../modules/Events',
44
'./Observer'
55
], function (blocks, Events, Observer) {
6-
6+
77
var Action = {
88
NOOP: 0,
99
ADD: 1,
@@ -33,15 +33,14 @@ define([
3333
newObservable.view._initialized = false;
3434

3535
newObservable.view.on('get', newObservable._getter);
36-
3736
newObservable.on('add', function () {
3837
if (newObservable.view._initialized) {
3938
newObservable.view._connections = {};
4039
newObservable.view.reset();
4140
ExtenderHelper.executeOperations(newObservable);
4241
}
4342
});
44-
43+
4544
newObservable.on('remove', function () {
4645
if (newObservable.view._initialized) {
4746
newObservable.view._connections = {};
@@ -114,18 +113,27 @@ define([
114113
},
115114

116115
executeOperationsChunk: function (observable, operations) {
117-
var action = Action.EXISTS;
116+
var action = Action.NOOP;
118117

119118
var collection = observable.__value__;
120119
var view = observable.view;
120+
// key = index of the __value__ array, value = index of the same value in the view
121121
var connections = view._connections;
122+
// key = index in the sorted collection, value = index in the (unsorted) connections
123+
var sortedConnections = {};
124+
var sorted = false;
122125
var newConnections = {};
123-
var viewIndex = 0;
126+
var collectionIndex;
127+
var targetViewIndex = 0;
124128
var update = view.update;
125129
var skip = 0;
126130
var take = collection.length;
127131
view.update = blocks.noop;
128132

133+
function getConnection(index) {
134+
return sorted ? connections[sortedConnections[index]] : connections[index];
135+
}
136+
129137
blocks.each(operations, function prepareOperations(operation) {
130138
switch (operation.type) {
131139
case ExtenderHelper.operations.SKIP:
@@ -135,15 +143,16 @@ define([
135143
}
136144
skip = blocks.unwrap(skip);
137145
break;
146+
138147
case ExtenderHelper.operations.TAKE:
139148
take = operation.take;
140149
if (blocks.isFunction(take)) {
141150
take = take.call(observable.__context__);
142151
}
143152
take = blocks.unwrap(take);
144153
break;
154+
145155
case ExtenderHelper.operations.SORT:
146-
// @todo resort connections after sorting this
147156
if (blocks.isString(operation.sort)) {
148157
collection = blocks.clone(collection).sort(function (valueA, valueB) {
149158
valueA = blocks.unwrap(valueA[operation.sort]);
@@ -162,16 +171,29 @@ define([
162171
collection = blocks.clone(collection).sort();
163172
}
164173
if (operations.length == 1) {
165-
operations.push({ type: ExtenderHelper.operations.FILTER, filter: function () { return true; }});
174+
operations.push({ type: ExtenderHelper.operations.FILTER, filter: noopFilter });
166175
}
176+
sorted = true;
167177
break;
168178
}
169179
});
170180

181+
if (sorted) {
182+
// create sortedConnections to match the sorted collection to connections
183+
blocks.each(observable.__value__, function (original, originalIndex) {
184+
blocks.each(collection, function (value, newIndex) {
185+
if (value == original) {
186+
sortedConnections[newIndex] = originalIndex;
187+
return false;
188+
}
189+
});
190+
});
191+
}
192+
171193
blocks.each(collection, function iterateCollection(value, index) {
172-
var oldIndex;
194+
var currentViewIndex;
173195
if (take <= 0) {
174-
while (view().length - viewIndex > 0) {
196+
while (view().length - targetViewIndex > 0) {
175197
view.removeAt(view().length - 1);
176198
view._connections = {};
177199
}
@@ -182,19 +204,17 @@ define([
182204
var filterCallback = operation.filter;
183205
operation.type = operation.type || (filterCallback && ExtenderHelper.operations.FILTER);
184206

185-
action = Action.NOOP;
186-
187207
switch (operation.type) {
188208
case ExtenderHelper.operations.FILTER:
189209
if (filterCallback.call(observable.__context__, value, index, collection)) {
190210
action = Action.EXISTS;
191211

192-
if (connections[index] === undefined) {
212+
if (getConnection(index) === undefined) {
193213
action = Action.ADD;
194214
}
195215
} else {
196216
action = Action.NOOP;
197-
if (connections[index] !== undefined) {
217+
if (getConnection(index) !== undefined) {
198218
action = Action.REMOVE;
199219
}
200220
return false;
@@ -207,7 +227,7 @@ define([
207227
if (skip >= 0) {
208228
action = Action.REMOVE;
209229
return false;
210-
} else if (skip < 0 && connections[index] === undefined) {
230+
} else if (skip < 0 && getConnection(index) === undefined) {
211231
action = Action.ADD;
212232
}
213233
break;
@@ -220,48 +240,56 @@ define([
220240
take -= 1;
221241
action = Action.EXISTS;
222242

223-
if (connections[index] === undefined) {
243+
if (getConnection(index) === undefined) {
224244
action = Action.ADD;
225245
}
226246
}
227247
break;
228248
}
229249
});
230250

231-
oldIndex = connections[index];
251+
currentViewIndex = getConnection(index);
252+
collectionIndex = sorted ? sortedConnections[index] : index;
253+
232254
switch (action) {
233255
case Action.ADD:
234-
newConnections[index] = viewIndex;
235-
view.splice(viewIndex, 0, value);
256+
newConnections[collectionIndex] = targetViewIndex;
257+
view.splice(targetViewIndex, 0, value);
258+
259+
// update connections so that the connections reflect the changes on the view-array
236260
blocks.each(connections, function (valueViewIndex, i) {
237-
if (valueViewIndex >= viewIndex) {
261+
if (valueViewIndex >= targetViewIndex) {
238262
connections[i] = ++valueViewIndex;
239263
}
240264
});
241-
viewIndex++;
265+
targetViewIndex++;
242266
break;
267+
243268
case Action.REMOVE:
244-
view.removeAt(oldIndex);
269+
view.removeAt(currentViewIndex);
270+
271+
// update connections so that the connections reflect the changes on the view-array
245272
blocks.each(connections, function (valueViewIndex,i ) {
246-
if (valueViewIndex > oldIndex) {
273+
if (valueViewIndex > currentViewIndex) {
247274
connections[i] = --valueViewIndex;
248275
}
249276
});
250277
break;
278+
251279
case Action.EXISTS:
252-
newConnections[index] = viewIndex;
253-
if (oldIndex != viewIndex) {
254-
view.move(oldIndex, viewIndex);
280+
newConnections[collectionIndex] = targetViewIndex;
281+
if (currentViewIndex != targetViewIndex) {
282+
view.move(currentViewIndex, targetViewIndex);
283+
284+
// update connections so that the connections reflect the changes on the view-array
255285
blocks.each(connections, function (valueViewIndex, i) {
256-
if (valueViewIndex > oldIndex) {
257-
valueViewIndex--;
258-
} else if (valueViewIndex > viewIndex) {
259-
valueViewIndex++;
286+
if (sorted ? i == sortedConnections[index] : i == index) {
287+
return;
260288
}
261-
connections[i] = valueViewIndex;
289+
connections[i] = (valueViewIndex > currentViewIndex ? --valueViewIndex : ++valueViewIndex) ;
262290
});
263291
}
264-
viewIndex++;
292+
targetViewIndex++;
265293
break;
266294
}
267295
});
@@ -271,6 +299,7 @@ define([
271299
view.update();
272300
}
273301
};
302+
function noopFilter() { return true; }
274303

275304
return ExtenderHelper;
276305
});

0 commit comments

Comments
 (0)