summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_shared/components/table_pagination.js
blob: 8943b850a72b4b6cf895a4bd05c4143dfb8559d3 (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
/* global Vue, gl */
/* eslint-disable no-param-reassign, no-plusplus */

window.Vue = require('vue');

((gl) => {
  const PAGINATION_UI_BUTTON_LIMIT = 4;
  const UI_LIMIT = 6;
  const SPREAD = '...';
  const PREV = 'Prev';
  const NEXT = 'Next';
  const FIRST = '<< First';
  const LAST = 'Last >>';

  gl.VueGlPagination = Vue.extend({
    props: {

      // TODO: Consider refactoring in light of turbolinks removal.

      /**
        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++) {
          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;
      },
    },
    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>
    `,
  });
})(window.gl || (window.gl = {}));