in src/Clients/Web/winjs/js/winjs.js [47322:47523]
_synchronize: function ListView_synchronize() {
var updater = this._updater;
this._updater = null;
this._groupsChanged = false;
this._countDifference = this._countDifference || 0;
if (updater && updater.changed) {
if (updater.itemsMoved) {
this._layout.itemsMoved && this._layout.itemsMoved();
}
if (updater.removed.length) {
this._layout.itemsRemoved && this._layout.itemsRemoved(updater.removed.map(function (node) {
return node.itemBox;
}));
}
if (updater.itemsMoved || updater.removed.length || Object.keys(this._insertedItems).length) {
this._layout.setupAnimations && this._layout.setupAnimations();
}
if (this._currentMode().onDataChanged) {
this._currentMode().onDataChanged();
}
var newSelection = [];
for (var i in updater.selectionFirst) {
if (updater.selectionFirst.hasOwnProperty(i)) {
var range = updater.selectionFirst[i];
updater.selectionChanged = updater.selectionChanged || ((range.newLastIndex - range.newFirstIndex) !== (range.oldLastIndex - range.oldFirstIndex));
if (range.newFirstIndex <= range.newLastIndex) {
newSelection.push({
firstIndex: range.newFirstIndex,
lastIndex: range.newLastIndex
});
}
}
}
if (updater.selectionChanged) {
var newSelectionItems = new _SelectionManager._Selection(this, newSelection);
// We do not allow listeners to cancel the selection
// change because the cancellation would also have to
// prevent the deletion.
this._selection._fireSelectionChanging(newSelectionItems);
this._selection._selected.set(newSelection);
this._selection._fireSelectionChanged();
newSelectionItems.clear();
} else {
this._selection._selected.set(newSelection);
}
this._selection._updateCount(this._cachedCount);
updater.newSelectionPivot = Math.min(this._cachedCount - 1, updater.newSelectionPivot);
this._selection._pivot = (updater.newSelectionPivot >= 0 ? updater.newSelectionPivot : _Constants._INVALID_INDEX);
if (updater.newFocus.type !== _UI.ObjectType.groupHeader) {
updater.newFocus.index = Math.max(0, Math.min(this._cachedCount - 1, updater.newFocus.index));
}
this._selection._setFocused(updater.newFocus, this._selection._keyboardFocused());
// If there are 2 edits before layoutAnimations runs we need to merge the 2 groups of modified elements.
// For example:
// If you start with A, B, C and add item Z to the beginning you will have
// [ -1 -> 0, 0 -> 1, 1 -> 2, 2 -> 3]
// However before layout is called an insert of Y to the beginning also happens you should get
// [ -1 -> 0, -1 -> 1, 0 -> 2, 1 -> 3, 2 -> 4]
var previousModifiedElements = this._modifiedElements || [];
var previousModifiedElementsHash = {};
this._modifiedElements = [];
this._countDifference += updater.countDifference;
for (i = 0; i < previousModifiedElements.length; i++) {
var modifiedElement = previousModifiedElements[i];
if (modifiedElement.newIndex === -1) {
this._modifiedElements.push(modifiedElement);
} else {
previousModifiedElementsHash[modifiedElement.newIndex] = modifiedElement;
}
}
for (i = 0; i < updater.removed.length; i++) {
var removed = updater.removed[i];
var modifiedElement = previousModifiedElementsHash[removed.index];
if (modifiedElement) {
delete previousModifiedElementsHash[removed.index];
} else {
modifiedElement = {
oldIndex: removed.index
};
}
modifiedElement.newIndex = -1;
if (!modifiedElement._removalHandled) {
modifiedElement._itemBox = removed.itemBox;
modifiedElement._containerStripe = removed.containerStripe;
}
this._modifiedElements.push(modifiedElement);
}
var insertedKeys = Object.keys(this._insertedItems);
for (i = 0; i < insertedKeys.length; i++) {
this._modifiedElements.push({
oldIndex: -1,
newIndex: this._insertedItems[insertedKeys[i]].index
});
}
this._writeProfilerMark("_synchronize:update_modifiedElements,StartTM");
var newItems = {};
for (i in updater.elements) {
if (updater.elements.hasOwnProperty(i)) {
var elementInfo = updater.elements[i];
newItems[elementInfo.newIndex] = {
element: elementInfo.item,
container: elementInfo.container,
itemBox: elementInfo.itemBox,
itemsManagerRecord: elementInfo.itemsManagerRecord,
detached: elementInfo.detached
};
var modifiedElement = previousModifiedElementsHash[elementInfo.index];
if (modifiedElement) {
delete previousModifiedElementsHash[elementInfo.index];
modifiedElement.newIndex = elementInfo.newIndex;
} else {
modifiedElement = {
oldIndex: elementInfo.index,
newIndex: elementInfo.newIndex
};
}
modifiedElement.moved = elementInfo.moved;
this._modifiedElements.push(modifiedElement);
}
}
this._writeProfilerMark("_synchronize:update_modifiedElements,StopTM");
var previousIndices = Object.keys(previousModifiedElementsHash);
for (i = 0; i < previousIndices.length; i++) {
var key = previousIndices[i];
var modifiedElement = previousModifiedElementsHash[key];
if (modifiedElement.oldIndex !== -1) {
this._modifiedElements.push(modifiedElement);
}
}
this._view.items._itemData = newItems;
if (updater.updateDrag && this._currentMode()._dragging) {
if (!this._currentMode()._draggingUnselectedItem) {
this._currentMode()._dragInfo = this._selection;
} else if (updater.newDragInfo) {
this._currentMode()._dragInfo = updater.newDragInfo;
}
this._currentMode().fireDragUpdateEvent();
}
// If the focused item is removed, or the item we're trying to focus on has been moved before we can focus on it,
// we need to update our focus request to get the item from the appropriate index.
if (updater.focusedItemRemoved || (this._focusRequest && (updater.oldFocus.index !== updater.newFocus.index) || (updater.oldFocus.type !== updater.newFocus.type))) {
this._itemFocused = false;
this._setFocusOnItem(this._selection._getFocused());
} else if (updater.newFocusedItem) {
// We need to restore the value of _hasKeyboardFocus because a changed item
// gets removed from the DOM at the time of the notification. If the item
// had focus at that time, then our value of _hasKeyboardFocus will have changed.
this._hasKeyboardFocus = updater.hadKeyboardFocus;
this._itemFocused = false;
this._setFocusOnItem(this._selection._getFocused());
}
var that = this;
return this._groups.synchronizeGroups().then(function () {
if (updater.newFocus.type === _UI.ObjectType.groupHeader) {
updater.newFocus.index = Math.min(that._groups.length() - 1, updater.newFocus.index);
if (updater.newFocus.index < 0) {
// An empty listview has currentFocus = item 0
updater.newFocus = { type: _UI.ObjectType.item, index: 0 };
}
that._selection._setFocused(updater.newFocus, that._selection._keyboardFocused());
}
that._versionManager.endUpdating();
if (updater.deletesCount > 0) {
that._updateDeleteWrapperSize();
}
return that._view.updateTree(that._cachedCount, that._countDifference, that._modifiedElements);
}).then(function () {
return that._lastScrollPosition;
});
} else {
this._countDifference += updater ? updater.countDifference : 0;
var that = this;
return this._groups.synchronizeGroups().then(function ListView_synchronizeGroups_success_groupsChanged() {
updater && that._versionManager.endUpdating();
return that._view.updateTree(that._cachedCount, that._countDifference, that._modifiedElements);
}).then(function () {
return that.scrollPosition;
});
}
},