UNPKG

fireproof

Version:
204 lines (142 loc) 4.35 kB
/** * A helper object for paging over Firebase objects. * @constructor Fireproof.Pager * @static * @param {Fireproof} ref a Firebase ref whose children you wish to page over. * @param {Number} [initialCount] The number of objects in the first page. * @property {Boolean} hasPrevious True if there are more objects before the current page. * @property {Boolean} hasNext True if there are more objects after the current page. */ function Pager(ref, initialCount) { if (arguments.length < 1) { throw new Error('Not enough arguments to Pager'); } this._mainRef = ref.ref(); this._resetCurrentOperation(); this.hasNext = true; this.hasPrevious = false; var promise; if (initialCount) { promise = this.next(initialCount); } else { promise = Fireproof.Promise.resolve([]); } this.then = promise.then.bind(promise); } /** * Get the next page of children from the ref. * @method Fireproof.Pager#next * @param {Number} count The size of the page. * @returns {Promise} A promise that resolves with an array of the next children. */ Pager.prototype.next = function(count) { if (arguments.length === 0) { throw new Error('Not enough arguments to next'); } var self = this; var requestedCount; if (self.hasNext) { return self._currentOperation .then(function() { self._direction = 'next'; var ref = self._mainRef; if (self._page) { requestedCount = count + 1; ref = ref.orderByPriority().startAt(self._page.priority, self._page.key) .limitToFirst(count + 2); } else { requestedCount = count; ref = ref.startAt().limitToFirst(count + 1); } return ref.once('value'); }) .then(function(snap) { return self._handleResults(snap, requestedCount); }); } else { return Fireproof.Promise.resolve([]); } }; /** * Get the previous page of children from the ref. * @method Fireproof.Pager#previous * @param {Number} count The size of the page. * @returns {Promise} A promise that resolves with an array of the next children. */ Pager.prototype.previous = function(count) { if (arguments.length === 0) { throw new Error('Not enough arguments to previous'); } var self = this; if (self.hasPrevious) { return self._currentOperation .then(function() { self._direction = 'previous'; var ref = self._mainRef; if (self._page) { ref = ref.orderByPriority().endAt(self._page.priority, self._page.key) .limitToLast(count + 2); } else { throw new Error('Cannot call #previous on a Pager without calling #next first'); } return ref.once('value'); }) .then(function(snap) { return self._handleResults(snap, count+1); }); } else { return Fireproof.Promise.resolve([]); } }; Pager.prototype._handleResults = function(snap, requestedCount) { var self = this, objects = []; snap.forEach(function(child) { objects.push(child); }); // remove any dead weight from the list if (self._direction === 'next') { if (self._page) { objects = objects.slice(1, requestedCount); } else { objects = objects.slice(0, requestedCount); } } else { if (snap.numChildren() <= requestedCount) { objects = objects.slice(0, snap.numChildren() - 1); } else { objects = objects.slice(1, requestedCount); } } if (self._direction === 'next') { this.hasNext = snap.numChildren() === requestedCount+1; this.hasPrevious = true; } else { this.hasPrevious = snap.numChildren() === requestedCount+1; this.hasNext = true; } if (objects.length > 0) { // set page positions if (self._direction === 'next') { self._page = { priority: objects[objects.length-1].getPriority(), key: objects[objects.length-1].key() }; } else { self._page = { priority: objects[0].getPriority(), key: objects[0].key() }; } } self._currentOperationCount--; if (self._currentOperationCount === 0) { self._resetCurrentOperation(); } return objects; }; Pager.prototype._resetCurrentOperation = function() { this._currentOperation = Fireproof.Promise.resolve(null); this._currentOperationCount = 0; }; Fireproof.Pager = Pager;