summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_shared/components/table_pagination.vue
blob: c44c606a8b23bd561270f2a1eef043fc867d4742 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<script>
  import { s__ } from '../../locale';

  const PAGINATION_UI_BUTTON_LIMIT = 4;
  const UI_LIMIT = 6;
  const SPREAD = '...';
  const PREV = s__('Pagination|Prev');
  const NEXT = s__('Pagination|Next');
  const FIRST = s__('Pagination|« First');
  const LAST = s__('Pagination|Last »');

  export default {
    props: {
      /**
        This function will take the information given by the pagination component
      */
      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 total = this.pageInfo.totalPages;
        const page = this.pageInfo.page;
        const items = [];

        if (page > 1) {
          items.push({ title: FIRST, first: true });
        }

        if (page > 1) {
          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 });

        const start = Math.max(page - PAGINATION_UI_BUTTON_LIMIT, 1);
        const end = Math.min(page + PAGINATION_UI_BUTTON_LIMIT, total);

        for (let i = start; i <= end; i += 1) {
          const isActive = i === page;
          items.push({ title: i, active: isActive, page: true });
        }

        if (total - page > PAGINATION_UI_BUTTON_LIMIT) {
          items.push({ title: SPREAD, separator: true, page: true });
        }

        if (page === total) {
          items.push({ title: NEXT, disabled: true, next: true });
        } else if (total - page >= 1) {
          items.push({ title: NEXT, next: true });
        }

        if (total - page >= 1) {
          items.push({ title: LAST, last: true });
        }

        return items;
      },
      showPagination() {
        return this.pageInfo.totalPages > 1;
      },
    },
    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(+text);
            break;
        }
      },
    },
  };
</script>
<template>
  <div
    v-if="showPagination"
    class="gl-pagination"
  >
    <ul class="pagination clearfix">
      <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,
          separator: item.separator,
          active: item.active,
          disabled: item.disabled
        }"
      >
        <a @click.prevent="changePage(item.title, item.disabled)">
          {{ item.title }}
        </a>
      </li>
    </ul>
  </div>
</template>