-
Bug
-
Resolution: Fixed
-
Normal
-
9.5.1
-
Security Level: Jimmy
-
None
Steps to Reproduce
Run fiddle
https://zkfiddle.org/sample/3e6inie/1-autopaging-height-calculation
Open fiddle result to separate tab (not in modal window)
Resize the window vertically until 9 rows are displayed.
Resize the window to one pixel (1px) smaller than the amount allowing 9 rows.
On local test, this is 494px
navigate to page 3 using the paging component
Current Result
Page 3 triggers MeshWidget._fixPageSize calculation. calculates a pageSize of 9.
Sends onPageSize event to grid to request data for 9 items on page 3.
Model contains 18 items, therefore 9 items on page 3 returns no entries, instead the grid returns 9 items on page 2 (items index 9 to 17).
Page 2 renders and trigger MeshWidget._fixPageSize calculation. calculates a pageSize of 8.
displays items index 8 to 15 (2nd page, with pagesize of 8)
Causes 3rd page to be unreachable by user
Expected Result
PageSize calculation on page 3 should be coherent with pageSize calculation on a full page
Debug Information
PageSize is calculated based the last row in the page
The average row height is calculated by adding the row offsetTop to row height and dividing by the number of rendered items.
However, this calculation can be off by 1px due to border calculations.
Style includes:
.z-row:first-child .z-row-inner, .z-row:first-child .z-cell
which cause every row but the first to have a border.
Assuming a content height of 10px, the average height calculated per row is:
1 row: (10) -> 10/1 = 10px
2 rows (10, 11): -> 21/2 = 10.5px
3 rows (10, 11, 11): -> 32/3 = 10.6666666667px
4 rows (10, 11, 11, 11): ->43/4 = 10.75px;
etc
This is enough to cause a page size mismatch if the last page has a low item count.
Workaround
manually add the extra 1px for the missing first border, cause imprecision in the other direction (over evaluate all rows by some fractions of a pixel).
However, imprecision in this direction doesn't cause shifts in pageSize
<script><![CDATA[ zk.afterLoad("zul.mesh", function () { function _fixPageSize(wgt, rows) { var ebody = wgt.ebody; if (!ebody) return; //not ready yet var max = ebody.offsetHeight; if (zk(ebody).hasHScroll()) //with horizontal scrollbar max -= jq.scrollbarWidth(); if (max == wgt._prehgh) return false; //same height, avoid fixing page size wgt._prehgh = max; var ebodytbl = wgt.ebodytbl, etbparent = ebodytbl.offsetParent, etbtop = ebodytbl.offsetTop, hgh = 0, row, j = 0; for (var it = wgt.getBodyWidgetIterator({skipHidden: true}), len = rows.length, w; (w = it.next()) && j < len; j++) { row = rows[j]; var top = row.offsetTop - (row.offsetParent == etbparent ? etbtop : 0); if (top > max) { --j; break; } hgh = top; } if (row) { //there is row var pgib = wgt.$n('pgib'), pgibHgh = 0; if (pgib) pgibHgh = pgib.offsetHeight; var withPgibMax = max + pgibHgh; if (top <= withPgibMax) { //row not exceeds the height, estimate var paging = (wgt.paging) ? wgt.paging : wgt.getPaginal(), totalsz = paging.getTotalSize(), rowsHgh = hgh + row.offsetHeight + 1, j1 = Math.floor(j * max / rowsHgh), j2 = Math.floor(j * withPgibMax / rowsHgh); if (totalsz > j2 || !paging.isAutohide()) j = j1; else j = j2; } //enforce pageSize change if (j == 0) j = 1; //at least one per page if (j != wgt.getPageSize()) { wgt.fire('onPageSize', {size: j}); return true; } } } var _xMeshWidget = {}; zk.override(zul.mesh.MeshWidget.prototype, _xMeshWidget, { _onRender: function () { //overriden in zkmax if (!this.$n()) return; // the target may not exist. B50-ZK-963 this._pendOnRender = false; if (this._syncingbodyrows || zAu.processing()) { //wait if busy (it might run outer) this.fireOnRender(zk.gecko ? 200 : 60); //is syncing rows, try it later return true; } var rows = this.ebodyrows ? this.ebodyrows.rows : null; if (this.inPagingMold() && this._autopaging && rows && rows.length) if (_fixPageSize(this, rows)) return; //need to reload with new page size if (zk.ie9 && (this._wsbak !== undefined)) { // B50-ZK-432 this.$n().style.whiteSpace = this._wsbak; delete this._wsbak; } if (!this.desktop || !this._model || !rows || !rows.length) return; //Note: we have to calculate from top to bottom because each row's //height might diff (due to different content) var items = [], min = zul.mesh.Scrollbar.getScrollPosV(this), max = min + this.ebody.offsetHeight; if (min == 0 && max == 0) return; //ZK-2796: Uncessary onRender command triggered when setting tabbox's maximalHeight attribute to true for (var j = 0, it = this.getBodyWidgetIterator({skipHidden: true}), len = rows.length, w; (w = it.next()) && j < len; j++) { if (!w._loaded) { //B70-ZK-2589: w and rows[j] belongs to different widget, //w shouldn't depend on rows[j], origin -> row = rows[j]; var row = w.$n(); if (row == null) continue; var $row = zk(row), top = $row.offsetTop(); if (top + $row.offsetHeight() < min) continue; if (top > max) break; //Bug 1822517 items.push(w); } } if (items.length) { this.fire('onRender', {items: items}, {implicit: true}); } } }); }); ]]></script>