diff options
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/pagination/table_pagination.vue')
-rw-r--r-- | app/assets/javascripts/vue_shared/components/pagination/table_pagination.vue | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/app/assets/javascripts/vue_shared/components/pagination/table_pagination.vue b/app/assets/javascripts/vue_shared/components/pagination/table_pagination.vue new file mode 100644 index 00000000000..1e2d4ffa7e3 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/pagination/table_pagination.vue @@ -0,0 +1,159 @@ +<script> +import { + PAGINATION_UI_BUTTON_LIMIT, + UI_LIMIT, + SPREAD, + PREV, + NEXT, + FIRST, + LAST, +} from '~/vue_shared/components/pagination/constants'; + +export default { + props: { + /** + This function will take the information given by the pagination component + + Here is an example `change` method: + + change(pagenum) { + gl.utils.visitUrl(`?page=${pagenum}`); + }, + */ + change: { + type: Function, + required: true, + }, + + /** + pageInfo will come from the headers of the API call + in the `.then` clause of the VueResource API call + there should be a function that contructs the pageInfo for this component + + This is an example: + + const pageInfo = headers => ({ + perPage: +headers['X-Per-Page'], + page: +headers['X-Page'], + total: +headers['X-Total'], + totalPages: +headers['X-Total-Pages'], + nextPage: +headers['X-Next-Page'], + previousPage: +headers['X-Prev-Page'], + }); + */ + pageInfo: { + type: Object, + required: true, + }, + }, + computed: { + prev() { + return this.pageInfo.previousPage; + }, + next() { + return this.pageInfo.nextPage; + }, + getItems() { + const { totalPages, nextPage, previousPage, page } = this.pageInfo; + const items = []; + + if (page > 1) { + items.push({ title: FIRST, first: true }); + } + + if (previousPage) { + items.push({ title: PREV, prev: true }); + } else { + items.push({ title: PREV, disabled: true, prev: true }); + } + + if (page > UI_LIMIT) items.push({ title: SPREAD, separator: true }); + + if (totalPages) { + const start = Math.max(page - PAGINATION_UI_BUTTON_LIMIT, 1); + const end = Math.min(page + PAGINATION_UI_BUTTON_LIMIT, totalPages); + + for (let i = start; i <= end; i += 1) { + const isActive = i === page; + items.push({ title: i, active: isActive, page: true }); + } + + if (totalPages - page > PAGINATION_UI_BUTTON_LIMIT) { + items.push({ title: SPREAD, separator: true, page: true }); + } + } + + if (nextPage) { + items.push({ title: NEXT, next: true }); + } else { + items.push({ title: NEXT, disabled: true, next: true }); + } + + if (totalPages && totalPages - page >= 1) { + items.push({ title: LAST, last: true }); + } + + return items; + }, + showPagination() { + return this.pageInfo.nextPage || this.pageInfo.previousPage; + }, + }, + methods: { + changePage(text, isDisabled) { + if (isDisabled) return; + + const { totalPages, nextPage, previousPage } = this.pageInfo; + + switch (text) { + case SPREAD: + break; + case LAST: + this.change(totalPages); + break; + case NEXT: + this.change(nextPage); + break; + case PREV: + this.change(previousPage); + break; + case FIRST: + this.change(1); + break; + default: + this.change(Number(text)); + break; + } + }, + hideOnSmallScreen(item) { + return !item.first && !item.last && !item.next && !item.prev && !item.active; + }, + }, +}; +</script> +<template> + <div v-if="showPagination" class="gl-pagination prepend-top-default"> + <ul class="pagination justify-content-center"> + <li + v-for="(item, index) in getItems" + :key="index" + :class="{ + page: item.page, + 'js-previous-button': item.prev, + 'js-next-button': item.next, + 'js-last-button': item.last, + 'js-first-button': item.first, + 'd-none d-md-block': hideOnSmallScreen(item), + separator: item.separator, + active: item.active, + disabled: item.disabled || item.separator, + }" + class="page-item" + > + <button type="button" class="page-link" @click="changePage(item.title, item.disabled)"> + {{ item.title }} + </button> + </li> + </ul> + </div> +</template> |