ucbuilder
Version:
For Developing Applications with multiple form/usercontrols etc.. In Single BrowserWindow...
421 lines (416 loc) • 19 kB
text/typescript
import { ItemIndexChangeBy, listUiHandler } from "ucbuilder/global/listUI/extended/listUiHandler";
import { scrollbarHandler } from "ucbuilder/global/listUI/pager/scrollbarHandler";
import { timeoutCall } from "ucbuilder/global/timeoutCall";
import { pagerATTR, PageNavigationResult } from "ucbuilder/global/listUI/pager/enumAndMore";
import { Usercontrol } from "ucbuilder/Usercontrol";
type KeyboardNavigationCallback = (evt: KeyboardEvent, valToAddRemove: number) => void;
export class pagerLV extends listUiHandler {
constructor() {
super();
}
scroller: scrollbarHandler = new scrollbarHandler();
/*source: {
_rows: any[];
rows: any[];
_this: () => pagerLV;
update: () => void;
} = {
_rows: [],
get rows() {
return this._rows;
},
_this: () => this,
set rows(value) {
this._rows = value;
this.update();
},
update() {
this._this().Events.onSourceUpdate.fire([this._rows.length]);
}
};*/
allItemHT: NodeListOf<HTMLElement>;
pageInfo: {
extended: {
pgrLv: pagerLV;
perPageRecord: number;
length: number;
_begin: number;
_currentIndex: number;
bottomIndex: number;
topHiddenRowCount: number;
bottomHiddenRowCount: number;
lastSideTopIndex: number;
isLastSideTopIndex: boolean;
};
defaultIndex: number;
selectedRow: any;
top: number;
pagelv: pagerLV;
minBottomIndex: number;
} = {
extended: {
pgrLv: undefined,
perPageRecord: 20,
get length() { return this.pgrLv.length; },
_begin: 0,
_currentIndex: 0,
get bottomIndex() { return (this._begin + this.perPageRecord) - 1; },
get topHiddenRowCount() {
return ((this.bottomIndex - this.perPageRecord) + 1);
},
get bottomHiddenRowCount() {
return Math.max(0, (this.length - (this._begin + this.perPageRecord)));
},
get lastSideTopIndex() { return Math.max(0, this.length - this.perPageRecord); },
get isLastSideTopIndex() { return this.lastSideTopIndex == this._begin; },
},
defaultIndex: 0,
selectedRow: undefined,
top: 0,
pagelv: undefined,
get minBottomIndex() { return Math.min(this.extended.bottomIndex, this.extended.length - 1); },
};
get currentIndex(): number { return this.OPTIONS.SESSION.currentIndex; }
set currentIndex(val: number) {
this.setCurrentIndex(val);
}
setCurrentIndex = (val: number, evt: MouseEvent | KeyboardEvent = undefined, eventType: ItemIndexChangeBy = 'Other'): void => {
let oldIndex = this.currentIndex;
let changed = (val !== oldIndex);
let currentItem = this.OPTIONS.currentItem;
let options = this.OPTIONS;
let session = options.SESSION;
if (currentItem != undefined)
currentItem.setAttribute('iscurrent', '0');
let pgInfo = this.pageInfo;
let pgInfoExt = pgInfo.extended;
let bIndex = pgInfo.minBottomIndex;
if (val >= pgInfoExt._begin && val <= bIndex) {
session.currentIndex = val;
} else {
if (val < pgInfoExt._begin) {
pgInfo.top = val;
} else {
pgInfo.top = val - pgInfoExt.perPageRecord + 1;
}
session.currentIndex = val;
}
let eletof = session.currentIndex - pgInfo.top;
this.OPTIONS.currentItem = this.Records.lstVWEle.children[eletof] as HTMLElement;
currentItem = this.OPTIONS.currentItem;
if (currentItem != undefined)
currentItem.setAttribute('iscurrent', '1');
if (changed)
this.Events.currentItemIndexChange.fire([oldIndex, session.currentIndex, evt, eventType]);
};
uc: Usercontrol;
init(lstVw: HTMLElement, scrollContainer: HTMLElement, uc: Usercontrol): void {
this.pageInfo.pagelv =
this.pageInfo.extended.pgrLv = this;
super.init(lstVw, scrollContainer, uc);
this.uc = uc;
this.scroller.init(this);
this.allItemHT = lstVw.childNodes as NodeListOf<HTMLElement>;
this.Records.itemAt = (index: number) => {
return this.allItemHT[index];
};
this.initkeyEvents();
lstVw.addEventListener("mousedown", (e: MouseEvent) => {
let itm = this.Records.getItemFromChild(e.target as HTMLElement);
if (itm != null) {
this.setCurrentIndex(itm.data(pagerATTR.itemIndex), e, "Mouse");
this.Events.itemMouseDown.fire([this.currentIndex, e]);
}
});
lstVw.addEventListener("mouseup", (e: MouseEvent) => {
let itm = this.Records.getItemFromChild(e.target as HTMLElement);
if (itm != null) {
this.Events.itemMouseUp.fire([this.currentIndex, e]);
}
});
this.initNodes();
/*
let _itemSize = this.nodes.itemSize;
let s = this.itemTemplate.extended.size;
setTimeout(() => {
_itemSize.height = s.height;
_itemSize.width = s.width;
}, 1);
*/
}
initkeyEvents(): void {
}
get perPageRecord(): number { return this.pageInfo.extended.perPageRecord; }
get beginIndex(): number { return this.pageInfo.top; }
initNodes(): void {
this.nodes.prepend = (index: number, replaceNode: boolean = false): HTMLElement => {
let _records = this.Records;
let itemNode = _records.getNode(index);
itemNode.data(pagerATTR.itemIndex, index);
let allHT = this.allItemHT;
if (allHT.length == 0)
_records.lstVWEle.appendChild(itemNode);
else {
if (!replaceNode) {
_records.lstVWEle.prepend(itemNode);
} else {
allHT[index].replaceWith(itemNode);
}
}
this.Events.newItemGenerate.fire([itemNode, index]);
return itemNode;
};
this.nodes.append = (index: number, replaceNode: boolean = false): HTMLElement => {
let _records = this.Records;
let itemNode = _records.getNode(index);
itemNode.data(pagerATTR.itemIndex, index);
itemNode.setAttribute('iscurrent', '0');
let allHT = this.allItemHT;
if (allHT.length == 0)
_records.lstVWEle.appendChild(itemNode);
else {
if (!replaceNode) {
_records.lstVWEle.append(itemNode);
} else {
allHT[index].replaceWith(itemNode);
}
}
this.Events.newItemGenerate.fire([itemNode, index]);
return itemNode;
};
this.nodes.fill = (): void => {
let _records = this.pageInfo;
this.nodes.clear();
for (let index = _records.top, len = _records.minBottomIndex; index <= len; index++)
this.nodes.append(index);
};
let calledToFill = false;
this.nodes.callToFill = (): void => {
if (calledToFill) return;
calledToFill = true;
timeoutCall.start(() => {
if (this.Events.beforeOldItemRemoved.length != 0) {
let cntnr = this.Records.lstVWEle.children;
for (let index = 0; index < cntnr.length; index++) {
const element = cntnr.item(index) as HTMLElement;
this.Events.beforeOldItemRemoved.fire([element]);
element.remove();
}
}
this.nodes.fill();
calledToFill = false;
});
};
this.nodes.indexOf = (ele: HTMLElement): number => {
return ele.data(pagerATTR.itemIndex);
};
this.nodes.loopVisibleRows = (callback: (ele: HTMLElement) => boolean = (ele) => { return true; }): void => {
let _records = this.Records;
let _chldrns = _records.lstVWEle.children;
let cIndex = this.currentIndex;
for (let index = 0; index < _chldrns.length; index++) {
const element = _chldrns[index] as HTMLElement;
let itemindex = parseInt(element.data(pagerATTR.itemIndex));
element.setAttribute('isCurrent', (itemindex == cIndex) ? '1' : '0');
if (!callback(element)) return;
}
};
}
update = (index: number): HTMLElement => {
let rec = this.Records;
let ele = this.nodes.append(index, true);
this.setCurrentIndex(this.currentIndex);
return ele;
};
navigatePages = {
callNavigate: (callback: KeyboardNavigationCallback = (evt, vltr) => { }, event: KeyboardEvent, valToAddRemove?: number): void => {
this.Events.onRowNavigationChanged(callback, event, valToAddRemove);
},
pageTo: {
downSide: {
check: (): PageNavigationResult => {
let nextPageBottom = this.pageInfo.extended.bottomIndex + this.pageInfo.extended.perPageRecord;
return (nextPageBottom < this.length - 1) ?
'OUTSIDE'
:
'LAST';
},
Advance: {
outside: (): void => {
this.pageInfo.extended._begin += this.pageInfo.extended.perPageRecord;
},
last: (): void => {
if (this.pageInfo.extended.bottomIndex > this.length) {
this.pageInfo.extended._begin = 0;
this.currentIndex = this.pageInfo.defaultIndex;
} else this.pageInfo.extended._begin = this.length - this.pageInfo.extended.perPageRecord;
},
},
Go: (event: KeyboardEvent): void => {
let dwnSide = this.navigatePages.pageTo.downSide;
let cmd = dwnSide.check();
switch (cmd) {
case "OUTSIDE":
this.navigatePages.callNavigate(dwnSide.Advance.outside, event);
break;
case "LAST":
this.navigatePages.callNavigate(dwnSide.Advance.last, event);
break;
}
this.nodes.callToFill();
this.currentIndex = this.pageInfo.minBottomIndex;
}
},
upSide: {
check: (): PageNavigationResult => {
let prevPageTop = this.pageInfo.top - this.pageInfo.extended.perPageRecord;
return (prevPageTop > this.pageInfo.defaultIndex) ?
"OUTSIDE"
:
"FIRST";
},
Advance: {
outside: (): void => {
this.pageInfo.extended._begin -= this.pageInfo.extended.perPageRecord;
this.nodes.callToFill();
this.currentIndex = this.pageInfo.extended._begin;
},
first: (): void => {
this.pageInfo.extended._begin = 0;
this.OPTIONS.SESSION.currentIndex = this.pageInfo.defaultIndex;
this.nodes.callToFill();
this.currentIndex = this.pageInfo.extended._begin;
},
},
Go: (event: KeyboardEvent): void => {
let upSd = this.navigatePages.pageTo.upSide;
let cmd = upSd.check();
switch (cmd) {
case "OUTSIDE":
this.navigatePages.callNavigate(upSd.Advance.outside, event);
break;
case "FIRST":
this.navigatePages.callNavigate(upSd.Advance.first, event);
break;
}
this.nodes.render();
}
}
},
moveTo: {
prevSide: {
check: (): PageNavigationResult => {
if (this.currentIndex > this.pageInfo.top)
return "DISPLAYED";
else {
if (this.pageInfo.top > this.pageInfo.defaultIndex) {
return "OUTSIDE";
} else {
return "FIRST"
}
}
/*return (this.currentIndex > this.pageInfo.top) ?
"DISPLAYED"
:
(this.pageInfo.top > this.pageInfo.defaultIndex) ?
"OUTSIDE"
:
"FIRST";*/
},
Advance: {
dispayed: (evt: KeyboardEvent, valToCount: number = 1): void => {
this.currentIndex -= valToCount;
},
outside: (evt: KeyboardEvent, valToCount: number = 1): HTMLElement => {
let eleToRem = this.Records.lstVWEle.lastElementChild as HTMLElement;
this.Events.beforeOldItemRemoved.fire([eleToRem]);
eleToRem.remove();
this.pageInfo.extended._begin--;
let ele = this.nodes.prepend(this.pageInfo.top);
this.currentIndex--;
return ele;
},
first: (evt: KeyboardEvent, valToCount: number = 1): void => {
if (this.Events.onReachFirstRecord()) {
this.pageInfo.extended._begin = this.pageInfo.extended.lastSideTopIndex;
this.nodes.callToFill();
this.currentIndex = this.pageInfo.minBottomIndex;
}
}
},
Go: (event: KeyboardEvent, valToCount: number = 1): void => {
let prvSide = this.navigatePages.moveTo.prevSide;
let cmd = prvSide.check();
switch (cmd) {
case "DISPLAYED":
this.navigatePages.callNavigate(prvSide.Advance.dispayed, event, valToCount);
break;
case "OUTSIDE":
this.navigatePages.callNavigate(prvSide.Advance.outside, event, valToCount);
break;
case "FIRST":
this.navigatePages.callNavigate(prvSide.Advance.first, event, valToCount);
break;
}
}
},
nextSide: {
check: (valToCount: number = 1): PageNavigationResult => {
if (this.currentIndex < this.pageInfo.minBottomIndex)
return "DISPLAYED";
else {
if (this.pageInfo.extended.bottomIndex < this.length - 1)
return "OUTSIDE";
else return "LAST";
}
/*return (this.currentIndex < this.pageInfo.minBottomIndex) ?
"DISPLAYED"
:
(this.pageInfo.extended.bottomIndex < this.length - 1) ?
"OUTSIDE"
:
"LAST";*/
},
Advance: {
dispayed: (evt: KeyboardEvent, valToCount: number = 1): void => {
this.currentIndex += valToCount;
},
outside: (evt: KeyboardEvent, valToCount: number = 1): HTMLElement => {
let lastTopIndex = this.pageInfo.extended.lastSideTopIndex;
if (this.pageInfo.top < lastTopIndex) {
let eleToRem = this.Records.lstVWEle.firstElementChild as HTMLElement;
this.Events.beforeOldItemRemoved.fire([eleToRem]);
eleToRem.remove();
this.pageInfo.extended._begin++;
} else this.pageInfo.extended._begin = lastTopIndex;
let newItemEle = this.nodes.append(this.pageInfo.minBottomIndex);
this.currentIndex++;
return newItemEle;
},
last: (evt: KeyboardEvent, valToCount: number = 1): void => {
if (this.Events.onReachLastRecord()) {
this.pageInfo.extended._begin = 0;
this.currentIndex = this.pageInfo.defaultIndex;
this.nodes.callToFill();
}
}
},
Go: (event: KeyboardEvent, valToCount: number = 1): void => {
let nxtSide = this.navigatePages.moveTo.nextSide;
let cmd = nxtSide.check(valToCount);
switch (cmd) {
case "DISPLAYED":
this.navigatePages.callNavigate(nxtSide.Advance.dispayed, event, valToCount);
break;
case "OUTSIDE":
this.navigatePages.callNavigate(nxtSide.Advance.outside, event, valToCount);
break;
case "LAST":
this.navigatePages.callNavigate(nxtSide.Advance.last, event, valToCount);
break;
}
}
}
},
};
}