Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function reporters() {
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['mocha', 'chai', 'source-map-support'],
frameworks: ['mocha', 'chai', 'source-map-support', 'sinon'],
files: ['./karma.entry.ts'],
preprocessors: {
'./karma.entry.ts': ['webpack']
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"karma-mocha-reporter": "^2.0.4",
"karma-phantomjs-launcher": "^1.0.0",
"karma-source-map-support": "^1.2.0",
"karma-sinon": "^1.0.5",
"karma-webpack": "^1.7.0",
"mocha": "^2.2.5",
"object-assign": "^4.1.0",
Expand All @@ -58,6 +59,7 @@
"remap-istanbul": "^0.6.4",
"rimraf": "^2.5.4",
"sourcemap-istanbul-instrumenter-loader": "^0.2.0",
"sinon": "^1.17.6",
"tslint-eslint-rules": "^1.3.0",
"tslint-loader": "^2.1.5",
"typedoc": "^0.4.5",
Expand All @@ -79,4 +81,4 @@
"lodash.range": "^3.2.0",
"qs": "^6.1.0"
}
}
}
12 changes: 5 additions & 7 deletions src/capacitor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,15 @@ export class FluxCapacitor extends EventEmitter {
query: Query;
bridge: BrowserBridge;
results: Results;
page: Pager;
private originalQuery: string = '';

constructor(endpoint: string, config: FluxConfiguration & any = {}, mask?: string) {
super();
this.bridge = new BrowserBridge(endpoint, config.https);
if (config.headers) this.bridge.headers = config.headers;
this.query = new Query().withConfiguration(filterObject(config, ['*', '!{headers,https}']), mask);
}

get page() {
return new Pager(this);
this.page = new Pager(this);
}

search(originalQuery: string = this.originalQuery): Promise<Results> {
Expand Down Expand Up @@ -85,7 +83,7 @@ export class FluxCapacitor extends EventEmitter {

reset(query: string = this.originalQuery): Promise<string> {
this.resetRecall();
this.emit(Events.PAGE_CHANGED, { pageIndex: 0 });
this.emit(Events.PAGE_CHANGED, { pageNumber: 1 });
return this.search(query)
.then((res) => this.emit(Events.RESET, res))
.then(() => query);
Expand All @@ -94,8 +92,8 @@ export class FluxCapacitor extends EventEmitter {
resize(pageSize: number, offset?: number): Promise<number> {
this.query.withConfiguration({ pageSize });
if (offset !== undefined) {
this.query.skip(offset);
this.emit(Events.PAGE_CHANGED, { pageIndex: this.page.pageFromOffset(offset) });
this.query.skip(offset - 1);
this.emit(Events.PAGE_CHANGED, { pageNumber: this.page.currentPage });
}
return this.search()
.then(() => pageSize);
Expand Down
105 changes: 48 additions & 57 deletions src/capacitor/pager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,108 +3,99 @@ import { Events, FluxCapacitor } from './index';
import range = require('lodash.range');

export class Pager {

constructor(private flux: FluxCapacitor) { }

next(realign: boolean = false): Promise<Results> {
return realign ?
this.jump(Math.min(this.currentPage + 1, this.finalPage)) :
this.paginate(true, this.hasNext);
next(): Promise<Results> {
return this.switchPage(this.nextPage);
}

prev(realign: boolean = false): Promise<Results> {
return realign ?
this.jump(Math.max(this.currentPage - 1, 0)) :
this.paginate(false, this.hasPrevious);
prev(): Promise<Results> {
return this.switchPage(this.previousPage);
}

last(): Promise<Results> {
return this.jump(this.finalPage);
return this.switchPage(this.finalPage);
}

reset(): Promise<Results> {
return this.pageTo(0, true);
return this.switchPage(this.firstPage);
}

get currentPage(): number {
return this.pageFromOffset(this.lastStep);
return Math.ceil(this.fromResult / this.pageSize);
}

get previousPage(): number | null {
return (this.currentPage - 1 >= this.firstPage) ? this.currentPage - 1 : null;
}

jump(page: number): Promise<Results> {
const offset = this.pageSize * page;
return this.pageTo(offset, offset >= 0 && offset < this.totalRecords, `page ${page} does not exist`);
get nextPage(): number | null {
return (this.currentPage + 1 <= this.finalPage) ? this.currentPage + 1 : null;
}

get firstPage(): number {
return 1;
}

get finalPage(): number {
if (this.totalRecords > 0) {
const total = Math.floor(this.totalRecords / this.pageSize);
return this.totalRecords % this.pageSize === 0 ? Math.max(total - 1, 0) : total;
return Math.max(Math.ceil(this.totalRecords / this.pageSize), 1);
}

get fromResult(): number {
return this.flux.query.build().skip + 1 || 1;
}

get toResult(): number {
if ((this.currentPage * this.pageSize) > this.totalRecords) {
return ((this.currentPage - 1) * this.pageSize) + (this.totalRecords % this.currentPage);
} else {
return this.currentPage * this.pageSize;
}
return 0;
}

pageNumbers(limit: number = 5): number[] {
return range(0, Math.min(this.finalPage + 1, limit))
.map(this.transformPages(limit));
get totalRecords(): number {
return this.flux.results ? this.flux.results.totalRecordCount : 0;
}

pageFromOffset(offset: number): number {
return Math.floor(offset / this.pageSize);
pageExists(page: number): boolean {
return page <= this.finalPage && page >= this.firstPage;
}

get hasNext(): boolean {
return this.step(true) < this.totalRecords;
pageNumbers(limit: number = 5): number[] {
return range(1, Math.min(this.finalPage + 1, limit + 1))
.map(this.transformPages(limit));
}

get hasPrevious(): boolean {
return this.lastStep !== 0;
switchPage(page: number): Promise<Results | void> {
if (this.pageExists(page)) {
const skip = (page - 1) * this.pageSize;
this.flux.query.skip(skip);
this.flux.emit(Events.PAGE_CHANGED, { pageNumber: page });
return this.flux.search();
} else {
return Promise.reject(new Error(`page ${page} does not exist`));
}
}

private transformPages(limit: number): (value: number) => number {
const border = Math.floor(limit / 2);
const border = Math.ceil(limit / 2);
return (value: number): number => {
// account for 0-indexed pages
value++;
if (this.currentPage <= border || limit > this.finalPage) {
// pages start at beginning
return value;
} else if (this.currentPage > this.finalPage - border) {
// pages start and end in the middle
return value + this.finalPage + 1 - limit;
return value + this.finalPage - limit;
} else {
// pages end at last page
return value + this.currentPage - border;
}
};
}

private paginate(forward: boolean, predicate: boolean): Promise<Results | void> {
return this.pageTo(this.step(forward), predicate, `already on ${forward ? 'last' : 'first'} page`);
}

private pageTo(offset: number, predicate: boolean, error?: string): Promise<Results | void> {
if (predicate) {
this.flux.query.skip(offset);
this.flux.emit(Events.PAGE_CHANGED, { pageIndex: this.pageFromOffset(offset) });
return this.flux.search();
}
return Promise.reject(new Error(error));
}

private step(add: boolean): number {
const skip = this.lastStep + (add ? this.pageSize : -this.pageSize);
return skip >= 0 ? skip : 0;
}

private get lastStep(): number {
return this.flux.query.build().skip || 0;
}

private get pageSize(): number {
return this.flux.query.build().pageSize || 10;
}

private get totalRecords(): number {
return this.flux.results ? this.flux.results.totalRecordCount : -1;
}

}
36 changes: 18 additions & 18 deletions test/capacitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,13 @@ describe('FluxCapacitor', function() {
});

it('should reset paging on refinement', (done) => {
mock.post(SEARCH_URL, (req, res) => res.body('ok'));
flux.query.skip(20);
mock.post(SEARCH_URL, (req, res) => {
expect(flux.query.build().skip).to.eq(0);
done();
});

flux.refine(SELECTED_REFINEMENT)
.then(() => {
expect(flux.query.build().skip).to.eq(0);
done();
});
flux.refine(SELECTED_REFINEMENT);
});

it('should skip reset paging on refinement', (done) => {
Expand All @@ -162,18 +162,18 @@ describe('FluxCapacitor', function() {
done();
});
});
});

describe('events', () => {
it('should emit refinements_changed event on refinement', (done) => {
mock.post(SEARCH_URL, (req, res) => res.body(JSON.stringify(REFINEMENT_RESULT)));
describe('events', () => {
it('should emit refinements_changed event on refinement', (done) => {
mock.post(SEARCH_URL, (req, res) => res.body(JSON.stringify(REFINEMENT_RESULT)));

flux.on(Events.REFINEMENTS_CHANGED, (data) => {
expect(data.available).to.eq('a');
expect(data.selected).to.eq('b');
done();
});
flux.refine(SELECTED_REFINEMENT);
flux.on(Events.REFINEMENTS_CHANGED, (data) => {
expect(data.available).to.eq('a');
expect(data.selected).to.eq('b');
done();
});
flux.refine(SELECTED_REFINEMENT);
});
});

Expand Down Expand Up @@ -265,7 +265,7 @@ describe('FluxCapacitor', function() {
});

describe('resizing behaviour', () => {
it('should resize the page and keep offset', (done) => {
it('should resize the page and keep skip', (done) => {
flux.query.skip(20);
mock.post(SEARCH_URL, (req, res) => {
expect(JSON.parse(req.body()).skip).to.eq(20);
Expand All @@ -282,7 +282,7 @@ describe('FluxCapacitor', function() {
expect(JSON.parse(req.body()).pageSize).to.eq(30);
done();
});
flux.resize(30, 0);
flux.resize(30, 1);
});
});

Expand Down Expand Up @@ -377,7 +377,7 @@ describe('FluxCapacitor', function() {
.withSelectedRefinements(refinement);
mock.post(SEARCH_URL, (req, res) => {
const body = JSON.parse(req.body());
expect(body.skip).to.not.be.ok;
expect(body.skip).to.eq(0);
expect(body.sort).to.eql([{ field: 'price', order: 'Ascending' }]);
expect(body.refinements).to.eql([refinement]);
done();
Expand Down
Loading