/*jslint browser: true,devel:true*/
/**
* Implementation of PagingModel backed by an oj.Collection. CollectionPagingDataSource
* provides a window into the collection, presenting both a standard JavaScript array and Knockout observable array for consumption.
* @export
* @class oj.CollectionPagingDataSource
* @classdesc Implementation of PagingModel using an oj.Collection
* @extends oj.DataSource
* @implements oj.PagingModel
* @param {oj.Collection} collection the collection to use as source data for this paging control
* @constructor
*/
oj.CollectionPagingDataSource = function(collection)
{
this.collection = collection;
// Start at the beginning
this.current = 0;
this.Init();
// Default the page size to 10
var self = this;
this.dataWindow = [];
this._noInit = true;
try {
this._setPageSize(10);
}
finally {
this._noInit = false;
}
};
// Subclass from oj.DataSource
oj.Object.createSubclass(oj.CollectionPagingDataSource, oj.DataSource, "oj.CollectionPagingDataSource");
/**
* Initializes the instance.
* @export
*/
oj.CollectionPagingDataSource.prototype.Init = function()
{
oj.CollectionPagingDataSource.superclass.Init.call(this);
};
oj.CollectionPagingDataSource.prototype._getSize = function() {
if (!this._hasMore()) {
// Return a size representing only what's left if we'd go over the bounds
return this.totalSize() - this.current;
}
// Otherwise window size should match the page size
return this.currentPageSize;
};
oj.CollectionPagingDataSource.prototype._refreshDataWindow = function() {
// Reinit the array
this.dataWindow = new Array(this._getSize());
var self = this;
return this.collection.IterativeAt(this.current, this.current + this.dataWindow.length).then(function(array) {
// Copy from the source data
for (var i = 0; i < array.length; i++) {
self.dataWindow[i] = array[i];
}
// Update the observable array
self._refreshObservableDataWindow();
self._endIndex = self._startIndex + self.dataWindow.length - 1;
});
};
oj.CollectionPagingDataSource.prototype._refreshObservableDataWindow = function() {
if (this.observableDataWindow !== undefined) {
// Manage the observable window array
this.observableDataWindow.removeAll();
for (var i = 0; i < this.dataWindow.length; i++) {
this.observableDataWindow.push(oj.KnockoutUtils.map(this.dataWindow[i]));
}
}
};
/**
* @export
* Return the current set of data in the paging window
*
* @returns {Array} the current set of data in the paging window
*/
oj.CollectionPagingDataSource.prototype.getWindow = function() {
return this.dataWindow;
};
/**
* @export
* Get the observable array representing the current set of data in the paging window
*
* @returns {Object} an observable array representing the current data in the paging window
*/
oj.CollectionPagingDataSource.prototype.getWindowObservable = function() {
if (this.observableDataWindow === undefined) {
this.observableDataWindow = ko.observableArray();
this._refreshObservableDataWindow();
}
return this.observableDataWindow;
};
/**
* Get the current page
* @return {number} The current page
* @export
* @expose
* @memberof! oj.CollectionPagingDataSource
* @instance
*/
oj.CollectionPagingDataSource.prototype.getPage = function()
{
return this._page;
};
/**
* Set the current page
* @param {number} value The current page
* @param {Object=} options Options<p>
* pageSize: The page size.<p>
* @return {Promise} promise object triggering done when complete..
* @export
* @expose
* @memberof! oj.CollectionPagingDataSource
* @instance
*/
oj.CollectionPagingDataSource.prototype.setPage = function(value, options)
{
options = options || {};
value = parseInt(value, 10);
try
{
oj.CollectionPagingDataSource.superclass.handleEvent.call(this, oj.PagingModel.EventType['BEFOREPAGE'], {'page' : value, 'previousPage' : this._page});
}
catch (err)
{
return Promise.reject(null);
}
this.pageSize = options['pageSize'] != null ? options['pageSize'] : this.pageSize;
options['startIndex'] = value * this.pageSize;
var previousPage = this._page;
this._page = value;
this._startIndex = options['startIndex'];
var self = this;
return new Promise(function(resolve, reject)
{
self._fetchInternal(options).then(function(result)
{
oj.CollectionPagingDataSource.superclass.handleEvent.call(self, oj.PagingModel.EventType['PAGE'], {'page' : self._page, 'previousPage' : previousPage});
resolve(null);
}, function (error)
{
// restore old page
self._page = previousPage;
self._startIndex = self._page * self.pageSize;
reject(null);
});
});
};
/**
* Get the current page start index
* @return {number} The current page start index
* @export
* @expose
* @memberof! oj.CollectionPagingDataSource
* @instance
*/
oj.CollectionPagingDataSource.prototype.getStartItemIndex = function()
{
return this._startIndex;
};
/**
* Get the current page end index
* @return {number} The current page end index
* @export
* @expose
* @memberof! oj.CollectionPagingDataSource
* @instance
*/
oj.CollectionPagingDataSource.prototype.getEndItemIndex = function()
{
return this._endIndex;
};
/**
* Get the page count
* @return {number} The total number of pages
* @export
* @expose
* @memberof! oj.CollectionPagingDataSource
* @instance
*/
oj.CollectionPagingDataSource.prototype.getPageCount = function()
{
var totalSize = this.totalSize();
return totalSize == -1 ? -1 : Math.ceil(totalSize / this.pageSize);
};
/**
* Fetch the row data.
* @param {Object=} options Options to control fetch
* @param {number} options.startIndex The index at which to start fetching records.
* @param {boolean} options.silent If set, do not fire a sync event.
* @return {Promise} Promise object resolves to a compound object which contains an array of row data objects and the startIndex triggering done when complete.<p>
* The structure of the resolved compound object is:<p>
* <table>
* <tbody>
* <tr><td><b>data</b></td><td>An array of raw row data</td></tr>
* <tr><td><b>startIndex</b></td><td>The startIndex for the returned set of rows</td></tr>
* </tbody>
* </table>
* @export
* @expose
* @memberof! oj.CollectionPagingDataSource
* @instance
*/
oj.CollectionPagingDataSource.prototype.fetch = function(options)
{
var opts = options || {};
if (opts['pageSize'] !== undefined && opts['startIndex'] !== undefined)
{
if (!this._hasMore())
{
// At the limit
this._processSuccess(null);
return Promise.resolve();
}
this.currentPageSize = opts['startIndex'] + opts['pageSize'];
var self = this;
return this._refreshDataWindow().then(function()
{
self._processSuccess(null);
});
}
else
{
return this._fetchInternal(options);
}
};
oj.CollectionPagingDataSource.prototype._fetchInternal = function(options)
{
// No fetching, but set up window according to options
var opts = options || {};
if (opts['startIndex'] !== undefined) {
this.current = opts['startIndex'];
}
if (opts['pageSize'] !== undefined) {
this.pageSize = opts['pageSize'];
this.currentPageSize = opts['pageSize'];
}
var self = this;
return new Promise(function(resolve, reject)
{
// Call collection fetch, and refresh the window on success
// Allow for the fact that this collection might not be backed by a rest service
try {
self.collection.fetch({success:function() {
self._refreshDataWindow().then(function() {
self._processSuccess(opts);
resolve({'data': self.getWindow(), 'startIndex': self.current});});
}});
}
catch (e) {
self._refreshDataWindow().then(function() {
self._processSuccess(opts);
resolve({'data': self.getWindow(), 'startIndex': self.current});});
}
});
};
oj.CollectionPagingDataSource.prototype._processSuccess = function(opts) {
var options = opts || {};
if (!options['silent'])
{
this.handleEvent("sync", {'data': this.getWindow(), 'startIndex': this.current});
}
if (options['success']) {
options['success']();
}
/* else if (this.fetchCallback) {
this.fetchCallback();
}*/
};
oj.CollectionPagingDataSource.prototype.handleEvent = function(eventType, event)
{
return oj.CollectionPagingDataSource.superclass.handleEvent.call(this, eventType, event);
};
/**
* Return whether there is more data which can be fetched.
* @private
*/
oj.CollectionPagingDataSource.prototype._hasMore = function()
{
return this.current + this.currentPageSize < this.totalSize();
};
/**
* Set or change the number of models in a page
*
* @param {number} n page size
*/
oj.CollectionPagingDataSource.prototype._setPageSize = function(n)
{
this.pageSize = n;
this.currentPageSize = n;
/* if (!this._noInit) {
var self = this;
return this._refreshDataWindow().then(function() {
self._processSuccess(null)});
}*/
};
oj.CollectionPagingDataSource.prototype.setFetchCallback = function(callback) {
this.fetchCallback = callback;
};
/**
* @export
* Return the size of the data locally in the dataSource. -1 if an initial fetch has not been
* done yet.
* @returns {number} size of data
* @expose
* @memberof! oj.CollectionPagingDataSource
* @instance
*/
oj.CollectionPagingDataSource.prototype.size = function()
{
var w = this.getWindow();
return w ? w.length : 0;
};
/**
* @export
* Return the total size of data available, including server side if not local.
* @returns {number} total size of data
* @expose
* @memberof! oj.CollectionPagingDataSource
* @instance
*/
oj.CollectionPagingDataSource.prototype.totalSize = function()
{
return this.collection.length;
};
Source: src/main/javascript/oracle/oj/ojpagingcontrol-model/CollectionPagingDataSource.js
Oracle® JavaScript Extension Toolkit (JET)
1.1.2
E65298-01