Steps to Reproduce
https://zkfiddle.org/sample/2pvqgk0/18-Another-new-ZK-fiddle
Run fiddle
1. Select last Listitem
2. Click button (delete last item)
3. Shift+Click any Listitem
Current Result
Error: Index: 6, Size: 6
Expected Result
no error
Debug Information
caused by the Listbox._selectUpto function (from SelectWidget)
this._lastSelectedItem is not deleted from Listbox when listitem is removed, Listbox tries to use a non-existing index
Workaround
(see fiddle, commented out)
zk.afterLoad("zul.sel, zkmax", function () { var _xListbox = {}; zk.override(zul.sel.Listbox.prototype, _xListbox, { _focus: function (row) { this.shiftAnchor = null; return _xListbox._focus.apply(this, arguments); }, _selectOne: function (row, skipFocus) { this.shiftAnchor = null; return _xListbox._selectOne.apply(this, arguments); }, _toggleSelect: function (row, toSel, evt, skipFocus) { this.shiftAnchor = null; return _xListbox._toggleSelect.apply(this, arguments); }, _selectUpto: function (row, evt, skipFocus) { /* don't touch behavior for rod listbox */ if (this._listbox$rod) { return _xListbox._selectUpto.apply(this, arguments); } var shiftAnchor = this.shiftAnchor || this._focusItem || ((this._lastSelectedItem && this._lastSelectedItem.parent) ? this._lastSelectedItem : this.firstItem); this._unsetSelectAllExcept(); this._changeSelect(shiftAnchor, true); if (row.isSelected()) { if (!skipFocus) this._focus(row); return; } var focusfound = false, rowfound = false, lastSelected = shiftAnchor; if (!lastSelected.isSelected()) { var rowIndex = this.indexOfItem(row), min = Number.MAX_VALUE, closestSelItem; for (var i = 0; i < this._selItems.length; ++i) { var item = this._selItems[i], index = this.indexOfItem(item), diff = rowIndex - index, oldmin = min; if ((diff <= 0) && closestSelItem) break; min = Math.min(diff, min); if (min != oldmin) lastSelected = item; } } for (var it = this.getBodyWidgetIterator(), si = this.getSelectedItem(), w; (w = it.next());) { if (w.isDisabled() || !w.isSelectable()) continue; if (focusfound) { this._changeSelect(w, true); if (w == row) break; } else if (rowfound) { this._changeSelect(w, true); if (this._isFocus(w) || w == lastSelected) break; } else if (!si) { if (w != row) continue; this._changeSelect(w, true); break; } else { rowfound = w == row; focusfound = this._isFocus(w) || w == lastSelected; if (rowfound || focusfound) { this._changeSelect(w, true); if (rowfound && focusfound) break; } } } if (!skipFocus) this._focus(row); this.shiftAnchor = shiftAnchor; this.fireOnSelect(row, evt); }, onChildRemoved_: function (child) { if(this.shiftAnchor === child) { this.shiftAnchor = null; } return _xListbox.onChildRemoved_.apply(this, arguments); } }); });
Secondary issue, related to main issue
If there is no selected element (due to component just having been rendered, and no selection triggered), doing shift+click on an item will select all items from index 0 to target (see 2nd listbox with selected items content filled onSelect)
However, only the targeted Listitem is marked as selected.
(This is due to the same line of code as the main issue, if no bounding item is found)