UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

965 lines (963 loc) • 49.3 kB
/** * DevExtreme (ui/grid_core/ui.grid_core.virtual_scrolling.js) * Version: 18.2.18 * Build date: Tue Oct 18 2022 * * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; var _renderer = require("../../core/renderer"); var _renderer2 = _interopRequireDefault(_renderer); var _window = require("../../core/utils/window"); var _common = require("../../core/utils/common"); var _uiGrid_core = require("./ui.grid_core.virtual_scrolling_core"); var _uiGrid_core2 = _interopRequireDefault(_uiGrid_core); var _uiGrid_core3 = require("./ui.grid_core.utils"); var _uiGrid_core4 = _interopRequireDefault(_uiGrid_core3); var _iterator = require("../../core/utils/iterator"); var _deferred = require("../../core/utils/deferred"); var _translator = require("../../animation/translator"); var _translator2 = _interopRequireDefault(_translator); var _load_indicator = require("../load_indicator"); var _load_indicator2 = _interopRequireDefault(_load_indicator); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj } } var TABLE_CLASS = "table", BOTTOM_LOAD_PANEL_CLASS = "bottom-load-panel", TABLE_CONTENT_CLASS = "table-content", GROUP_SPACE_CLASS = "group-space", CONTENT_CLASS = "content", ROW_CLASS = "dx-row", FREESPACE_CLASS = "dx-freespace-row", COLUMN_LINES_CLASS = "dx-column-lines", VIRTUAL_ROW_CLASS = "dx-virtual-row", SCROLLING_MODE_INFINITE = "infinite", SCROLLING_MODE_VIRTUAL = "virtual", SCROLLING_MODE_STANDARD = "standard", PIXELS_LIMIT = 25e4; var isVirtualMode = function(that) { return that.option("scrolling.mode") === SCROLLING_MODE_VIRTUAL }; var isAppendMode = function(that) { return that.option("scrolling.mode") === SCROLLING_MODE_INFINITE }; var isVirtualRowRendering = function(that) { var rowRenderingMode = that.option("scrolling.rowRenderingMode"); if (rowRenderingMode === SCROLLING_MODE_VIRTUAL) { return true } else { if (rowRenderingMode === SCROLLING_MODE_STANDARD) { return false } } }; var _correctCount = function(items, count, fromEnd, isItemCountableFunc) { var countCorrection = fromEnd ? 0 : 1; for (var i = 0; i < count + countCorrection; i++) { var item = items[fromEnd ? items.length - 1 - i : i]; if (item && !isItemCountableFunc(item, i === count)) { count++ } } return count }; var VirtualScrollingDataSourceAdapterExtender = function() { var _updateLoading = function(that) { var beginPageIndex = that._virtualScrollController.beginPageIndex(-1); if (isVirtualMode(that)) { if (beginPageIndex < 0 || that.viewportSize() >= 0 && that.getViewportItemIndex() >= 0 && (beginPageIndex * that.pageSize() > that.getViewportItemIndex() || beginPageIndex * that.pageSize() + that.itemsCount() < that.getViewportItemIndex() + that.viewportSize()) && that._dataSource.isLoading()) { if (!that._isLoading) { that._isLoading = true; that.loadingChanged.fire(true) } } else { if (that._isLoading) { that._isLoading = false; that.loadingChanged.fire(false) } } } }; var result = { init: function(dataSource) { var that = this; that.callBase.apply(that, arguments); that._items = []; that._isLoaded = true; that._virtualScrollController = new _uiGrid_core2.default.VirtualScrollController(that.component, { pageSize: function() { return that.pageSize() }, totalItemsCount: function() { return that.totalItemsCount() }, hasKnownLastPage: function() { return that.hasKnownLastPage() }, pageIndex: function(index) { return dataSource.pageIndex(index) }, isLoading: function() { return dataSource.isLoading() && !that.isCustomLoading() }, pageCount: function() { return that.pageCount() }, load: function() { return dataSource.load() }, updateLoading: function() { _updateLoading(that) }, itemsCount: function() { return that.itemsCount(true) }, items: function() { return dataSource.items() }, viewportItems: function(items) { if (items) { that._items = items } return that._items }, onChanged: function(e) { that.changed.fire(e) }, changingDuration: function(e) { return that._renderTime || 0 } }) }, _handleLoadingChanged: function(isLoading) { var that = this; if (!isVirtualMode(that)) { that._isLoading = isLoading; that.callBase.apply(that, arguments) } }, _handleLoadError: function() { var that = this; that._isLoading = false; that.loadingChanged.fire(false); that.callBase.apply(that, arguments) }, _handleDataChanged: function(e) { var callBase = this.callBase.bind(this); this._virtualScrollController.handleDataChanged(callBase, e) }, _customizeRemoteOperations: function(options, isReload, operationTypes) { var that = this; if (!that.option("legacyRendering") && isVirtualMode(that) && !(operationTypes.reload || isReload) && operationTypes.skip && that._renderTime < that.option("scrolling.renderingThreshold")) { options.delay = void 0 } that.callBase.apply(that, arguments) }, items: function() { return this._items }, itemsCount: function(isBase) { if (isBase) { return this.callBase() } return this._virtualScrollController.itemsCount() }, load: function(loadOptions) { if (loadOptions) { return this.callBase(loadOptions) } return this._virtualScrollController.load() }, isLoading: function() { return this._isLoading }, isLoaded: function() { return this._dataSource.isLoaded() && this._isLoaded }, resetPagesCache: function() { this._virtualScrollController.reset(); this.callBase.apply(this, arguments) }, _changeRowExpandCore: function() { var result = this.callBase.apply(this, arguments); this.resetPagesCache(); _updateLoading(this); return result }, reload: function() { this._dataSource.pageIndex(this.pageIndex()); var virtualScrollController = this._virtualScrollController; if (virtualScrollController) { var d = new _deferred.Deferred; this.callBase.apply(this, arguments).done(function(r) { var delayDeferred = virtualScrollController._delayDeferred; if (delayDeferred) { delayDeferred.done(d.resolve).fail(d.reject) } else { d.resolve(r) } }).fail(d.reject); return d } else { return this.callBase.apply(this, arguments) } }, refresh: function(options, isReload, operationTypes) { var that = this, storeLoadOptions = options.storeLoadOptions, dataSource = that._dataSource; if (isReload || operationTypes.reload) { that._virtualScrollController.reset(); dataSource.items().length = 0; that._isLoaded = false; _updateLoading(that); that._isLoaded = true; if (isAppendMode(that)) { that.pageIndex(0); dataSource.pageIndex(0); storeLoadOptions.pageIndex = 0; options.pageIndex = 0; storeLoadOptions.skip = 0 } else { dataSource.pageIndex(that.pageIndex()); if (dataSource.paginate()) { storeLoadOptions.skip = that.pageIndex() * that.pageSize() } } } return that.callBase.apply(that, arguments) }, dispose: function() { this._virtualScrollController.dispose(); this.callBase.apply(this, arguments) } }; ["virtualItemsCount", "getContentOffset", "getVirtualContentSize", "setContentSize", "setViewportPosition", "getViewportItemIndex", "setViewportItemIndex", "getItemIndexByPosition", "viewportSize", "viewportItemSize", "getItemSize", "getItemSizes", "pageIndex", "beginPageIndex", "endPageIndex", "loadIfNeed"].forEach(function(name) { result[name] = function() { var virtualScrollController = this._virtualScrollController; return virtualScrollController[name].apply(virtualScrollController, arguments) } }); return result }(); var VirtualScrollingRowsViewExtender = function() { var removeEmptyRows = function($emptyRows, className) { var rowCount, $tBodies = $emptyRows.parent("." + className); if ($tBodies.length) { $emptyRows = $tBodies } rowCount = className === FREESPACE_CLASS ? $emptyRows.length - 1 : $emptyRows.length; for (var i = 0; i < rowCount; i++) { $emptyRows.eq(i).remove() } }; return { init: function() { var that = this, dataController = that.getController("data"); that.callBase(); dataController.pageChanged.add(function() { that.scrollToPage(dataController.pageIndex()) }); if (!that.option("legacyRendering") && dataController.pageIndex() > 0) { var resizeHandler = function resizeHandler() { that.resizeCompleted.remove(resizeHandler); that.scrollToPage(dataController.pageIndex()) }; that.resizeCompleted.add(resizeHandler) } }, scrollToPage: function(pageIndex) { var scrollPosition, that = this, dataController = that._dataController, pageSize = dataController ? dataController.pageSize() : 0; if (isVirtualMode(that) || isAppendMode(that)) { var itemSize = dataController.getItemSize(), itemSizes = dataController.getItemSizes(), itemIndex = pageIndex * pageSize; scrollPosition = itemIndex * itemSize; for (var index in itemSizes) { if (index <= itemIndex) { scrollPosition += itemSizes[index] - itemSize } } } else { scrollPosition = 0 } that.scrollTo({ y: scrollPosition, x: that._scrollLeft }) }, renderDelayedTemplates: function(e) { this._updateContentPosition(true); this.callBase.apply(this, arguments) }, _renderCore: function(e) { var that = this, startRenderDate = new Date; that.callBase.apply(that, arguments); var dataSource = that._dataController._dataSource; if (dataSource && e) { var itemCount = e.items ? e.items.length : 20; var viewportSize = that._dataController.viewportSize() || 20; if (isVirtualRowRendering(that)) { dataSource._renderTime = (new Date - startRenderDate) * viewportSize / itemCount } else { dataSource._renderTime = new Date - startRenderDate } } }, _getRowElements: function(tableElement) { var $rows = this.callBase(tableElement); return $rows && $rows.not("." + VIRTUAL_ROW_CLASS) }, _renderContent: function(contentElement, tableElement) { var that = this, virtualItemsCount = that._dataController.virtualItemsCount(); if (virtualItemsCount && that.option("legacyRendering")) { if ((0, _window.hasWindow)()) { tableElement.addClass(that.addWidgetPrefix(TABLE_CONTENT_CLASS)) } if (!contentElement.children().length) { contentElement.append(tableElement) } else { contentElement.children().first().replaceWith(tableElement) } if (1 === contentElement.children("table").length) { contentElement.append(that._createTable()); that._contentHeight = 0 } return contentElement } return that.callBase.apply(that, arguments) }, _removeRowsElements: function(contentTable, removeCount, changeType) { var rowElements = this._getRowElements(contentTable).toArray(); if ("append" === changeType) { rowElements = rowElements.slice(0, removeCount) } else { rowElements = rowElements.slice(-removeCount) } var errorHandlingController = this.getController("errorHandling"); rowElements.map(function(rowElement) { var $rowElement = (0, _renderer2.default)(rowElement); errorHandlingController && errorHandlingController.removeErrorRow($rowElement.next()); $rowElement.remove() }) }, _restoreErrorRow: function(contentTable) { var editingController = this.getController("editing"); editingController && editingController.hasChanges() && this._getRowElements(contentTable).each(function(_, item) { var rowOptions = (0, _renderer2.default)(item).data("options"); if (rowOptions) { var editData = editingController.getEditDataByKey(rowOptions.key); editData && editingController._showErrorRow(editData) } }) }, _updateContent: function(tableElement, change) { var contentTable, $freeSpaceRowElements, that = this, contentElement = that._findContentElement(), changeType = change && change.changeType; if ("append" === changeType || "prepend" === changeType) { contentTable = contentElement.children().first(); var $tBodies = that._getBodies(tableElement); if (!that.option("legacyRendering") && 1 === $tBodies.length) { that._getBodies(contentTable)["append" === changeType ? "append" : "prepend"]($tBodies.children()) } else { $tBodies["append" === changeType ? "appendTo" : "prependTo"](contentTable) } tableElement.remove(); $freeSpaceRowElements = that._getFreeSpaceRowElements(contentTable); removeEmptyRows($freeSpaceRowElements, FREESPACE_CLASS); if (change.removeCount) { that._removeRowsElements(contentTable, change.removeCount, changeType) } that._restoreErrorRow(contentTable) } else { that.callBase.apply(that, arguments) } that._updateBottomLoading() }, _addVirtualRow: function($table, isFixed, location, position) { if (!position) { return } var $virtualRow = this._createEmptyRow(VIRTUAL_ROW_CLASS, isFixed, position); $virtualRow = this._wrapRowIfNeed($table, $virtualRow); this._appendEmptyRow($table, $virtualRow, location) }, _updateContentPosition: function(isRender) { var that = this, dataController = that._dataController, rowHeight = that._rowHeight || 20; dataController.viewportItemSize(rowHeight); if (!that.option("legacyRendering") && (isVirtualMode(that) || isVirtualRowRendering(that))) { if (!isRender) { var rowHeights = that._getRowElements(that._tableElement).toArray().map(function(row) { return row.getBoundingClientRect().height }); dataController.setContentSize(rowHeights) } var top = dataController.getContentOffset("begin"), bottom = dataController.getContentOffset("end"), $tables = that.getTableElements(), $virtualRows = $tables.children("tbody").children("." + VIRTUAL_ROW_CLASS); removeEmptyRows($virtualRows, VIRTUAL_ROW_CLASS); $tables.each(function(index) { var isFixed = index > 0; that._isFixedTableRendering = isFixed; that._addVirtualRow((0, _renderer2.default)(this), isFixed, "top", top); that._addVirtualRow((0, _renderer2.default)(this), isFixed, "bottom", bottom); that._isFixedTableRendering = false }); !isRender && that._updateScrollTopPosition(top) } else { (0, _common.deferUpdate)(function() { that._updateContentPositionCore() }) } }, _updateScrollTopPosition: function(top) { if (this._scrollTop < top && !this._isScrollByEvent && this._dataController.pageIndex() > 0) { this.scrollTo({ top: top, left: this._scrollLeft }) } }, _updateContentPositionCore: function() { var contentElement, contentHeight, top, $tables, $contentTable, virtualTable, isRenderVirtualTableContentRequired, that = this, rowHeight = that._rowHeight || 20, virtualItemsCount = that._dataController.virtualItemsCount(); if (virtualItemsCount) { contentElement = that._findContentElement(); $tables = contentElement.children(); $contentTable = $tables.eq(0); virtualTable = $tables.eq(1); that._contentTableHeight = $contentTable[0].offsetHeight; that._dataController.viewportItemSize(rowHeight); that._dataController.setContentSize(that._contentTableHeight); contentHeight = that._dataController.getVirtualContentSize(); top = that._dataController.getContentOffset(); (0, _common.deferRender)(function() { _translator2.default.move($contentTable, { left: 0, top: top }); isRenderVirtualTableContentRequired = that._contentHeight !== contentHeight || 0 === contentHeight || !that._isTableLinesDisplaysCorrect(virtualTable) || !that._isColumnElementsEqual($contentTable.find("col"), virtualTable.find("col")); if (isRenderVirtualTableContentRequired) { that._contentHeight = contentHeight; that._renderVirtualTableContent(virtualTable, contentHeight) } that._updateScrollTopPosition(top) }) } }, _isTableLinesDisplaysCorrect: function(table) { var hasColumnLines = table.find("." + COLUMN_LINES_CLASS).length > 0; return hasColumnLines === this.option("showColumnLines") }, _isColumnElementsEqual: function($columns, $virtualColumns) { var result = $columns.length === $virtualColumns.length; if (result) { (0, _iterator.each)($columns, function(index, element) { if (element.style.width !== $virtualColumns[index].style.width) { result = false; return result } }) } return result }, _renderVirtualTableContent: function(container, height) { var i, that = this, columns = that._columnsController.getVisibleColumns(), html = that._createColGroup(columns).prop("outerHTML"), freeSpaceCellsHtml = "", columnLinesClass = that.option("showColumnLines") ? COLUMN_LINES_CLASS : "", createFreeSpaceRowHtml = function(height) { return "<tr style='height:" + height + "px;' class='" + FREESPACE_CLASS + " " + ROW_CLASS + " " + columnLinesClass + "' >" + freeSpaceCellsHtml + "</tr>" }; for (i = 0; i < columns.length; i++) { var classes = that._getCellClasses(columns[i]), classString = classes.length ? " class='" + classes.join(" ") + "'" : ""; freeSpaceCellsHtml += "<td" + classString + "/>" } while (height > PIXELS_LIMIT) { html += createFreeSpaceRowHtml(PIXELS_LIMIT); height -= PIXELS_LIMIT } html += createFreeSpaceRowHtml(height); container.addClass(that.addWidgetPrefix(TABLE_CLASS)); container.html(html) }, _getCellClasses: function(column) { var classes = [], cssClass = column.cssClass, isExpandColumn = "expand" === column.command; cssClass && classes.push(cssClass); isExpandColumn && classes.push(this.addWidgetPrefix(GROUP_SPACE_CLASS)); return classes }, _findBottomLoadPanel: function($contentElement) { var $element = $contentElement || this.element(); var $bottomLoadPanel = $element && $element.find("." + this.addWidgetPrefix(BOTTOM_LOAD_PANEL_CLASS)); if ($bottomLoadPanel && $bottomLoadPanel.length) { return $bottomLoadPanel } }, _updateBottomLoading: function() { var that = this, scrollingMode = that.option("scrolling.mode"), virtualMode = scrollingMode === SCROLLING_MODE_VIRTUAL, appendMode = scrollingMode === SCROLLING_MODE_INFINITE, showBottomLoading = !that._dataController.hasKnownLastPage() && that._dataController.isLoaded() && (virtualMode || appendMode), $contentElement = that._findContentElement(), bottomLoadPanelElement = that._findBottomLoadPanel($contentElement); if (showBottomLoading) { if (!bottomLoadPanelElement) { (0, _renderer2.default)("<div>").addClass(that.addWidgetPrefix(BOTTOM_LOAD_PANEL_CLASS)).append(that._createComponent((0, _renderer2.default)("<div>"), _load_indicator2.default).$element()).appendTo($contentElement) } } else { if (bottomLoadPanelElement) { bottomLoadPanelElement.remove() } } }, _handleScroll: function(e) { var that = this; if (that._hasHeight && that._rowHeight) { that._dataController.setViewportPosition(e.scrollOffset.top) } that.callBase.apply(that, arguments) }, _needUpdateRowHeight: function(itemsCount) { var that = this; return that.callBase.apply(that, arguments) || itemsCount > 0 && that.option("scrolling.mode") === SCROLLING_MODE_INFINITE && that.option("scrolling.rowRenderingMode") !== SCROLLING_MODE_VIRTUAL }, _updateRowHeight: function() { var viewportHeight, that = this; that.callBase.apply(that, arguments); if (that._rowHeight) { that._updateContentPosition(); viewportHeight = that._hasHeight ? that.element().outerHeight() : (0, _renderer2.default)((0, _window.getWindow)()).outerHeight(); that._dataController.viewportSize(Math.ceil(viewportHeight / that._rowHeight)) } }, updateFreeSpaceRowHeight: function() { var result = this.callBase.apply(this, arguments); if (result) { this._updateContentPosition() } return result }, setLoading: function(isLoading, messageText) { var that = this, callBase = that.callBase, dataController = that._dataController, hasBottomLoadPanel = dataController.pageIndex() > 0 && dataController.isLoaded() && !!that._findBottomLoadPanel(); if (hasBottomLoadPanel) { isLoading = false } callBase.call(that, isLoading, messageText) }, _resizeCore: function() { var that = this, $element = that.element(); that.callBase(); if (that.component.$element() && !that._windowScroll && $element.closest((0, _window.getWindow)().document).length) { that._windowScroll = _uiGrid_core2.default.subscribeToExternalScrollers($element, function(scrollPos) { if (!that._hasHeight && that._rowHeight) { that._dataController.setViewportPosition(scrollPos) } }, that.component.$element()); that.on("disposing", function() { that._windowScroll.dispose() }) } that.loadIfNeed() }, loadIfNeed: function() { var dataController = this._dataController; if (dataController && dataController.loadIfNeed) { dataController.loadIfNeed() } }, setColumnWidths: function(widths) { var $content, scrollable = this.getScrollable(); this.callBase.apply(this, arguments); if ("virtual" === this.option("scrolling.mode")) { $content = scrollable ? scrollable.$content() : this.element(); this.callBase(widths, $content.children("." + this.addWidgetPrefix(CONTENT_CLASS)).children(":not(." + this.addWidgetPrefix(TABLE_CONTENT_CLASS) + ")")) } }, dispose: function() { clearTimeout(this._scrollTimeoutID); this.callBase() } } }(); module.exports = { defaultOptions: function() { return { scrolling: { timeout: 300, updateTimeout: 300, minTimeout: 0, renderingThreshold: 100, removeInvisiblePages: true, rowPageSize: 5, mode: "standard", preloadEnabled: false, rowRenderingMode: "standard" } } }, extenders: { dataSourceAdapter: VirtualScrollingDataSourceAdapterExtender, controllers: { data: function() { var members = { _refreshDataSource: function() { var baseResult = this.callBase.apply(this, arguments) || (new _deferred.Deferred).resolve().promise(); baseResult.done(this.initVirtualRows.bind(this)); return baseResult }, getRowPageSize: function() { var rowPageSize = this.option("scrolling.rowPageSize"), pageSize = this.pageSize(); return pageSize && pageSize < rowPageSize ? pageSize : rowPageSize }, reload: function() { var that = this, rowsScrollController = that._rowsScrollController || that._dataSource, itemIndex = rowsScrollController && rowsScrollController.getItemIndexByPosition(), result = this.callBase.apply(this, arguments); return result && result.done(function() { if (isVirtualMode(that) || isVirtualRowRendering(that)) { var rowIndexOffset = that.getRowIndexOffset(), rowIndex = Math.floor(itemIndex) - rowIndexOffset, component = that.component, scrollable = component.getScrollable && component.getScrollable(); if (scrollable && !that.option("legacyRendering")) { var rowElement = component.getRowElement(rowIndex), $rowElement = rowElement && rowElement[0] && (0, _renderer2.default)(rowElement[0]), top = $rowElement && $rowElement.position().top; if (top > 0) { top = Math.round(top + $rowElement.outerHeight() * (itemIndex % 1)); scrollable.scrollTo({ y: top }) } } } }) }, initVirtualRows: function() { var that = this, virtualRowsRendering = isVirtualRowRendering(that); if ("virtual" !== that.option("scrolling.mode") && true !== virtualRowsRendering || false === virtualRowsRendering || that.option("legacyRendering") || !that.option("scrolling.rowPageSize")) { that._visibleItems = null; that._rowsScrollController = null; return } that._rowPageIndex = Math.ceil(that.pageIndex() * that.pageSize() / that.getRowPageSize()); that._visibleItems = []; var isItemCountable = function(item) { return "data" === item.rowType || "group" === item.rowType && that._dataSource.isGroupItemCountable(item.data) }; that._rowsScrollController = new _uiGrid_core2.default.VirtualScrollController(that.component, { pageSize: function() { return that.getRowPageSize() }, totalItemsCount: function() { return isVirtualMode(that) ? that.totalItemsCount() : that._items.filter(isItemCountable).length }, hasKnownLastPage: function() { return true }, pageIndex: function(index) { if (void 0 !== index) { that._rowPageIndex = index } return that._rowPageIndex }, isLoading: function() { return that.isLoading() }, pageCount: function pageCount() { var pageCount = Math.ceil(this.totalItemsCount() / this.pageSize()); return pageCount ? pageCount : 1 }, load: function() { if (that._rowsScrollController.pageIndex() >= this.pageCount()) { that._rowPageIndex = this.pageCount() - 1; that._rowsScrollController.pageIndex(that._rowPageIndex) } if (!that._rowsScrollController._dataSource.items().length && this.totalItemsCount()) { return } that._rowsScrollController.handleDataChanged(function(change) { change = change || {}; change.changeType = change.changeType || "refresh"; change.items = change.items || that._visibleItems; that._visibleItems.forEach(function(item, index) { item.rowIndex = index }); that._fireChanged(change) }) }, updateLoading: function() {}, itemsCount: function() { return that._rowsScrollController._dataSource.items().filter(isItemCountable).length }, correctCount: function(items, count, fromEnd) { return _correctCount(items, count, fromEnd, isItemCountable) }, items: function(countableOnly) { var dataSource = that.dataSource(), virtualItemsCount = dataSource && dataSource.virtualItemsCount(), begin = virtualItemsCount ? virtualItemsCount.begin : 0, rowPageSize = that.getRowPageSize(); var skip = that._rowPageIndex * rowPageSize - begin; var take = rowPageSize; var result = that._items; if (skip < 0) { return [] } if (skip) { skip = this.correctCount(result, skip); result = result.slice(skip) } if (take) { take = this.correctCount(result, take); result = result.slice(0, take) } return countableOnly ? result.filter(isItemCountable) : result }, viewportItems: function(items) { if (items) { that._visibleItems = items } return that._visibleItems }, onChanged: function() {}, changingDuration: function(e) { var dataSource = that.dataSource(); return dataSource && dataSource._renderTime || 0 } }, true); if (that.isLoaded()) { that._rowsScrollController.load() } }, _updateItemsCore: function(change) { var _this = this; var delta = this.getRowIndexDelta(); this.callBase.apply(this, arguments); var rowsScrollController = this._rowsScrollController; if (rowsScrollController) { var visibleItems = this._visibleItems; var isRefresh = "refresh" === change.changeType || change.isLiveUpdate; if ("append" === change.changeType && change.items && !change.items.length) { return } if (isRefresh || "append" === change.changeType || "prepend" === change.changeType) { change.cancel = true; isRefresh && rowsScrollController.reset(); rowsScrollController.load() } else { if ("update" === change.changeType) { change.rowIndices.forEach(function(rowIndex, index) { var changeType = change.changeTypes[index]; var newItem = change.items[index]; if ("update" === changeType) { visibleItems[rowIndex] = newItem } else { if ("insert" === changeType) { visibleItems.splice(rowIndex, 0, newItem) } else { if ("remove" === changeType) { visibleItems.splice(rowIndex, 1) } } } }) } else { visibleItems.forEach(function(item, index) { visibleItems[index] = _this._items[index + delta] || visibleItems[index] }); change.items = visibleItems } visibleItems.forEach(function(item, index) { item.rowIndex = index }) } } }, _applyChange: function(change) { var that = this, items = change.items, changeType = change.changeType, removeCount = change.removeCount; if (removeCount) { var fromEnd = "prepend" === changeType; removeCount = _correctCount(that._items, removeCount, fromEnd, function(item, isNextAfterLast) { return "data" === item.rowType || "group" === item.rowType && (that._dataSource.isGroupItemCountable(item.data) || isNextAfterLast) }); change.removeCount = removeCount } switch (changeType) { case "prepend": that._items.unshift.apply(that._items, items); if (removeCount) { that._items.splice(-removeCount) } break; case "append": that._items.push.apply(that._items, items); if (removeCount) { that._items.splice(0, removeCount) } break; default: that.callBase(change) } }, items: function(allItems) { return allItems ? this._items : this._visibleItems || this._items }, getRowIndexDelta: function() { var visibleItems = this._visibleItems, delta = 0; if (visibleItems && visibleItems[0]) { delta = this._items.indexOf(visibleItems[0]) } return delta < 0 ? 0 : delta }, getRowIndexOffset: function() { var offset = 0, dataSource = this.dataSource(), rowsScrollController = this._rowsScrollController; if (rowsScrollController) { offset = rowsScrollController.beginPageIndex() * rowsScrollController._dataSource.pageSize() } else { if ("virtual" === this.option("scrolling.mode") && dataSource) { offset = dataSource.beginPageIndex() * dataSource.pageSize() } } return offset }, viewportSize: function() { var rowsScrollController = this._rowsScrollController; rowsScrollController && rowsScrollController.viewportSize.apply(rowsScrollController, arguments); var dataSource = this._dataSource; return dataSource && dataSource.viewportSize.apply(dataSource, arguments) }, viewportItemSize: function() { var rowsScrollController = this._rowsScrollController; rowsScrollController && rowsScrollController.viewportItemSize.apply(rowsScrollController, arguments); var dataSource = this._dataSource; return dataSource && dataSource.viewportItemSize.apply(dataSource, arguments) }, setViewportPosition: function() { var rowsScrollController = this._rowsScrollController, dataSource = this._dataSource; if (rowsScrollController) { rowsScrollController.setViewportPosition.apply(rowsScrollController, arguments).done(function() { dataSource && dataSource.setViewportItemIndex(rowsScrollController.getViewportItemIndex()) }) } else { dataSource && dataSource.setViewportPosition.apply(dataSource, arguments) } }, setContentSize: function(sizes) { var rowsScrollController = this._rowsScrollController; rowsScrollController && rowsScrollController.setContentSize(sizes); var dataSource = this._dataSource; return dataSource && dataSource.setContentSize(sizes) }, loadIfNeed: function() { var rowsScrollController = this._rowsScrollController; rowsScrollController && rowsScrollController.loadIfNeed(); var dataSource = this._dataSource; return dataSource && dataSource.loadIfNeed() }, getItemSize: function() { var rowsScrollController = this._rowsScrollController; if (rowsScrollController) { return rowsScrollController.getItemSize.apply(rowsScrollController, arguments) } var dataSource = this._dataSource; return dataSource && dataSource.getItemSize.apply(dataSource, arguments) }, getItemSizes: function() { var rowsScrollController = this._rowsScrollController; if (rowsScrollController) { return rowsScrollController.getItemSizes.apply(rowsScrollController, arguments) } var dataSource = this._dataSource; return dataSource && dataSource.getItemSizes.apply(dataSource, arguments) }, getContentOffset: function() { var rowsScrollController = this._rowsScrollController; if (rowsScrollController) { return rowsScrollController.getContentOffset.apply(rowsScrollController, arguments) } var dataSource = this._dataSource; return dataSource && dataSource.getContentOffset.apply(dataSource, arguments) }, dispose: function() { var rowsScrollController = this._rowsScrollController; rowsScrollController && rowsScrollController.dispose(); this.callBase.apply(this, arguments) } }; _uiGrid_core4.default.proxyMethod(members, "virtualItemsCount"); _uiGrid_core4.default.proxyMethod(members, "getVirtualContentSize"); _uiGrid_core4.default.proxyMethod(members, "setViewportItemIndex"); return members }(), resizing: { resize: function() { var result, that = this, callBase = that.callBase; if (!that.option("legacyRendering") && (isVirtualMode(that) || isVirtualRowRendering(that))) { clearTimeout(that._resizeTimeout); var diff = new Date - that._lastTime; var updateTimeout = that.option("scrolling.updateTimeout"); if (that._lastTime && diff < updateTimeout) { result = new _deferred.Deferred; that._resizeTimeout = setTimeout(function() { callBase.apply(that).done(result.resolve).fail(result.reject); that._lastTime = new Date }, updateTimeout); that._lastTime = new Date } else { result = callBase.apply(that); if (that._dataController.isLoaded()) { that._lastTime = new Date } } } else { result = callBase.apply(that) } return result }, dispose: function() { this.callBase.apply(this, arguments); clearTimeout(this._resizeTimeout) } } }, views: { rowsView: VirtualScrollingRowsViewExtender } } };