/**
* Copyright (c) 2014, Oracle and/or its affiliates.
* All rights reserved.
*/
/**
* @export
* @class oj.PagingDataGridDataSource
* @classdesc Object representing data used by the paging component
* @param {oj.DataGridDataSource|null} dataSource
* @param {Object|null} options Array of options for the PagingControlDataSource
* @extends oj.DataGridDataSource
* @implements oj.PagingModel
* @constructor
*/
oj.PagingDataGridDataSource = function(dataSource, options)
{
// Initialize
if (!(dataSource instanceof oj.DataGridDataSource))
{
// we only support Array, oj.Collection, or ko.observableArray. To
// check for observableArray, we can't do instanceof check because it's
// a function. So we just check if it contains a subscribe function.
throw new oj.Message('Not a datagridatasource', 'Not a datagridatasource', oj.Message.SEVERITY_LEVEL['ERROR']);
}
this.dataSource = dataSource;
this._startIndex = 0;
this.Init();
};
// Subclass from oj.DataSource
oj.Object.createSubclass(oj.PagingDataGridDataSource, oj.DataGridDataSource, "oj.PagingDataGridDataSource");
/**
* Initializes the instance.
* @export
*/
oj.PagingDataGridDataSource.prototype.Init = function()
{
oj.PagingDataGridDataSource.superclass.Init.call(this);
this._registerEventListeners();
};
/**
* Register event handlers on the underlying datasource.
* @private
*/
oj.PagingDataGridDataSource.prototype._registerEventListeners = function()
{
this.dataSource.on("change", this._handleChange.bind(this));
};
/**
* Get the current page
* @return {number} The current page
* @export
*/
oj.PagingDataGridDataSource.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>
* @export
*/
oj.PagingDataGridDataSource.prototype.setPage = function(value, options)
{
options = options || {};
value = parseInt(value, 10);
try
{
oj.PagingDataGridDataSource.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)
{
resolve(null);
}, function (error)
{
// restore old page
self._page = previousPage;
self._startIndex = self._page * self._pageSize;
reject(null);
});
});
};
/**
* Calls fetch on the datasource with paging options.
* @private
*/
oj.PagingDataGridDataSource.prototype._fetchInternal = function(options)
{
this._initialized = true;
this._startIndex = options['startIndex'];
var self = this;
return new Promise(function(resolve, reject) {
self.handleEvent("change", {'operation': 'sync', 'pageSize': self._pageSize});
resolve(undefined);
});
};
/**
* Calls fetch on the datasource with paging options.
* @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 when done
* @export
* @expose
* @memberof! oj.PagingDataGridDataSource
* @instance
*/
oj.PagingDataGridDataSource.prototype.fetch = function(options)
{
this._pageSize = options['pageSize'] + options['startIndex'];
options['startIndex'] = 0;
return this._fetchInternal(options);
};
/**
* Get the current page start index
* @return {number} The current page start index
* @export
*/
oj.PagingDataGridDataSource.prototype.getStartItemIndex = function()
{
return this._startIndex;
};
/**
* Get the current page end index
* @return {number} The current page end index
* @export
*/
oj.PagingDataGridDataSource.prototype.getEndItemIndex = function()
{
return this._endIndex;
};
/**
* Get the page count
* @return {number} The total number of pages
* @export
*/
oj.PagingDataGridDataSource.prototype.getPageCount = function()
{
var totalSize = this.totalSize();
return totalSize == -1 ? -1 : Math.ceil(totalSize / this._pageSize);
};
/**
* Handle data grid change events
* @param {Object} options the options associated with the oj.DataGridDataSource event.
* @private
*/
oj.PagingDataGridDataSource.prototype._handleChange = function(options) {
var operation;
operation = options['operation'];
switch(operation)
{
case 'refresh':
this._startIndex = 0;
// pass the refresh event through to the data grid and the paging control
this.handleEvent("change", {'operation': 'sync', 'pageSize': this._pageSize});
this.handleEvent(oj.PagingTableDataSource.EventType['REFRESH'], null);
break;
case 'reset':
// the paging control will set a new startIndex and kick off a fecth here
this.handleEvent(oj.PagingTableDataSource.EventType['RESET'], null);
break;
case 'insert':
this.handleEvent(oj.PagingTableDataSource.EventType['ADD'], {'index':options['indexes']['row']});
break;
case 'delete':
this.handleEvent(oj.PagingTableDataSource.EventType['REMOVE'], null);
break;
case 'update':
options['indexes']['row'] = options['indexes']['row'] - this._startIndex >= 0 ? options['indexes']['row'] - this._startIndex : -1;
this.handleEvent("change", options);
break;
default:
this.handleEvent('change', options);
this.handleEvent(oj.PagingTableDataSource.EventType['SYNC'], null);
}
};
/**** start delegated functions ****/
/**
* Returns the total number of rows or columns. If the value return is not >= 0 then it is automatically assumed
* that the total count is unknown. In the case of paging returns the total number of rows/colums on the page.
* @param {string} axis the axis in which we inquire for the total count. Valid values are "row" and "column".
* @return {number} the total number of rows/columns.
* @export
*/
oj.PagingDataGridDataSource.prototype.getCount = function(axis)
{
return this.dataSource.getCount(axis);
};
/**
* Returns whether the total count returned in getCount function is an actual or an estimate.
* @param {string} axis the axis in which we inquire whether the total count is an estimate. Valid values are
* "row" and "column".
* @return {string} "actual" if the count returned in getCount function is the actual count, "estimate" if the
* count returned in getCount function is an estimate. The default value is "actual".
* @export
*/
oj.PagingDataGridDataSource.prototype.getCountPrecision = function(axis)
{
return this.dataSource.getCountPrecision(axis);
};
/**
* Fetch a range of headers from the data source.
* @param {Object} headerRange information about the header range, it must contain the following properties:
* axis, start, count.
* @param {string} headerRange.axis the axis of the header that are fetched. Valid values are "row" and "column".
* @param {number} headerRange.start the start index of the range in which the header data are fetched.
* @param {number} headerRange.count the size of the range in which the header data are fetched.
* @param {Object} callbacks the callbacks to be invoke when fetch headers operation is completed. The valid callback
* types are "success" and "error".
* @param {function(HeaderSet)} callbacks.success the callback to invoke when fetch headers completed successfully.
* @param {function({status: Object})} callbacks.error the callback to invoke when fetch cells failed.
* @param {Object=} callbackObjects the object in which the callback function is invoked on. This is optional.
* You can specify the callback object for each callbacks using the "success" and "error" keys.
* @export
*/
oj.PagingDataGridDataSource.prototype.fetchHeaders = function(headerRange, callbacks, callbackObjects)
{
var headerSet;
if (this._initialized == null)
{
headerSet = new oj.ArrayHeaderSet(0, 0, headerRange.axis, null);
if (callbacks != null && callbacks['success'])
{
callbacks['success'].call(callbackObjects['success'], headerSet, headerRange);
}
}
else
{
if (headerRange['axis'] === 'row')
{
headerRange['start'] += this._startIndex;
if (headerRange['start'] + headerRange['count'] > this._startIndex + this._pageSize)
{
headerRange['count'] = this._pageSize - headerRange['start'];
}
this._pendingRowHeaderCallback = {'callbacks': callbacks, 'callbackObjects': callbackObjects}
this.dataSource.fetchHeaders(headerRange, {success: this._handleRowHeaderFetchSuccess.bind(this), error: this._handleRowHeaderFetchError.bind(this)}, callbackObjects);
}
else
{
this.dataSource.fetchHeaders(headerRange, callbacks, callbackObjects);
}
}
};
/**
* Handle row headers fetch success by adjusting startIndex back to 0 and passing a PagingHeaderSet
* @param {Object} headerSet a cellSet object
* @param {Object} headerRange
* @private
*/
oj.PagingDataGridDataSource.prototype._handleRowHeaderFetchSuccess = function(headerSet, headerRange)
{
var pagingHeaderSet;
headerRange['start'] -= this._startIndex;
pagingHeaderSet = new oj.PagingHeaderSet(headerSet, this._startIndex)
this._pendingRowHeaderCallback['callbacks']['success'].call(this._pendingRowHeaderCallback['callbackObjects']['success'], pagingHeaderSet, headerRange);
this._pendingRowHeaderCallback = null;
};
/**
* Handle row header fetch error
* @param {Object} error error
* @private
*/
oj.PagingDataGridDataSource.prototype._handleRowHeaderFetchError = function(error)
{
this._pendingRowHeaderCallback['callbacks']['error'].call(this._pendingRowHeaderCallback['callbackObjects']['error'], error);
this._pendingRowHeaderCallback = null;
};
/**
* Fetch a range of cells from the data source.
* @param {Array.<Object>} cellRanges Information about the cell range. A cell range is defined by an array
* of range info for each axis, where each range contains three properties: axis, start, count.
* @param {string} cellRanges.axis the axis associated with this range where cells are fetched. Valid
* values are "row" and "column".
* @param {number} cellRanges.start the start index of the range for this axis in which the cells are fetched.
* @param {number} cellRanges.count the size of the range for this axis in which the cells are fetched.
* @param {Object} callbacks the callbacks to be invoke when fetch cells operation is completed. The valid callback
* types are "success" and "error".
* @param {function(CellSet)} callbacks.success the callback to invoke when fetch cells completed successfully.
* @param {function({status: Object})} callbacks.error the callback to invoke when fetch cells failed.
* @param {Object=} callbackObjects the object in which the callback function is invoked on. This is optional.
* You can specify the callback object for each callbacks using the "success" and "error" keys.
* @export
*/
oj.PagingDataGridDataSource.prototype.fetchCells = function(cellRanges, callbacks, callbackObjects)
{
var cellSet, i;
if (this._initialized == null)
{
cellSet = new oj.ArrayCellSet(0, 0, 0, 0, null);
if (callbacks != null && callbacks['success'])
{
callbacks['success'].call(callbackObjects['success'], cellSet, cellRanges);
}
}
else
{
for (i=0; i<cellRanges.length; i+=1)
{
if (cellRanges[i]['axis'] === 'row')
{
cellRanges[i]['start'] += this._startIndex;
if (cellRanges[i]['start'] + cellRanges[i]['count'] > this._startIndex + this._pageSize)
{
cellRanges[i]['count'] = this._pageSize - cellRanges[i]['start'];
}
}
}
this._pendingCellCallback = {'callbacks': callbacks, 'callbackObjects': callbackObjects}
this.dataSource.fetchCells(cellRanges, {success: this._handleCellsFetchSuccess.bind(this), error: this._handleCellsFetchError.bind(this)}, callbackObjects);
}
};
/**
* Handle cell fetch success by adjusting the row startIndex and passing the PagingCellSet
* @param {Object} cellSet a cellSet object
* @param {Array.<Object>} cellRanges Information about the cell range. A cell range is defined by an array
* of range info for each axis, where each range contains three properties: axis, start, count.
* @param {string} cellRanges.axis the axis associated with this range where cells are fetched. Valid
* values are "row" and "column".
* @param {number} cellRanges.start the start index of the range for this axis in which the cells are fetched.
* @private
*/
oj.PagingDataGridDataSource.prototype._handleCellsFetchSuccess = function(cellSet, cellRanges)
{
var i, pagedCellSet;
for (i=0; i<cellRanges.length; i+=1)
{
if (cellRanges[i]['axis'] === 'row')
{
cellRanges[i]['start'] -= this._startIndex;
}
}
pagedCellSet = new oj.PagingCellSet(cellSet, this._startIndex)
this._pendingCellCallback['callbacks']['success'].call(this._pendingCellCallback['callbackObjects']['success'], pagedCellSet, cellRanges);
this._pendingCellCallback = null;
// tell PC fetchEnd
this._endIndex = this._startIndex + cellSet.getCount('row') - 1;
this.handleEvent('sync', {'data': new Array(cellSet.getCount('row')), 'startIndex': this._startIndex});
};
/**
* Handle a cell fetch error
* @param {Object} error error
* @private
*/
oj.PagingDataGridDataSource.prototype._handleCellsFetchError = function(error)
{
this._pendingCellCallback['callbacks']['error'].call(this._pendingCellCallback['callbackObjects']['error'], error);
this._pendingCellCallback = null;
};
/**
* Returns the keys based on the indexes.
* @param {Object} indexes the index for each axis
* @param {Object} indexes.row the index for the row axis
* @param {Object} indexes.column the index for the column axis
* @return {Object.<Object, Object>} an object containing the keys for each axis
* @export
*/
oj.PagingDataGridDataSource.prototype.keys = function(indexes)
{
var pagedIndexes = {'column': indexes['column'], 'row': indexes['row'] + this._startIndex};
return this.dataSource.keys(pagedIndexes);
};
/**
* Returns the row and column index based on the keys.
* @param {Object} keys the key for each axis
* @param {Object} keys.row the key for the row axis
* @param {Object} keys.column the key for the column axis
* @return {Object.<number, number>} indexes an object containing the index for each axis
* @export
*/
oj.PagingDataGridDataSource.prototype.indexes = function(keys)
{
var indexes = this.dataSource.indexes(keys);
if (indexes['row'] != -1)
{
indexes['row'] -= this._startIndex;
}
return indexes;
};
/**
* Determines whether this DataGridDataSource supports certain feature.
* @param {string} feature the feature in which its capabilities is inquired. Currently the only valid feature is "sort".
* @return {string|null} the name of the feature. For sort, the valid return values are: "full", "none". Returns null if the
* feature is not recognized.
* @export
*/
oj.PagingDataGridDataSource.prototype.getCapability = function(feature)
{
return this.dataSource.getCapability(feature);
};
/**
* @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.PagingDataGridDataSource
* @instance
*/
oj.PagingDataGridDataSource.prototype.size = function()
{
var count;
if (this._initialized == null)
{
return -1;
}
count = this.dataSource.getCount('row')
if (this.dataSource.getCount('row') > this._pageSize)
{
return this._pageSize;
}
return count;
};
/**
* Performs a sort on the data source.
* @param {Object} criteria the sort criteria.
* @param {string} criteria.axis The axis in which the sort is performed, valid values are "row", "column"
* @param {Object} criteria.key The key that identifies which header to sort
* @param {string} criteria.direction the sort direction, valid values are "ascending", "descending", "none" (default)
* @param {Object} callbacks the callbacks to be invoke upon completion of the sort operation. The callback
* properties are "success" and "error".
* @param {function()} callbacks.success the callback to invoke when the sort completed successfully.
* @param {function({status: Object})} callbacks.error the callback to invoke when sort failed.
* @param {Object=} callbackObjects the object in which the callback function is invoked on. This is optional.
* You can specify the callback object for each callbacks using the "success" and "error" properties.
* @export
*/
oj.PagingDataGridDataSource.prototype.sort = function(criteria, callbacks, callbackObjects)
{
this.dataSource.sort(criteria, callbacks, callbackObjects);
};
/**
* @export
* Return the total size of data available, including server side if not local.
* @returns {number} total size of data
* @expose
* @memberof! oj.PagingDataGridDataSource
* @instance
*/
oj.PagingDataGridDataSource.prototype.totalSize = function()
{
if (this._initialized == null)
{
return -1;
}
return this.dataSource.getCount('row');
};
/**
* Move a model to a new index in the collection, if atKey is null adds to the end
* @param {Object} moveKey the key of the model that should be moved
* @param {Object} atKey the key of the model that the moved model should be inserted before or after
* @param {string} position The position of the moved row relative to the reference row.
* Valid values are: "before", "after"
* @param {function()} callbacks.success the callback to invoke when the move completed successfully.
* @param {function({status: Object})} callbacks.error the callback to invoke when move failed.
* @param {Object=} callbackObjects the object in which the callback function is invoked on. This is optional.
* You can specify the callback object for each callbacks using the "success" and "error" properties.
* @export
*/
oj.PagingDataGridDataSource.prototype.move = function(moveKey, atKey, position, callbacks, callbackObjects)
{
this.dataSource.move(moveKey, atKey, position, callbacks, callbackObjects);
};
/**** end delegated functions ****/
Source: src/main/javascript/oracle/oj/ojdatagrid/PagingDataGridDataSource.js
Oracle® JavaScript Extension Toolkit (JET)
1.1.2
E65298-01