@haxtheweb/haxcms-nodejs
Version:
HAXcms single and multisite nodejs server, api, and administration
6 lines • 7.49 kB
JavaScript
/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
import{SizeCache as i}from"./shared/SizeCache.js";import{BaseLayout as t,dim1 as e}from"./shared/BaseLayout.js";export const flow=i=>Object.assign({type:FlowLayout},i);function leadingMargin(i){return"horizontal"===i?"marginLeft":"marginTop"}function trailingMargin(i){return"horizontal"===i?"marginRight":"marginBottom"}function offset(i){return"horizontal"===i?"xOffset":"yOffset"}function collapseMargins(i,t){const e=[i,t].sort();return e[1]<=0?Math.min(...e):e[0]>=0?Math.max(...e):e[0]+e[1]}class MetricsCache{constructor(){this._childSizeCache=new i,this._marginSizeCache=new i,this._metricsCache=new Map}update(i,t){const s=new Set;Object.keys(i).forEach((h=>{const a=Number(h);this._metricsCache.set(a,i[a]),this._childSizeCache.set(a,i[a][e(t)]),s.add(a),s.add(a+1)}));for(const i of s){const e=this._metricsCache.get(i)?.[leadingMargin(t)]||0,s=this._metricsCache.get(i-1)?.[trailingMargin(t)]||0;this._marginSizeCache.set(i,collapseMargins(e,s))}}get averageChildSize(){return this._childSizeCache.averageSize}get totalChildSize(){return this._childSizeCache.totalSize}get averageMarginSize(){return this._marginSizeCache.averageSize}get totalMarginSize(){return this._marginSizeCache.totalSize}getLeadingMarginValue(i,t){return this._metricsCache.get(i)?.[leadingMargin(t)]||0}getChildSize(i){return this._childSizeCache.getSize(i)}getMarginSize(i){return this._marginSizeCache.getSize(i)}clear(){this._childSizeCache.clear(),this._marginSizeCache.clear(),this._metricsCache.clear()}}export class FlowLayout extends t{constructor(){super(...arguments),this._itemSize={width:100,height:100},this._physicalItems=new Map,this._newPhysicalItems=new Map,this._metricsCache=new MetricsCache,this._anchorIdx=null,this._anchorPos=null,this._stable=!0,this._measureChildren=!0,this._estimate=!0}get measureChildren(){return this._measureChildren}updateItemSizes(i){this._metricsCache.update(i,this.direction),this._scheduleReflow()}_getPhysicalItem(i){return this._newPhysicalItems.get(i)??this._physicalItems.get(i)}_getSize(i){return this._getPhysicalItem(i)&&this._metricsCache.getChildSize(i)}_getAverageSize(){return this._metricsCache.averageChildSize||this._itemSize[this._sizeDim]}_estimatePosition(i){const t=this._metricsCache;if(-1===this._first||-1===this._last)return t.averageMarginSize+i*(t.averageMarginSize+this._getAverageSize());if(i<this._first){const e=this._first-i;return this._getPhysicalItem(this._first).pos-(t.getMarginSize(this._first-1)||t.averageMarginSize)-(e*t.averageChildSize+(e-1)*t.averageMarginSize)}{const e=i-this._last;return this._getPhysicalItem(this._last).pos+(t.getChildSize(this._last)||t.averageChildSize)+(t.getMarginSize(this._last)||t.averageMarginSize)+e*(t.averageChildSize+t.averageMarginSize)}}_getPosition(i){const t=this._getPhysicalItem(i),{averageMarginSize:e}=this._metricsCache;return 0===i?this._metricsCache.getMarginSize(0)??e:t?t.pos:this._estimatePosition(i)}_calculateAnchor(i,t){return i<=0?0:t>this._scrollSize-this._viewDim1?this.items.length-1:Math.max(0,Math.min(this.items.length-1,Math.floor((i+t)/2/this._delta)))}_getAnchor(i,t){if(0===this._physicalItems.size)return this._calculateAnchor(i,t);if(this._first<0)return this._calculateAnchor(i,t);if(this._last<0)return this._calculateAnchor(i,t);const e=this._getPhysicalItem(this._first),s=this._getPhysicalItem(this._last),h=e.pos;if(s.pos+this._metricsCache.getChildSize(this._last)<i)return this._calculateAnchor(i,t);if(h>t)return this._calculateAnchor(i,t);let a=this._firstVisible-1,r=-1/0;for(;r<i;){r=this._getPhysicalItem(++a).pos+this._metricsCache.getChildSize(a)}return a}_getActiveItems(){0===this._viewDim1||0===this.items.length?this._clearItems():this._getItems()}_clearItems(){this._first=-1,this._last=-1,this._physicalMin=0,this._physicalMax=0;const i=this._newPhysicalItems;this._newPhysicalItems=this._physicalItems,this._newPhysicalItems.clear(),this._physicalItems=i,this._stable=!0}_getItems(){const i=this._newPhysicalItems;let t,e;if(this._stable=!0,null!==this.pin){const{index:i}=this.pin;this._anchorIdx=i,this._anchorPos=this._getPosition(i)}if(t=this._scrollPosition-this._overhang,e=this._scrollPosition+this._viewDim1+this._overhang,e<0||t>this._scrollSize)return void this._clearItems();null!==this._anchorIdx&&null!==this._anchorPos||(this._anchorIdx=this._getAnchor(t,e),this._anchorPos=this._getPosition(this._anchorIdx));let s=this._getSize(this._anchorIdx);void 0===s&&(this._stable=!1,s=this._getAverageSize());const h=this._metricsCache.getMarginSize(this._anchorIdx)??this._metricsCache.averageMarginSize,a=this._metricsCache.getMarginSize(this._anchorIdx+1)??this._metricsCache.averageMarginSize;0===this._anchorIdx&&(this._anchorPos=h),this._anchorIdx===this.items.length-1&&(this._anchorPos=this._scrollSize-a-s);let r=0;for(this._anchorPos+s+a<t&&(r=t-(this._anchorPos+s+a)),this._anchorPos-h>e&&(r=e-(this._anchorPos-h)),r&&(this._scrollPosition-=r,t-=r,e-=r,this._scrollError+=r),i.set(this._anchorIdx,{pos:this._anchorPos,size:s}),this._first=this._last=this._anchorIdx,this._physicalMin=this._anchorPos-h,this._physicalMax=this._anchorPos+s+a;this._physicalMin>t&&this._first>0;){let t=this._getSize(--this._first);void 0===t&&(this._stable=!1,t=this._getAverageSize());let e=this._metricsCache.getMarginSize(this._first);void 0===e&&(this._stable=!1,e=this._metricsCache.averageMarginSize),this._physicalMin-=t;const s=this._physicalMin;if(i.set(this._first,{pos:s,size:t}),this._physicalMin-=e,!1===this._stable&&!1===this._estimate)break}for(;this._physicalMax<e&&this._last<this.items.length-1;){let t=this._getSize(++this._last);void 0===t&&(this._stable=!1,t=this._getAverageSize());let e=this._metricsCache.getMarginSize(this._last);void 0===e&&(this._stable=!1,e=this._metricsCache.averageMarginSize);const s=this._physicalMax;if(i.set(this._last,{pos:s,size:t}),this._physicalMax+=t+e,!this._stable&&!this._estimate)break}const c=this._calculateError();c&&(this._physicalMin-=c,this._physicalMax-=c,this._anchorPos-=c,this._scrollPosition-=c,i.forEach((i=>i.pos-=c)),this._scrollError+=c),this._stable&&(this._newPhysicalItems=this._physicalItems,this._newPhysicalItems.clear(),this._physicalItems=i)}_calculateError(){return 0===this._first?this._physicalMin:this._physicalMin<=0?this._physicalMin-this._first*this._delta:this._last===this.items.length-1?this._physicalMax-this._scrollSize:this._physicalMax>=this._scrollSize?this._physicalMax-this._scrollSize+(this.items.length-1-this._last)*this._delta:0}_reflow(){const{_first:i,_last:t}=this;super._reflow(),(-1===this._first&&-1==this._last||this._first===i&&this._last===t)&&this._resetReflowState()}_resetReflowState(){this._anchorIdx=null,this._anchorPos=null,this._stable=!0}_updateScrollSize(){const{averageMarginSize:i}=this._metricsCache;this._scrollSize=Math.max(1,this.items.length*(i+this._getAverageSize())+i)}get _delta(){const{averageMarginSize:i}=this._metricsCache;return this._getAverageSize()+i}_getItemPosition(i){return{[this._positionDim]:this._getPosition(i),[this._secondaryPositionDim]:0,[offset(this.direction)]:-(this._metricsCache.getLeadingMarginValue(i,this.direction)??this._metricsCache.averageMarginSize)}}_getItemSize(i){return{[this._sizeDim]:this._getSize(i)||this._getAverageSize(),[this._secondarySizeDim]:this._itemSize[this._secondarySizeDim]}}_viewDim2Changed(){this._metricsCache.clear(),this._scheduleReflow()}}