devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
448 lines (442 loc) • 20.5 kB
JavaScript
/**
* DevExtreme (ui/grid_core/ui.grid_core.data_source_adapter.js)
* Version: 18.1.3
* Build date: Tue May 15 2018
*
* Copyright (c) 2012 - 2018 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
;
var Callbacks = require("../../core/utils/callbacks"),
gridCore = require("../data_grid/ui.data_grid.core"),
commonUtils = require("../../core/utils/common"),
typeUtils = require("../../core/utils/type"),
each = require("../../core/utils/iterator").each,
extend = require("../../core/utils/extend").extend,
ArrayStore = require("../../data/array_store"),
deferredUtils = require("../../core/utils/deferred"),
when = deferredUtils.when,
Deferred = deferredUtils.Deferred;
module.exports = gridCore.Controller.inherit(function() {
function cloneItems(items, groupCount) {
if (items) {
items = items.slice(0);
if (groupCount) {
for (var i = 0; i < items.length; i++) {
items[i] = extend({
key: items[i].key
}, items[i]);
items[i].items = cloneItems(items[i].items, groupCount - 1)
}
}
}
return items
}
function calculateOperationTypes(loadOptions, lastLoadOptions) {
var operationTypes = {};
if (lastLoadOptions) {
operationTypes = {
sorting: !gridCore.equalSortParameters(loadOptions.sort, lastLoadOptions.sort),
grouping: !gridCore.equalSortParameters(loadOptions.group, lastLoadOptions.group, true),
groupExpanding: !gridCore.equalSortParameters(loadOptions.group, lastLoadOptions.group),
filtering: !gridCore.equalFilterParameters(loadOptions.filter, lastLoadOptions.filter),
skip: loadOptions.skip !== lastLoadOptions.skip,
take: loadOptions.take !== lastLoadOptions.take
};
operationTypes.reload = operationTypes.sorting || operationTypes.grouping || operationTypes.filtering;
operationTypes.paging = operationTypes.skip || operationTypes.take
}
return operationTypes
}
function executeTask(action, timeout) {
if (typeUtils.isDefined(timeout)) {
commonUtils.executeAsync(action, timeout)
} else {
action()
}
}
function createEmptyPagesData() {
return {
pages: {}
}
}
function getPageDataFromCache(options) {
return options.cachedPagesData.pages[options.pageIndex]
}
function setPageDataToCache(options, data) {
var pageIndex = options.pageIndex;
if (void 0 !== pageIndex) {
options.cachedPagesData.pages[pageIndex] = data
}
}
return {
init: function(dataSource, remoteOperations) {
var that = this;
that._dataSource = dataSource;
that._remoteOperations = remoteOperations || {};
that._isLastPage = !dataSource.isLastPage();
that._hasLastPage = false;
that._currentTotalCount = 0;
that._cachedPagesData = createEmptyPagesData();
that.changed = Callbacks();
that.loadingChanged = Callbacks();
that.loadError = Callbacks();
that.customizeStoreLoadOptions = Callbacks();
that._dataChangedHandler = that._handleDataChanged.bind(that);
that._dataLoadingHandler = that._handleDataLoading.bind(that);
that._dataLoadedHandler = that._handleDataLoaded.bind(that);
that._loadingChangedHandler = that._handleLoadingChanged.bind(that);
that._loadErrorHandler = that._handleLoadError.bind(that);
dataSource.on("changed", that._dataChangedHandler);
dataSource.on("customizeStoreLoadOptions", that._dataLoadingHandler);
dataSource.on("customizeLoadResult", that._dataLoadedHandler);
dataSource.on("loadingChanged", that._loadingChangedHandler);
dataSource.on("loadError", that._loadErrorHandler);
each(dataSource, function(memberName, member) {
if (!that[memberName] && typeUtils.isFunction(member)) {
that[memberName] = function() {
return this._dataSource[memberName].apply(this._dataSource, arguments)
}
}
})
},
remoteOperations: function() {
return this._remoteOperations
},
dispose: function(isSharedDataSource) {
var that = this,
dataSource = that._dataSource;
dataSource.off("changed", that._dataChangedHandler);
dataSource.off("customizeStoreLoadOptions", that._dataLoadingHandler);
dataSource.off("customizeLoadResult", that._dataLoadedHandler);
dataSource.off("loadingChanged", that._loadingChangedHandler);
dataSource.off("loadError", that._loadErrorHandler);
if (!isSharedDataSource) {
dataSource.dispose()
}
},
refresh: function(options, isReload, operationTypes) {
var that = this,
dataSource = that._dataSource;
if (isReload || operationTypes.reload) {
that._currentTotalCount = 0;
that._isLastPage = !dataSource.paginate();
that._hasLastPage = that._isLastPage
}
},
resetCache: function() {
this._cachedStoreData = void 0;
this._cachedPagingData = void 0
},
resetPagesCache: function() {
this._cachedPagesData = createEmptyPagesData()
},
_customizeRemoteOperations: function(options, isReload, operationTypes) {
var that = this,
cachedStoreData = that._cachedStoreData,
cachedPagingData = that._cachedPagingData,
cachedPagesData = that._cachedPagesData;
if (isReload) {
cachedStoreData = void 0;
cachedPagingData = void 0;
cachedPagesData = createEmptyPagesData()
} else {
if (operationTypes.reload) {
cachedPagingData = void 0;
cachedPagesData = createEmptyPagesData()
} else {
if (operationTypes.take || operationTypes.groupExpanding) {
cachedPagesData = createEmptyPagesData()
}
}
each(operationTypes, function(operationType, value) {
if (value && options.remoteOperations[operationType]) {
cachedStoreData = void 0;
cachedPagingData = void 0
}
})
}
if (cachedPagingData) {
options.remoteOperations.paging = false
}
options.cachedStoreData = cachedStoreData;
options.cachedPagingData = cachedPagingData;
options.cachedPagesData = cachedPagesData;
if (!options.isCustomLoading) {
that._cachedStoreData = cachedStoreData;
that._cachedPagingData = cachedPagingData;
that._cachedPagesData = cachedPagesData
}
},
_handleDataLoading: function(options) {
var loadOptions, operationTypes, that = this,
dataSource = that._dataSource,
lastLoadOptions = that._lastLoadOptions;
that.customizeStoreLoadOptions.fire(options);
options.delay = this.option("loadingTimeout");
options.originalStoreLoadOptions = options.storeLoadOptions;
options.remoteOperations = extend({}, this.remoteOperations());
var isReload = !that.isLoaded() && !that._isRefreshing;
if (that.option("integrationOptions.renderedOnServer") && !that.isLoaded()) {
options.delay = void 0
}
loadOptions = extend({}, options.storeLoadOptions);
operationTypes = calculateOperationTypes(loadOptions, lastLoadOptions);
that._customizeRemoteOperations(options, isReload, operationTypes);
if (!options.isCustomLoading) {
options.pageIndex = dataSource.pageIndex();
that._lastLoadOptions = loadOptions;
that._isRefreshing = true;
when(that.refresh(options, isReload, operationTypes)).done(function() {
if (that._lastOperationId === options.operationId) {
that.load()
}
}).fail(function() {
dataSource.cancel(options.operationId)
}).always(function() {
that._isRefreshing = false
});
dataSource.cancel(that._lastOperationId);
that._lastOperationId = options.operationId;
if (that._isRefreshing) {
dataSource.cancel(that._lastOperationId)
}
}
this._handleDataLoadingCore(options)
},
_handleDataLoadingCore: function(options) {
var remoteOperations = options.remoteOperations;
options.loadOptions = {};
var cachedExtra = options.cachedPagesData.extra;
var localLoadOptionNames = {
filter: !remoteOperations.filtering,
sort: !remoteOperations.sorting,
group: !remoteOperations.grouping,
summary: !remoteOperations.summary,
skip: !remoteOperations.paging,
take: !remoteOperations.paging,
requireTotalCount: cachedExtra && "totalCount" in cachedExtra || !remoteOperations.paging
};
each(options.storeLoadOptions, function(optionName, optionValue) {
if (localLoadOptionNames[optionName]) {
options.loadOptions[optionName] = optionValue;
delete options.storeLoadOptions[optionName]
}
});
if (cachedExtra) {
options.extra = cachedExtra
}
options.data = getPageDataFromCache(options) || options.cachedStoreData
},
_handleDataLoaded: function(options) {
var loadOptions = options.loadOptions,
localPaging = options.remoteOperations && !options.remoteOperations.paging,
cachedPagesData = options.cachedPagesData,
needCache = false !== this.option("cacheEnabled") && options.storeLoadOptions,
needPageCache = needCache && !options.isCustomLoading && cachedPagesData && (!localPaging || options.storeLoadOptions.group) && !this.option("legacyRendering"),
needPagingCache = needCache && localPaging,
needStoreCache = needPagingCache && !options.isCustomLoading;
if (!loadOptions) {
this._dataSource.cancel(options.operationId);
return
}
if (localPaging) {
options.skip = loadOptions.skip;
options.take = loadOptions.take;
delete loadOptions.skip;
delete loadOptions.take
}
if (loadOptions.group) {
loadOptions.group = options.group || loadOptions.group
}
var groupCount = gridCore.normalizeSortingInfo(options.storeLoadOptions.group || loadOptions.group).length;
if (!needPageCache || !getPageDataFromCache(options)) {
if (needPagingCache && options.cachedPagingData) {
options.data = cloneItems(options.cachedPagingData, groupCount)
} else {
if (needStoreCache) {
if (!this._cachedStoreData) {
this._cachedStoreData = cloneItems(options.data, gridCore.normalizeSortingInfo(options.storeLoadOptions.group).length)
} else {
if (options.mergeStoreLoadData) {
options.data = this._cachedStoreData = this._cachedStoreData.concat(options.data)
}
}
}
new ArrayStore(options.data).load(loadOptions).done(function(data) {
options.data = data
});
if (needStoreCache) {
this._cachedPagingData = cloneItems(options.data, groupCount)
}
}
if (loadOptions.requireTotalCount && localPaging) {
options.extra = typeUtils.isPlainObject(options.extra) ? options.extra : {};
options.extra.totalCount = options.data.length
}
this._handleDataLoadedCore(options);
if (needPageCache) {
cachedPagesData.extra = cachedPagesData.extra || extend({}, options.extra);
when(options.data).done(function(data) {
setPageDataToCache(options, cloneItems(data, groupCount))
})
}
}
options.storeLoadOptions = options.originalStoreLoadOptions
},
_handleDataLoadedCore: function(options) {
if (options.remoteOperations && !options.remoteOperations.paging && Array.isArray(options.data)) {
if (void 0 !== options.skip) {
options.data = options.data.slice(options.skip)
}
if (void 0 !== options.take) {
options.data = options.data.slice(0, options.take)
}
}
},
_handleLoadingChanged: function(isLoading) {
this.loadingChanged.fire(isLoading)
},
_handleLoadError: function(error) {
this.changed.fire({
changeType: "loadError",
error: error
});
this.loadError.fire(error)
},
_handleDataChanged: function(args) {
var currentTotalCount, that = this,
dataSource = that._dataSource,
isLoading = false,
itemsCount = that.itemsCount();
that._isLastPage = !itemsCount || !that.pageSize() || itemsCount < that.pageSize();
if (that._isLastPage) {
that._hasLastPage = true
}
if (dataSource.totalCount() >= 0) {
if (dataSource.pageIndex() >= that.pageCount()) {
dataSource.pageIndex(that.pageCount() - 1);
dataSource.load();
isLoading = true
}
} else {
currentTotalCount = dataSource.pageIndex() * that.pageSize() + itemsCount;
that._currentTotalCount = Math.max(that._currentTotalCount, currentTotalCount);
if (0 === itemsCount && dataSource.pageIndex() >= that.pageCount()) {
dataSource.pageIndex(that.pageCount() - 1);
if ("infinite" !== that.option("scrolling.mode")) {
dataSource.load();
isLoading = true
}
}
}
if (!isLoading) {
this.component._optionCache = {};
this.changed.fire(args);
this.component._optionCache = void 0
}
},
_scheduleCustomLoadCallbacks: function(deferred) {
var that = this;
that._isCustomLoading = true;
deferred.always(function() {
that._isCustomLoading = false
})
},
isLastPage: function() {
return this._isLastPage
},
totalCount: function() {
return parseInt(this._currentTotalCount || this._dataSource.totalCount())
},
itemsCount: function() {
return this._dataSource.items().length
},
totalItemsCount: function() {
return this.totalCount()
},
pageSize: function() {
var dataSource = this._dataSource;
if (!arguments.length && !dataSource.paginate()) {
return 0
}
return dataSource.pageSize.apply(dataSource, arguments)
},
pageCount: function() {
var that = this,
count = that.totalItemsCount(),
pageSize = that.pageSize();
if (pageSize && count > 0) {
return Math.max(1, Math.ceil(count / pageSize))
}
return 1
},
hasKnownLastPage: function() {
return this._hasLastPage || this._dataSource.totalCount() >= 0
},
loadFromStore: function(loadOptions) {
var dataSource = this._dataSource,
d = new Deferred;
if (!dataSource) {
return
}
dataSource.store().load(loadOptions).done(function(data, extra) {
if (data && !Array.isArray(data) && Array.isArray(data.data)) {
extra = data;
data = data.data
}
d.resolve(data, extra)
}).fail(d.reject);
return d
},
isCustomLoading: function() {
return !!this._isCustomLoading
},
load: function(options) {
var store, loadResult, dataSourceLoadOptions, that = this,
dataSource = that._dataSource,
d = new Deferred;
if (options) {
store = dataSource.store();
dataSourceLoadOptions = dataSource.loadOptions();
loadResult = {
storeLoadOptions: options,
isCustomLoading: true
};
each(store._customLoadOptions() || [], function(_, optionName) {
if (!(optionName in loadResult.storeLoadOptions)) {
loadResult.storeLoadOptions[optionName] = dataSourceLoadOptions[optionName]
}
});
that._scheduleCustomLoadCallbacks(d);
dataSource._scheduleLoadCallbacks(d);
that._handleDataLoading(loadResult);
executeTask(function() {
if (!dataSource.store()) {
return d.reject("canceled")
}
when(loadResult.data || that.loadFromStore(loadResult.storeLoadOptions)).done(function(data, extra) {
loadResult.data = data;
loadResult.extra = extra || {};
that._handleDataLoaded(loadResult);
if (options.requireTotalCount && void 0 === loadResult.extra.totalCount) {
loadResult.extra.totalCount = store.totalCount(loadResult.storeLoadOptions)
}
when(loadResult.data, loadResult.extra.totalCount).done(function(data, totalCount) {
loadResult.extra.totalCount = totalCount;
d.resolve(data, loadResult.extra)
}).fail(d.reject)
}).fail(d.reject)
}, that.option("loadingTimeout"));
return d.fail(function() {
that.fireEvent("loadError", arguments)
}).promise()
} else {
return dataSource.load()
}
},
reload: function(full) {
return full ? this._dataSource.reload() : this._dataSource.load()
}
}
}());