diff --git a/iron-list.html b/iron-list.html index 27b92725..f36603f7 100644 --- a/iron-list.html +++ b/iron-list.html @@ -1629,7 +1629,87 @@ if (activeEl && physicalItem !== activeEl && physicalItem.contains(activeEl) && activeElTabIndex !== SECRET_TABINDEX) { return; } - this.toggleSelectionForItem(model[this.as]); + + var sourceEvent = e && e.detail && e.detail.sourceEvent; + + // Handle `shift` click scenario + if (this.multiSelection && this.selectedItems.length && sourceEvent.shiftKey) { + this._shiftSelectHandler(model[this.as]); + } else { + this.toggleSelectionForItem(model[this.as]); + } + }, + + _shiftSelectHandler: function(selectedItem) { + var selectedIndex = this.items.indexOf(selectedItem); + var _selectedItemIndexes = this.selectedItems.map(function(item) { + return this.items.indexOf(item); + }.bind(this)); + + var firstSelectedIndex = _selectedItemIndexes.reduce(function(currentIndex, itemIndex) { + return Math.min(currentIndex, itemIndex); + }); + + var lastSelectedIndex = _selectedItemIndexes.reduce(function(currentIndex, itemIndex) { + return Math.max(currentIndex, itemIndex); + }); + + var startIndex = Math.min(selectedIndex, firstSelectedIndex); + var lastIndex = Math.max(selectedIndex, lastSelectedIndex); + + // Select the range created with the shift select + this._selectRange(startIndex, lastIndex); + + // Deselect everything outside of the shift select range (will only occur + // if a user shift selects in the middle of a range) + if (selectedIndex > firstSelectedIndex && selectedIndex < lastSelectedIndex) { + this._deselectRange(selectedIndex + 1, lastSelectedIndex); + } + }, + + /** + * Updates the models of all physical items + */ + _updatePhysicalItemModels: function() { + this._physicalItems.map(function(el) { + return this.modelForElement(el); + }.bind(this)).forEach(function(model) { + model[this.selectedAs] = (this.$.selector).isSelected(this.items[model[this.indexAs]]); + }.bind(this)); + }, + + /** + * UnSelect all items in a certain range (inclusive of both start and end) + */ + _deselectRange: function(start, end) { + this.items.slice(start, end + 1) + .map(function(item) { + return this._getNormalizedItem(item); + }.bind(this)) + .filter(function(item) { + return (this.$.selector).isSelected(item); + }.bind(this)) + .forEach(function(item) { + this.$.selector.deselect(item); + }.bind(this)); + this._updatePhysicalItemModels(); + }, + + /** + * Select all items in a certain range (inclusive of both start and end) + */ + _selectRange: function(start, end) { + this.items.slice(start, end + 1) + .map(function(item) { + return this._getNormalizedItem(item); + }.bind(this)) + .filter(function(item) { + return !(this.$.selector).isSelected(item); + }.bind(this)) + .forEach(function(item) { + this.$.selector.select(item); + }.bind(this)); + this._updatePhysicalItemModels(); }, _multiSelectionChanged: function(multiSelection) {