diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js index 1bc81d2e4a4e320074cd0ed1e49ed7d64794262c..09c4261b3187d25d5486220db2a7035844749b7f 100644 --- a/app/assets/javascripts/lib/utils/url_utility.js +++ b/app/assets/javascripts/lib/utils/url_utility.js @@ -66,6 +66,13 @@ return results; })()).join('&'); }; + w.gl.utils.removeParams = (params) => { + const url = new URL(window.location.href); + params.forEach((param) => { + url.search = w.gl.utils.removeParamQueryString(url.search, param); + }); + return url.href; + }; w.gl.utils.getLocationHash = function(url) { var hashIndex; if (typeof url === 'undefined') { diff --git a/app/assets/javascripts/pager.js b/app/assets/javascripts/pager.js index e35cf6d295e37c4a22f4464cf8927b35dcb507fb..5f6bc902cf856acef181ae80165ba91789368c09 100644 --- a/app/assets/javascripts/pager.js +++ b/app/assets/javascripts/pager.js @@ -1,11 +1,15 @@ +require('~/lib/utils/common_utils'); +require('~/lib/utils/url_utility'); + (() => { const ENDLESS_SCROLL_BOTTOM_PX = 400; const ENDLESS_SCROLL_FIRE_DELAY_MS = 1000; const Pager = { init(limit = 0, preload = false, disable = false, callback = $.noop) { + this.url = $('.content_list').data('href') || gl.utils.removeParams(['limit', 'offset']); this.limit = limit; - this.offset = this.limit; + this.offset = parseInt(gl.utils.getParameterByName('offset'), 10) || this.limit; this.disable = disable; this.callback = callback; this.loading = $('.loading').first(); @@ -20,7 +24,7 @@ this.loading.show(); $.ajax({ type: 'GET', - url: $('.content_list').data('href') || window.location.href, + url: this.url, data: `limit=${this.limit}&offset=${this.offset}`, dataType: 'json', error: () => this.loading.hide(), diff --git a/changelogs/unreleased/28030-infinite-offset.yml b/changelogs/unreleased/28030-infinite-offset.yml new file mode 100644 index 0000000000000000000000000000000000000000..6f4082d7684f305ab08a3db1acedbae9a4bb620f --- /dev/null +++ b/changelogs/unreleased/28030-infinite-offset.yml @@ -0,0 +1,4 @@ +--- +title: allow offset query parameter for infinite list pages +merge_request: +author: diff --git a/spec/javascripts/pager_spec.js b/spec/javascripts/pager_spec.js new file mode 100644 index 0000000000000000000000000000000000000000..d966226909bc9ba1100b9bf8339adc28d24d684f --- /dev/null +++ b/spec/javascripts/pager_spec.js @@ -0,0 +1,90 @@ +/* global fixture */ + +require('~/pager'); + +describe('pager', () => { + const Pager = window.Pager; + + it('is defined on window', () => { + expect(window.Pager).toBeDefined(); + }); + + describe('init', () => { + const originalHref = window.location.href; + + beforeEach(() => { + setFixtures('
'); + spyOn($, 'ajax'); + }); + + afterEach(() => { + window.history.replaceState({}, null, originalHref); + }); + + it('should use data-href attribute from list element', () => { + const href = `${gl.TEST_HOST}/some_list.json`; + setFixtures(`
`); + Pager.init(); + expect(Pager.url).toBe(href); + }); + + it('should use current url if data-href attribute not provided', () => { + const href = `${gl.TEST_HOST}/some_list`; + spyOn(gl.utils, 'removeParams').and.returnValue(href); + Pager.init(); + expect(Pager.url).toBe(href); + }); + + it('should get initial offset from query parameter', () => { + window.history.replaceState({}, null, '?offset=100'); + Pager.init(); + expect(Pager.offset).toBe(100); + }); + + it('keeps extra query parameters from url', () => { + window.history.replaceState({}, null, '?filter=test&offset=100'); + const href = `${gl.TEST_HOST}/some_list?filter=test`; + spyOn(gl.utils, 'removeParams').and.returnValue(href); + Pager.init(); + expect(gl.utils.removeParams).toHaveBeenCalledWith(['limit', 'offset']); + expect(Pager.url).toEqual(href); + }); + }); + + describe('getOld', () => { + beforeEach(() => { + setFixtures('
'); + Pager.init(); + }); + + it('shows loader while loading next page', () => { + spyOn(Pager.loading, 'show'); + Pager.getOld(); + expect(Pager.loading.show).toHaveBeenCalled(); + }); + + it('hides loader on success', () => { + spyOn($, 'ajax').and.callFake(options => options.success({})); + spyOn(Pager.loading, 'hide'); + Pager.getOld(); + expect(Pager.loading.hide).toHaveBeenCalled(); + }); + + it('hides loader on error', () => { + spyOn($, 'ajax').and.callFake(options => options.error()); + spyOn(Pager.loading, 'hide'); + Pager.getOld(); + expect(Pager.loading.hide).toHaveBeenCalled(); + }); + + it('sends request to url with offset and limit params', () => { + spyOn($, 'ajax'); + Pager.offset = 100; + Pager.limit = 20; + Pager.getOld(); + const [{ data, url }] = $.ajax.calls.argsFor(0); + expect(data).toBe('limit=20&offset=100'); + expect(url).toBe('/some_list'); + }); + }); +});