UNPKG

@gramio/pagination

Version:

Pagination library for telegram bots

285 lines (280 loc) 7.57 kB
'use strict'; var callbackData = require('@gramio/callback-data'); var keyboards = require('@gramio/keyboards'); function calculatePagination(count, offset, limit) { const totalPages = Math.ceil(count / limit); const currentPage = Math.floor(offset / limit) + 1; const hasNext = currentPage < totalPages; const hasPrevious = currentPage > 1; return { totalPages, currentPage, hasNext, hasPrevious }; } class Pagination { name; getData; limitValue = 10; columnsValue; itemDataIterator; onSelectCallback; getCount; pageInfoFormat; firstLastPage = false; wrapKeyboardHandler; callbackData; selectCallbackDataFunction; payloadInstance; constructor(name, funcOrCallbackData, func) { this.name = name; this.getData = funcOrCallbackData instanceof callbackData.CallbackData ? func : funcOrCallbackData; this.payloadInstance = funcOrCallbackData instanceof callbackData.CallbackData ? funcOrCallbackData : void 0; const payloadCallbackData = this.payloadInstance ?? new callbackData.CallbackData("noop"); this.callbackData = new callbackData.CallbackData(name).enum("type", ["set", "select", "set_page"]).number("offset").data("payload", payloadCallbackData, { optional: true }); } payload(payload) { this.payloadInstance = payload; return this; } wrapKeyboard(func) { this.wrapKeyboardHandler = func; return this; } limit(count) { this.limitValue = count; return this; } count(func) { this.getCount = func; return this; } item(item) { this.itemDataIterator = item; return this; } columns(count) { this.columnsValue = count; return this; } onSelect(callback) { this.onSelectCallback = callback; return this; } selectCallbackData(callback) { this.selectCallbackDataFunction = callback; return this; } withPageInfo(format) { this.pageInfoFormat = format; return this; } withFirstLastPage() { this.firstLastPage = true; return this; } async getDataWithPaginationInfo(offset, ...args) { if (!this.getCount) { const data2 = await this.getData({ offset, limit: this.limitValue + 1, payload: args[0] }); return { data: data2.slice(0, this.limitValue), pagination: { hasNext: data2.length > this.limitValue, hasPrevious: offset > 0 } }; } const [count, data] = await Promise.all([ this.getCount(), this.getData({ offset, limit: this.limitValue, payload: args[0] }) ]); return { data, pagination: calculatePagination(count, offset, this.limitValue) }; } async getKeyboardWithData(offset = 0, ...args) { const { data, pagination } = await this.getDataWithPaginationInfo( offset, ...args ); const keyboard = new keyboards.InlineKeyboard({ enableSetterKeyboardHelpers: true }).columns(this.columnsValue).add( ...data.map((x) => { const item = this.itemDataIterator?.(x); return keyboards.InlineKeyboard.text( // @ts-expect-error item?.title ?? x.title, this.selectCallbackDataFunction?.({ // @ts-expect-error id: item?.id ?? x.id, payload: args[0], offset, limit: this.limitValue }) ?? this.callbackData.pack({ type: "select", // @ts-expect-error offset: item?.id ?? x.id, payload: args[0] }) ); }) ).row().columns(void 0).addIf( this.firstLastPage && pagination.hasPrevious, keyboards.InlineKeyboard.text( "\u23EE\uFE0F", this.callbackData.pack({ type: "set_page", offset: 0, payload: args[0] }) ) ).addIf( pagination.hasPrevious, keyboards.InlineKeyboard.text( "\u2B05\uFE0F", this.callbackData.pack({ type: "set", offset: offset - this.limitValue, payload: args[0] }) ) ).addIf( "totalPages" in pagination && !!this.pageInfoFormat, keyboards.InlineKeyboard.text( // biome-ignore lint/style/noNonNullAssertion: <explanation> this.pageInfoFormat(pagination), "$noop$" ) ).addIf( pagination.hasNext, keyboards.InlineKeyboard.text( "\u27A1\uFE0F", this.callbackData.pack({ type: "set", offset: offset + this.limitValue, payload: args[0] }) ) ).addIf( this.firstLastPage && "totalPages" in pagination && pagination.hasNext, keyboards.InlineKeyboard.text( "\u23ED\uFE0F", this.callbackData.pack({ type: "set_page", offset: pagination.totalPages - 1, payload: args[0] }) ) ); return { keyboard: this.wrapKeyboardHandler?.({ keyboard, pagination, offset, limit: this.limitValue, data, payload: args[0] }) ?? keyboard, data, pagination }; } async getKeyboard(offset = 0, ...args) { const { data, pagination } = await this.getDataWithPaginationInfo( offset, ...args ); const keyboard = new keyboards.InlineKeyboard({ enableSetterKeyboardHelpers: true }).columns(this.columnsValue).add( ...data.map((x) => { const item = this.itemDataIterator?.(x); return keyboards.InlineKeyboard.text( // @ts-expect-error item?.title ?? x.title, this.selectCallbackDataFunction?.({ // @ts-expect-error id: item?.id ?? x.id, payload: args[0], offset, limit: this.limitValue }) ?? this.callbackData.pack({ type: "select", // @ts-expect-error offset: item?.id ?? x.id, payload: args[0] }) ); }) ).row().columns(void 0).addIf( this.firstLastPage && pagination.hasPrevious, keyboards.InlineKeyboard.text( "\u23EE\uFE0F", this.callbackData.pack({ type: "set_page", offset: 0, payload: args[0] }) ) ).addIf( pagination.hasPrevious, keyboards.InlineKeyboard.text( "\u2B05\uFE0F", this.callbackData.pack({ type: "set", offset: offset - this.limitValue, payload: args[0] }) ) ).addIf( "totalPages" in pagination && !!this.pageInfoFormat, keyboards.InlineKeyboard.text( // biome-ignore lint/style/noNonNullAssertion: <explanation> this.pageInfoFormat(pagination), "$noop$" ) ).addIf( pagination.hasNext, keyboards.InlineKeyboard.text( "\u27A1\uFE0F", this.callbackData.pack({ type: "set", offset: offset + this.limitValue, payload: args[0] }) ) ).addIf( this.firstLastPage && "totalPages" in pagination && pagination.hasNext, keyboards.InlineKeyboard.text( "\u23ED\uFE0F", this.callbackData.pack({ type: "set_page", offset: pagination.totalPages - 1, payload: args[0] }) ) ); return this.wrapKeyboardHandler?.({ keyboard, pagination, offset, limit: this.limitValue, data, payload: args[0] }) ?? keyboard; } } exports.Pagination = Pagination;