summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_shared/components/table_pagination.vue
blob: 5e7df22dd83a789ccc8743bd49ca8b2b75c33df3 (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
<script>
const PAGINATION_UI_BUTTON_LIMIT = 4;
const UI_LIMIT = 6;
const SPREAD = '...';
const PREV = 'Prev';
const NEXT = 'Next';
const FIRST = '« First';
const LAST = 'Last »';

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,
    },
  },
  methods: {
    changePage(e) {
      const text = e.target.innerText;
      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;
      }
    },
  },
  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 });

      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;
    },
  },
};
</script>
<template>
  <div class="gl-pagination">
    <ul class="pagination clearfix">
      <li
        v-for="item in getItems"
        :class="{
          page: item.page,
          prev: item.prev,
          next: item.next,
          separator: item.separator,
          active: item.active,
          disabled: item.disabled
        }">
        <a @click="changePage($event)">{{item.title}}</a>
      </li>
    </ul>
  </div>
</template>