devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
678 lines (676 loc) • 30 kB
JavaScript
/**
* DevExtreme (ui/grid_core/ui.grid_core.grid_view.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 _uiGrid_core = require("./ui.grid_core.modules");
var _uiGrid_core2 = _interopRequireDefault(_uiGrid_core);
var _common = require("../../core/utils/common");
var _common2 = _interopRequireDefault(_common);
var _window = require("../../core/utils/window");
var _window2 = _interopRequireDefault(_window);
var _iterator = require("../../core/utils/iterator");
var _type = require("../../core/utils/type");
var _type2 = _interopRequireDefault(_type);
var _uiGrid_core3 = require("./ui.grid_core.utils");
var _uiGrid_core4 = _interopRequireDefault(_uiGrid_core3);
var _message = require("../../localization/message");
var _message2 = _interopRequireDefault(_message);
var _deferred = require("../../core/utils/deferred");
var _dom_adapter = require("../../core/dom_adapter");
var _dom_adapter2 = _interopRequireDefault(_dom_adapter);
var _browser = require("../../core/utils/browser");
var _browser2 = _interopRequireDefault(_browser);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
"default": obj
}
}
var TABLE_CLASS = "table",
BORDERS_CLASS = "borders",
TABLE_FIXED_CLASS = "table-fixed",
IMPORTANT_MARGIN_CLASS = "important-margin",
TEXT_CONTENT_CLASS = "text-content",
HIDDEN_CLASS = "dx-hidden",
GRIDBASE_CONTAINER_CLASS = "dx-gridbase-container",
HIDDEN_COLUMNS_WIDTH = "adaptiveHidden",
EDITORS_INPUT_SELECTOR = "input:not([type='hidden'])",
VIEW_NAMES = ["columnsSeparatorView", "blockSeparatorView", "trackerView", "headerPanel", "columnHeadersView", "rowsView", "footerView", "columnChooserView", "filterPanelView", "pagerView", "draggingHeaderView", "contextMenuView", "errorView", "headerFilterView", "filterBuilderView"];
var isPercentWidth = function(width) {
return _type2.default.isString(width) && "%" === width.slice(-1)
};
var mergeArraysByMaxValue = function(values1, values2) {
var i, result = [];
if (values1 && values2 && values1.length && values1.length === values2.length) {
for (i = 0; i < values1.length; i++) {
result.push(values1[i] > values2[i] ? values1[i] : values2[i])
}
} else {
if (values1 && values1.length) {
result = values1
} else {
if (values2) {
result = values2
}
}
}
return result
};
var getContainerHeight = function($container) {
var clientHeight = $container.get(0).clientHeight,
paddingTop = parseFloat($container.css("paddingTop")),
paddingBottom = parseFloat($container.css("paddingBottom"));
return clientHeight - paddingTop - paddingBottom
};
var calculateFreeWidth = function(that, widths) {
var contentWidth = that._rowsView.contentWidth(),
totalWidth = that._getTotalWidth(widths, contentWidth);
return contentWidth - totalWidth
};
var calculateFreeWidthWithCurrentMinWidth = function(that, columnIndex, currentMinWidth, widths) {
return calculateFreeWidth(that, widths.map(function(width, index) {
return index === columnIndex ? currentMinWidth : width
}))
};
var restoreFocus = function(focusedElement, selectionRange) {
focusedElement.focus();
_uiGrid_core4.default.setSelectionRange(focusedElement, selectionRange)
};
var ResizingController = _uiGrid_core2.default.ViewController.inherit({
_initPostRenderHandlers: function() {
var that = this,
dataController = that._dataController;
if (!that._refreshSizesHandler) {
that._refreshSizesHandler = function(e) {
dataController.changed.remove(that._refreshSizesHandler);
var resizeDeferred, changeType = e && e.changeType,
isDelayed = e && e.isDelayed,
items = dataController.items();
if (!e || "refresh" === changeType || "prepend" === changeType || "append" === changeType) {
if (!isDelayed) {
resizeDeferred = that.resize()
}
} else {
if ("update" === changeType && e.changeTypes) {
if ((items.length > 1 || "insert" !== e.changeTypes[0]) && !(0 === items.length && "remove" === e.changeTypes[0]) && !e.needUpdateDimensions) {
that._rowsView.resize()
} else {
resizeDeferred = that.resize()
}
}
}
if (changeType && "updateSelection" !== changeType && "updateFocusedRow" !== changeType && !isDelayed) {
(0, _deferred.when)(resizeDeferred).done(function() {
that._setAriaRowColCount();
that.component._fireContentReadyAction()
})
}
};
that._dataController.changed.add(function() {
that._dataController.changed.add(that._refreshSizesHandler)
})
}
},
_setAriaRowColCount: function() {
var component = this.component;
component.setAria({
rowCount: this._dataController.totalItemsCount(),
colCount: component.columnCount()
}, component.$element().children("." + GRIDBASE_CONTAINER_CLASS))
},
_getBestFitWidths: function() {
if (!this.option("legacyRendering")) {
return this._rowsView.getColumnWidths()
}
var rowsColumnWidths, headerColumnWidths, footerColumnWidths, resultWidths, that = this;
rowsColumnWidths = that._rowsView.getColumnWidths();
headerColumnWidths = that._columnHeadersView && that._columnHeadersView.getColumnWidths();
footerColumnWidths = that._footerView && that._footerView.getColumnWidths();
resultWidths = mergeArraysByMaxValue(rowsColumnWidths, headerColumnWidths);
resultWidths = mergeArraysByMaxValue(resultWidths, footerColumnWidths);
return resultWidths
},
_setVisibleWidths: function(visibleColumns, widths) {
var columnsController = this._columnsController;
columnsController.beginUpdate();
(0, _iterator.each)(visibleColumns, function(index, column) {
var columnId = columnsController.getColumnId(column);
columnsController.columnOption(columnId, "visibleWidth", widths[index])
});
columnsController.endUpdate()
},
_toggleBestFitModeForView: function(view, className, isBestFit) {
if (!view || !view.isVisible()) {
return
}
var $tableBody, $rowsTable = this._rowsView._getTableElement(),
$viewTable = view._getTableElement();
if ($viewTable) {
if (isBestFit) {
$tableBody = $viewTable.children("tbody").appendTo($rowsTable)
} else {
$tableBody = $rowsTable.children("." + className).appendTo($viewTable)
}
$tableBody.toggleClass(className, isBestFit);
$tableBody.toggleClass(this.addWidgetPrefix("best-fit"), isBestFit)
}
},
_toggleBestFitMode: function(isBestFit) {
var $element = this.component.$element(),
that = this;
if (!that.option("legacyRendering")) {
var $rowsTable = that._rowsView._getTableElement(),
$rowsFixedTable = that._rowsView.getTableElements().eq(1);
$rowsTable.css("tableLayout", isBestFit ? "auto" : "fixed");
$rowsTable.children("colgroup").css("display", isBestFit ? "none" : "");
$rowsFixedTable.toggleClass(this.addWidgetPrefix(TABLE_FIXED_CLASS), !isBestFit);
that._toggleBestFitModeForView(that._columnHeadersView, "dx-header", isBestFit);
that._toggleBestFitModeForView(that._footerView, "dx-footer", isBestFit);
if (that._needStretch()) {
$rowsTable.get(0).style.width = isBestFit ? "auto" : ""
}
if (_browser2.default.msie && 11 === parseInt(_browser2.default.version)) {
$rowsTable.find("." + this.addWidgetPrefix(TABLE_FIXED_CLASS)).each(function() {
this.style.width = isBestFit ? "10px" : ""
})
}
} else {
$element.find("." + this.addWidgetPrefix(TABLE_CLASS)).toggleClass(this.addWidgetPrefix(TABLE_FIXED_CLASS), !isBestFit);
$element.find(EDITORS_INPUT_SELECTOR).toggleClass(HIDDEN_CLASS, isBestFit);
$element.find(".dx-group-cell").toggleClass(HIDDEN_CLASS, isBestFit);
$element.find(".dx-header-row ." + this.addWidgetPrefix(TEXT_CONTENT_CLASS)).css("maxWidth", "")
}
},
_synchronizeColumns: function() {
var resetBestFitMode, focusedElement, isFocusOutsideWindow, selectionRange, that = this,
columnsController = that._columnsController,
visibleColumns = columnsController.getVisibleColumns(),
columnAutoWidth = that.option("columnAutoWidth"),
legacyRendering = that.option("legacyRendering"),
needBestFit = that._needBestFit(),
hasMinWidth = false,
isColumnWidthsCorrected = false,
resultWidths = [],
normalizeWidthsByExpandColumns = function() {
var expandColumnWidth;
(0, _iterator.each)(visibleColumns, function(index, column) {
if ("groupExpand" === column.type) {
expandColumnWidth = resultWidths[index]
}
});
(0, _iterator.each)(visibleColumns, function(index, column) {
if ("groupExpand" === column.type && expandColumnWidth) {
resultWidths[index] = expandColumnWidth
}
})
};
!needBestFit && (0, _iterator.each)(visibleColumns, function(index, column) {
if ("auto" === column.width || legacyRendering && column.fixed) {
needBestFit = true;
return false
}
});
(0, _iterator.each)(visibleColumns, function(index, column) {
if (column.minWidth) {
hasMinWidth = true;
return false
}
});
that._setVisibleWidths(visibleColumns, []);
if (needBestFit) {
focusedElement = _dom_adapter2.default.getActiveElement();
selectionRange = _uiGrid_core4.default.getSelectionRange(focusedElement);
that._toggleBestFitMode(true);
resetBestFitMode = true
}
_common2.default.deferUpdate(function() {
if (needBestFit) {
resultWidths = that._getBestFitWidths();
(0, _iterator.each)(visibleColumns, function(index, column) {
var columnId = columnsController.getColumnId(column);
columnsController.columnOption(columnId, "bestFitWidth", resultWidths[index], true)
})
} else {
if (hasMinWidth) {
resultWidths = that._getBestFitWidths()
}
}(0, _iterator.each)(visibleColumns, function(index) {
var width = this.width;
if ("auto" !== width) {
if (_type2.default.isDefined(width)) {
resultWidths[index] = _type2.default.isNumeric(width) ? parseFloat(width) : width
} else {
if (!columnAutoWidth) {
resultWidths[index] = void 0
}
}
}
});
if (resetBestFitMode) {
that._toggleBestFitMode(false);
resetBestFitMode = false;
if (focusedElement && focusedElement !== _dom_adapter2.default.getActiveElement()) {
isFocusOutsideWindow = focusedElement.getBoundingClientRect().bottom < 0;
if (!isFocusOutsideWindow) {
if (_browser2.default.msie) {
setTimeout(function() {
restoreFocus(focusedElement, selectionRange)
})
} else {
restoreFocus(focusedElement, selectionRange)
}
}
}
}
isColumnWidthsCorrected = that._correctColumnWidths(resultWidths, visibleColumns);
if (columnAutoWidth) {
normalizeWidthsByExpandColumns();
if (that._needStretch()) {
that._processStretch(resultWidths, visibleColumns)
}
}
_common2.default.deferRender(function() {
if (needBestFit || isColumnWidthsCorrected) {
that._setVisibleWidths(visibleColumns, resultWidths)
}
})
})
},
_needBestFit: function() {
return this.option("columnAutoWidth")
},
_needStretch: function() {
return this.option("legacyRendering") || this._columnsController.getVisibleColumns().some(function(c) {
return "auto" === c.width && !c.command
})
},
_getAverageColumnsWidth: function(resultWidths) {
var freeWidth = calculateFreeWidth(this, resultWidths),
columnCountWithoutWidth = resultWidths.filter(function(width) {
return void 0 === width
}).length;
return freeWidth / columnCountWithoutWidth
},
_correctColumnWidths: function(resultWidths, visibleColumns) {
var i, averageColumnsWidth, lastColumnIndex, that = this,
hasPercentWidth = false,
hasAutoWidth = false,
isColumnWidthsCorrected = false,
$element = that.component.$element(),
hasWidth = that._hasWidth;
for (i = 0; i < visibleColumns.length; i++) {
var index = i,
column = visibleColumns[index],
isHiddenColumn = resultWidths[index] === HIDDEN_COLUMNS_WIDTH,
width = resultWidths[index],
minWidth = column.minWidth;
if (minWidth) {
if (void 0 === width) {
averageColumnsWidth = that._getAverageColumnsWidth(resultWidths);
width = averageColumnsWidth
} else {
if (isPercentWidth(width)) {
var freeWidth = calculateFreeWidthWithCurrentMinWidth(that, index, minWidth, resultWidths);
if (freeWidth < 0) {
width = -1
}
}
}
}
if (minWidth && that._getRealColumnWidth(width) < minWidth && !isHiddenColumn) {
resultWidths[index] = minWidth;
isColumnWidthsCorrected = true;
i = -1
}
if (!_type2.default.isDefined(column.width)) {
hasAutoWidth = true
}
if (isPercentWidth(column.width)) {
hasPercentWidth = true
}
}
if ($element && that._maxWidth) {
delete that._maxWidth;
$element.css("maxWidth", "")
}
if (!hasAutoWidth && resultWidths.length) {
var contentWidth = that._rowsView.contentWidth(),
scrollbarWidth = that._rowsView.getScrollbarWidth(),
totalWidth = that._getTotalWidth(resultWidths, contentWidth);
if (totalWidth < contentWidth) {
lastColumnIndex = _uiGrid_core4.default.getLastResizableColumnIndex(visibleColumns, resultWidths);
if (lastColumnIndex >= 0) {
resultWidths[lastColumnIndex] = "auto";
isColumnWidthsCorrected = true;
if (!hasWidth && !hasPercentWidth) {
that._maxWidth = totalWidth + scrollbarWidth + (that.option("showBorders") ? 2 : 0);
$element.css("maxWidth", that._maxWidth)
}
}
}
}
return isColumnWidthsCorrected
},
_processStretch: function(resultSizes, visibleColumns) {
var diff, diffElement, onePixelElementsCount, i, groupSize = this._rowsView.contentWidth(),
tableSize = this._getTotalWidth(resultSizes, groupSize),
unusedIndexes = {
length: 0
};
if (!resultSizes.length) {
return
}(0, _iterator.each)(visibleColumns, function(index) {
if (this.width || resultSizes[index] === HIDDEN_COLUMNS_WIDTH) {
unusedIndexes[index] = true;
unusedIndexes.length++
}
});
diff = groupSize - tableSize;
diffElement = Math.floor(diff / (resultSizes.length - unusedIndexes.length));
onePixelElementsCount = diff - diffElement * (resultSizes.length - unusedIndexes.length);
if (diff >= 0) {
for (i = 0; i < resultSizes.length; i++) {
if (unusedIndexes[i]) {
continue
}
resultSizes[i] += diffElement;
if (onePixelElementsCount > 0) {
if (onePixelElementsCount < 1) {
resultSizes[i] += onePixelElementsCount;
onePixelElementsCount = 0
} else {
resultSizes[i]++;
onePixelElementsCount--
}
}
}
}
},
_getRealColumnWidth: function(width, groupWidth) {
if (!isPercentWidth(width)) {
return parseFloat(width)
}
groupWidth = groupWidth || this._rowsView.contentWidth();
return parseFloat(width) * groupWidth / 100
},
_getTotalWidth: function(widths, groupWidth) {
var width, i, result = 0;
for (i = 0; i < widths.length; i++) {
width = widths[i];
if (width && width !== HIDDEN_COLUMNS_WIDTH) {
result += this._getRealColumnWidth(width, groupWidth)
}
}
return Math.round(result)
},
updateSize: function($rootElement) {
var $groupElement, width, that = this,
importantMarginClass = that.addWidgetPrefix(IMPORTANT_MARGIN_CLASS);
if (void 0 === that._hasHeight && $rootElement && $rootElement.is(":visible")) {
$groupElement = $rootElement.children("." + that.getWidgetContainerClass());
if ($groupElement.length) {
$groupElement.detach()
}
that._hasHeight = !!getContainerHeight($rootElement);
width = $rootElement.width();
$rootElement.addClass(importantMarginClass);
that._hasWidth = $rootElement.width() === width;
$rootElement.removeClass(importantMarginClass);
if ($groupElement.length) {
$groupElement.appendTo($rootElement)
}
}
},
publicMethods: function() {
return ["resize", "updateDimensions"]
},
resize: function() {
return !this.component._requireResize && this.updateDimensions()
},
updateDimensions: function(checkSize) {
var that = this;
that._initPostRenderHandlers();
if (!that._checkSize(checkSize)) {
return
}
var prevResult = that._resizeDeferred,
result = that._resizeDeferred = new _deferred.Deferred;
(0, _deferred.when)(prevResult).always(function() {
_common2.default.deferRender(function() {
if (that._dataController.isLoaded()) {
that._synchronizeColumns()
}
that._resetGroupElementHeight();
_common2.default.deferUpdate(function() {
_common2.default.deferRender(function() {
_common2.default.deferUpdate(function() {
that._updateDimensionsCore()
})
})
})
}).done(result.resolve).fail(result.reject)
});
return result.promise()
},
_resetGroupElementHeight: function() {
var groupElement = this.component.$element().children().get(0),
scrollable = this._rowsView.getScrollable();
if (groupElement.style.height && (!scrollable || !scrollable.scrollTop())) {
groupElement.style.height = ""
}
},
_checkSize: function(checkSize) {
var $rootElement = this.component.$element();
if (checkSize && (this._lastWidth === $rootElement.width() && this._lastHeight === $rootElement.height() || !$rootElement.is(":visible"))) {
return false
}
return true
},
_setScrollerSpacingCore: function(hasHeight) {
var that = this,
vScrollbarWidth = hasHeight ? that._rowsView.getScrollbarWidth() : 0,
hScrollbarWidth = that._rowsView.getScrollbarWidth(true);
_common2.default.deferRender(function() {
that._columnHeadersView && that._columnHeadersView.setScrollerSpacing(vScrollbarWidth);
that._footerView && that._footerView.setScrollerSpacing(vScrollbarWidth);
that._rowsView.setScrollerSpacing(vScrollbarWidth, hScrollbarWidth)
})
},
_setScrollerSpacing: function(hasHeight) {
var that = this,
scrollable = that._rowsView.getScrollable();
if (!scrollable && hasHeight) {
_common2.default.deferRender(function() {
_common2.default.deferUpdate(function() {
that._setScrollerSpacingCore(hasHeight)
})
})
} else {
that._setScrollerSpacingCore(hasHeight)
}
},
_updateDimensionsCore: function() {
var hasHeight, $testDiv, that = this,
dataController = that._dataController,
rowsView = that._rowsView,
$rootElement = that.component.$element(),
groupElement = $rootElement.children().get(0),
rootElementHeight = $rootElement && ($rootElement.get(0).clientHeight || $rootElement.height()),
maxHeight = parseFloat($rootElement.css("maxHeight")),
maxHeightHappened = maxHeight && rootElementHeight >= maxHeight,
height = that.option("height") || $rootElement.get(0).style.height,
editorFactory = that.getController("editorFactory"),
isMaxHeightApplied = maxHeightHappened && groupElement.scrollHeight === groupElement.offsetHeight;
that.updateSize($rootElement);
hasHeight = that._hasHeight || maxHeightHappened;
if (height && that._hasHeight ^ "auto" !== height) {
$testDiv = (0, _renderer2.default)("<div>").height(height).appendTo($rootElement);
that._hasHeight = !!$testDiv.height();
$testDiv.remove()
}
_common2.default.deferRender(function() {
rowsView.height(null, hasHeight);
if (maxHeightHappened && !isMaxHeightApplied) {
(0, _renderer2.default)(groupElement).css("height", maxHeight)
}
if (!dataController.isLoaded()) {
rowsView.setLoading(dataController.isLoading());
return
}
_common2.default.deferUpdate(function() {
that._updateLastSizes($rootElement);
that._setScrollerSpacing(hasHeight);
(0, _iterator.each)(VIEW_NAMES, function(index, viewName) {
var view = that.getView(viewName);
if (view) {
view.resize()
}
});
editorFactory && editorFactory.resize()
})
})
},
_updateLastSizes: function($rootElement) {
this._lastWidth = $rootElement.width();
this._lastHeight = $rootElement.height()
},
optionChanged: function(args) {
switch (args.name) {
case "width":
case "height":
this.component._renderDimensions();
this.resize();
case "legacyRendering":
case "renderAsync":
args.handled = true;
return;
default:
this.callBase(args)
}
},
init: function() {
var that = this;
that._dataController = that.getController("data");
that._columnsController = that.getController("columns");
that._columnHeadersView = that.getView("columnHeadersView");
that._footerView = that.getView("footerView");
that._rowsView = that.getView("rowsView")
}
});
var SynchronizeScrollingController = _uiGrid_core2.default.ViewController.inherit({
_scrollChangedHandler: function(views, pos, viewName) {
for (var j = 0; j < views.length; j++) {
if (views[j] && views[j].name !== viewName) {
views[j].scrollTo({
left: pos.left,
top: pos.top
})
}
}
},
init: function() {
var view, i, views = [this.getView("columnHeadersView"), this.getView("footerView"), this.getView("rowsView")];
for (i = 0; i < views.length; i++) {
view = views[i];
if (view) {
view.scrollChanged.add(this._scrollChangedHandler.bind(this, views))
}
}
}
});
var GridView = _uiGrid_core2.default.View.inherit({
_endUpdateCore: function() {
if (this.component._requireResize) {
this.component._requireResize = false;
this._resizingController.resize()
}
},
_getWidgetAriaLabel: function() {
return "dxDataGrid-ariaDataGrid"
},
init: function() {
var that = this;
that._resizingController = that.getController("resizing");
that._dataController = that.getController("data")
},
getView: function(name) {
return this.component._views[name]
},
element: function() {
return this._groupElement
},
optionChanged: function(args) {
var that = this;
if (_type2.default.isDefined(that._groupElement) && "showBorders" === args.name) {
that._groupElement.toggleClass(that.addWidgetPrefix(BORDERS_CLASS), !!args.value);
args.handled = true
} else {
that.callBase(args)
}
},
_renderViews: function($groupElement) {
var that = this;
(0, _iterator.each)(VIEW_NAMES, function(index, viewName) {
var view = that.getView(viewName);
if (view) {
view.render($groupElement)
}
})
},
_getTableRoleName: function() {
return "grid"
},
render: function($rootElement) {
var that = this,
isFirstRender = !that._groupElement,
$groupElement = that._groupElement || (0, _renderer2.default)("<div>").addClass(that.getWidgetContainerClass());
$groupElement.addClass(GRIDBASE_CONTAINER_CLASS);
$groupElement.toggleClass(that.addWidgetPrefix(BORDERS_CLASS), !!that.option("showBorders"));
that.setAria("role", "presentation", $rootElement);
that.component.setAria({
role: this._getTableRoleName(),
label: _message2.default.format(that._getWidgetAriaLabel())
}, $groupElement);
that._rootElement = $rootElement || that._rootElement;
if (isFirstRender) {
that._groupElement = $groupElement;
_window2.default.hasWindow() && that.getController("resizing").updateSize($rootElement);
$groupElement.appendTo($rootElement)
}
that._renderViews($groupElement)
},
update: function() {
var that = this,
$rootElement = that._rootElement,
$groupElement = that._groupElement,
resizingController = that.getController("resizing");
if ($rootElement && $groupElement) {
resizingController.resize();
if (that._dataController.isLoaded()) {
that.component._fireContentReadyAction()
}
}
}
});
module.exports = {
defaultOptions: function() {
return {
showBorders: false,
renderAsync: false,
legacyRendering: false
}
},
controllers: {
resizing: ResizingController,
synchronizeScrolling: SynchronizeScrollingController
},
views: {
gridView: GridView
}
};