Commit 8906bbae authored by Phil Hughes's avatar Phil Hughes

Merge branch '34810-vue-pagination' into 'master'

Prevent default click since we change the url manually

Closes #34810

See merge request !12721
parents 64701b51 b2b527a6
...@@ -46,6 +46,8 @@ export default { ...@@ -46,6 +46,8 @@ export default {
}, },
methods: { methods: {
changePage(e) { changePage(e) {
if (e.target.parentElement.classList.contains('disabled')) return;
const text = e.target.innerText; const text = e.target.innerText;
const { totalPages, nextPage, previousPage } = this.pageInfo; const { totalPages, nextPage, previousPage } = this.pageInfo;
...@@ -82,7 +84,9 @@ export default { ...@@ -82,7 +84,9 @@ export default {
const page = this.pageInfo.page; const page = this.pageInfo.page;
const items = []; const items = [];
if (page > 1) items.push({ title: FIRST }); if (page > 1) {
items.push({ title: FIRST, first: true });
}
if (page > 1) { if (page > 1) {
items.push({ title: PREV, prev: true }); items.push({ title: PREV, prev: true });
...@@ -110,7 +114,9 @@ export default { ...@@ -110,7 +114,9 @@ export default {
items.push({ title: NEXT, next: true }); items.push({ title: NEXT, next: true });
} }
if (total - page >= 1) items.push({ title: LAST, last: true }); if (total - page >= 1) {
items.push({ title: LAST, last: true });
}
return items; return items;
}, },
...@@ -124,13 +130,15 @@ export default { ...@@ -124,13 +130,15 @@ export default {
v-for="item in getItems" v-for="item in getItems"
:class="{ :class="{
page: item.page, page: item.page,
prev: item.prev, 'js-previous-button': item.prev,
next: item.next, 'js-next-button': item.next,
'js-last-button': item.last,
'js-first-button': item.first,
separator: item.separator, separator: item.separator,
active: item.active, active: item.active,
disabled: item.disabled disabled: item.disabled
}"> }">
<a @click="changePage($event)">{{item.title}}</a> <a @click.prevent="changePage($event)">{{item.title}}</a>
</li> </li>
</ul> </ul>
</div> </div>
......
---
title: Prevent disabled pagination button to be clicked
merge_request:
author:
...@@ -143,6 +143,7 @@ import '~/lib/utils/common_utils'; ...@@ -143,6 +143,7 @@ import '~/lib/utils/common_utils';
it('should return valid parameter', () => { it('should return valid parameter', () => {
const value = gl.utils.getParameterByName('scope'); const value = gl.utils.getParameterByName('scope');
expect(gl.utils.getParameterByName('p')).toEqual('2');
expect(value).toBe('all'); expect(value).toBe('all');
}); });
......
import Vue from 'vue'; import Vue from 'vue';
import paginationComp from '~/vue_shared/components/table_pagination.vue'; import paginationComp from '~/vue_shared/components/table_pagination.vue';
import '~/lib/utils/common_utils';
describe('Pagination component', () => { describe('Pagination component', () => {
let component; let component;
let PaginationComponent; let PaginationComponent;
let spy;
const changeChanges = { let mountComponet;
one: '',
};
const change = (one) => {
changeChanges.one = one;
};
beforeEach(() => { beforeEach(() => {
spy = jasmine.createSpy('spy');
PaginationComponent = Vue.extend(paginationComp); PaginationComponent = Vue.extend(paginationComp);
mountComponet = function (props) {
return new PaginationComponent({
propsData: props,
}).$mount();
};
}); });
it('should render and start at page 1', () => { describe('render', () => {
component = new PaginationComponent({ describe('prev button', () => {
propsData: { it('should be disabled and non clickable', () => {
component = mountComponet({
pageInfo: { pageInfo: {
totalPages: 10,
nextPage: 2, nextPage: 2,
previousPage: '', page: 1,
perPage: 20,
previousPage: NaN,
total: 84,
totalPages: 5,
}, },
change, change: spy,
}, });
}).$mount();
expect(component.$el.classList).toContain('gl-pagination'); expect(
component.$el.querySelector('.js-previous-button').classList.contains('disabled'),
).toEqual(true);
component.changePage({ target: { innerText: '1' } }); component.$el.querySelector('.js-previous-button a').click();
expect(changeChanges.one).toEqual(1); expect(spy).not.toHaveBeenCalled();
}); });
it('should go to the previous page', () => { it('should be enabled and clickable', () => {
component = new PaginationComponent({ component = mountComponet({
propsData: {
pageInfo: { pageInfo: {
totalPages: 10,
nextPage: 3, nextPage: 3,
page: 2,
perPage: 20,
previousPage: 1, previousPage: 1,
total: 84,
totalPages: 5,
}, },
change, change: spy,
}, });
}).$mount();
component.changePage({ target: { innerText: 'Prev' } }); component.$el.querySelector('.js-previous-button a').click();
expect(changeChanges.one).toEqual(1); expect(spy).toHaveBeenCalledWith(1);
});
}); });
it('should go to the next page', () => { describe('first button', () => {
component = new PaginationComponent({ it('should call the change callback with the first page', () => {
propsData: { component = mountComponet({
pageInfo: { pageInfo: {
totalPages: 10, nextPage: 3,
nextPage: 5, page: 2,
previousPage: 3, perPage: 20,
}, previousPage: 1,
change, total: 84,
totalPages: 5,
}, },
}).$mount(); change: spy,
});
component.changePage({ target: { innerText: 'Next' } }); const button = component.$el.querySelector('.js-first-button a');
expect(changeChanges.one).toEqual(5); expect(button.textContent.trim()).toEqual('« First');
button.click();
expect(spy).toHaveBeenCalledWith(1);
});
}); });
it('should go to the last page', () => { describe('last button', () => {
component = new PaginationComponent({ it('should call the change callback with the last page', () => {
propsData: { component = mountComponet({
pageInfo: { pageInfo: {
totalPages: 10, nextPage: 3,
nextPage: 5, page: 2,
previousPage: 3, perPage: 20,
}, previousPage: 1,
change, total: 84,
totalPages: 5,
}, },
}).$mount(); change: spy,
});
const button = component.$el.querySelector('.js-last-button a');
component.changePage({ target: { innerText: 'Last »' } }); expect(button.textContent.trim()).toEqual('Last »');
expect(changeChanges.one).toEqual(10); button.click();
expect(spy).toHaveBeenCalledWith(5);
});
}); });
it('should go to the first page', () => { describe('next button', () => {
component = new PaginationComponent({ it('should be disabled and non clickable', () => {
propsData: { component = mountComponet({
pageInfo: { pageInfo: {
totalPages: 10,
nextPage: 5, nextPage: 5,
previousPage: 3, page: 5,
}, perPage: 20,
change, previousPage: 1,
total: 84,
totalPages: 5,
}, },
}).$mount(); change: spy,
});
expect(
component.$el.querySelector('.js-next-button').textContent.trim(),
).toEqual('Next');
component.changePage({ target: { innerText: '« First' } }); component.$el.querySelector('.js-next-button a').click();
expect(changeChanges.one).toEqual(1); expect(spy).not.toHaveBeenCalled();
}); });
it('should do nothing', () => { it('should be enabled and clickable', () => {
component = new PaginationComponent({ component = mountComponet({
propsData: {
pageInfo: { pageInfo: {
totalPages: 10, nextPage: 4,
nextPage: 2, page: 3,
previousPage: '', perPage: 20,
}, previousPage: 2,
change, total: 84,
totalPages: 5,
}, },
}).$mount(); change: spy,
});
component.changePage({ target: { innerText: '...' } }); component.$el.querySelector('.js-next-button a').click();
expect(changeChanges.one).toEqual(1); expect(spy).toHaveBeenCalledWith(4);
}); });
});
describe('paramHelper', () => {
afterEach(() => {
window.history.pushState({}, null, '');
}); });
it('can parse url parameters correctly', () => { describe('numbered buttons', () => {
window.history.pushState({}, null, '?scope=all&p=2'); it('should render 5 pages', () => {
component = mountComponet({
const scope = gl.utils.getParameterByName('scope'); pageInfo: {
const p = gl.utils.getParameterByName('p'); nextPage: 4,
page: 3,
expect(scope).toEqual('all'); perPage: 20,
expect(p).toEqual('2'); previousPage: 2,
total: 84,
totalPages: 5,
},
change: spy,
}); });
it('returns null if param not in url', () => { expect(component.$el.querySelectorAll('.page').length).toEqual(5);
window.history.pushState({}, null, '?p=2'); });
});
const scope = gl.utils.getParameterByName('scope'); it('should render the spread operator', () => {
const p = gl.utils.getParameterByName('p'); component = mountComponet({
pageInfo: {
nextPage: 4,
page: 3,
perPage: 20,
previousPage: 2,
total: 84,
totalPages: 10,
},
change: spy,
});
expect(scope).toEqual(null); expect(component.$el.querySelector('.separator').textContent.trim()).toEqual('...');
expect(p).toEqual('2'); });
}); });
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment