Uploaded image for project: 'ZK'
  1. ZK
  2. ZK-4850

Autopaging row height calculation incorrect by 1px

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: Normal Normal
    • 9.6.0
    • 9.5.1
    • Components
    • 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 

      { # border-top-width: 0; }

       
      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>
      
      

            Leon03 Leon03
            MDuchemin MDuchemin
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: