UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

872 lines (704 loc) • 30.4 kB
"use strict"; var $ = require("../../core/renderer"), domAdapter = require("../../core/dom_adapter"), eventsEngine = require("../../events/core/events_engine"), dataUtils = require("../../core/element_data"), clickEvent = require("../../events/click"), browser = require("../../core/utils/browser"), commonUtils = require("../../core/utils/common"), styleUtils = require("../../core/utils/style"), getPublicElement = require("../../core/utils/dom").getPublicElement, typeUtils = require("../../core/utils/type"), iteratorUtils = require("../../core/utils/iterator"), extend = require("../../core/utils/extend").extend, getDefaultAlignment = require("../../core/utils/position").getDefaultAlignment, devices = require("../../core/devices"), modules = require("./ui.grid_core.modules"), gridCoreUtils = require("./ui.grid_core.utils"), columnStateMixin = require("./ui.grid_core.column_state_mixin"), noop = commonUtils.noop; var SCROLL_CONTAINER_CLASS = "scroll-container", GROUP_SPACE_CLASS = "group-space", CONTENT_CLASS = "content", TABLE_CLASS = "table", TABLE_FIXED_CLASS = "table-fixed", CONTENT_FIXED_CLASS = "content-fixed", ROW_CLASS = "dx-row", GROUP_ROW_CLASS = "dx-group-row", DETAIL_ROW_CLASS = "dx-master-detail-row", FILTER_ROW_CLASS = "filter-row", HIDDEN_COLUMNS_WIDTH = "0.0001px", CELL_HINT_VISIBLE = "dxCellHintVisible", FORM_FIELD_ITEM_CONTENT_CLASS = "dx-field-item-content"; var appendElementTemplate = { render: function render(options) { options.container.append(options.content); } }; var subscribeToRowClick = function subscribeToRowClick(that, $table) { var touchTarget, touchCurrentTarget, timeoutId; function clearTouchTargets(timeout) { return setTimeout(function () { touchTarget = touchCurrentTarget = null; }, timeout); } eventsEngine.on($table, "touchstart touchend", ".dx-row", function (e) { clearTimeout(timeoutId); if (e.type === "touchstart") { touchTarget = e.target; touchCurrentTarget = e.currentTarget; timeoutId = clearTouchTargets(1000); } else { timeoutId = clearTouchTargets(); } }); eventsEngine.on($table, "dxclick", ".dx-row", { useNative: that._isNativeClick() }, that.createAction(function (e) { var dxEvent = e.event; if (touchTarget) { dxEvent.target = touchTarget; dxEvent.currentTarget = touchCurrentTarget; } if (!$(dxEvent.target).closest("a").length) { e.rowIndex = that.getRowIndex(dxEvent.currentTarget); if (e.rowIndex >= 0) { e.rowElement = getPublicElement($(dxEvent.currentTarget)); e.columns = that.getColumns(); that._rowClick(e); } } })); }; var getWidthStyle = function getWidthStyle(width) { if (width === "auto") return ""; return typeof width === "number" ? width + "px" : width; }; exports.ColumnsView = modules.View.inherit(columnStateMixin).inherit({ _createScrollableOptions: function _createScrollableOptions() { var that = this, scrollingOptions = that.option("scrolling"), useNativeScrolling = that.option("scrolling.useNative"); var options = extend({}, scrollingOptions, { direction: "both", updateManually: true, bounceEnabled: false, useKeyboard: false }); // TODO jsdmitry: This condition is for unit tests and testing scrollable if (useNativeScrolling === undefined) { useNativeScrolling = true; } if (useNativeScrolling === "auto") { delete options.useNative; delete options.useSimulatedScrollbar; } else { options.useNative = !!useNativeScrolling; options.useSimulatedScrollbar = !useNativeScrolling; } return options; }, _updateCell: function _updateCell($cell, parameters) { if (parameters.rowType) { this._cellPrepared($cell, parameters); } }, _createCell: function _createCell(options) { var column = options.column, alignment = column.alignment || getDefaultAlignment(this.option("rtlEnabled")); var cell = domAdapter.createElement("td"); cell.style.textAlign = alignment; var $cell = $(cell); if (!typeUtils.isDefined(column.groupIndex) && column.cssClass) { $cell.addClass(column.cssClass); } if (column.command === "expand") { $cell.addClass(column.cssClass); $cell.addClass(this.addWidgetPrefix(GROUP_SPACE_CLASS)); } if (!this.option("legacyRendering") && this.option("columnAutoWidth")) { if (column.width || column.minWidth) { cell.style.minWidth = getWidthStyle(column.minWidth || column.width); } if (column.width) { cell.style.width = cell.style.maxWidth = getWidthStyle(column.width); } } column.colspan > 1 && $cell.attr("colSpan", column.colspan); return $cell; }, _createRow: function _createRow(rowObject) { var $element = $("<tr>").addClass(ROW_CLASS); this.setAria("role", "row", $element); return $element; }, _createTable: function _createTable(columns, isAppend) { var that = this, $table = $("<table>").addClass(that.addWidgetPrefix(TABLE_CLASS)).addClass(that.addWidgetPrefix(TABLE_FIXED_CLASS)); if (columns && !isAppend) { $table.append(that._createColGroup(columns)); if (devices.real().ios) { // T198380 $table.append($("<thead>").append("<tr>")); } that.setAria("role", "presentation", $table); } else { that.setAria("hidden", true, $table); } $table.append($("<tbody>")); if (isAppend) { return $table; } // T138469 if (browser.mozilla) { eventsEngine.on($table, "mousedown", "td", function (e) { if (e.ctrlKey) { e.preventDefault(); } }); } if (that.option("cellHintEnabled")) { eventsEngine.on($table, "mousemove", ".dx-row > td", this.createAction(function (args) { var e = args.event, difference, $element = $(e.target), $cell = $(e.currentTarget), $row = $cell.parent(), isDataRow = $row.hasClass("dx-data-row"), isHeaderRow = $row.hasClass("dx-header-row"), isGroupRow = $row.hasClass("dx-group-row"), isMasterDetailRow = $row.hasClass(DETAIL_ROW_CLASS), isFilterRow = $row.hasClass(that.addWidgetPrefix(FILTER_ROW_CLASS)), visibleColumns = that._columnsController.getVisibleColumns(), rowOptions = $row.data("options"), columnIndex = $cell.index(), cellOptions = rowOptions && rowOptions.cells && rowOptions.cells[columnIndex], column = cellOptions ? cellOptions.column : visibleColumns[columnIndex], msieCorrection = browser.msie ? 1 : 0; if (!isMasterDetailRow && !isFilterRow && (!isDataRow || isDataRow && column && !column.cellTemplate) && (!isHeaderRow || isHeaderRow && column && !column.headerCellTemplate) && (!isGroupRow || isGroupRow && column && (column.groupIndex === undefined || !column.groupCellTemplate))) { if ($element.data(CELL_HINT_VISIBLE)) { $element.removeAttr("title"); $element.data(CELL_HINT_VISIBLE, false); } difference = $element[0].scrollWidth - $element[0].clientWidth - msieCorrection; // T598499 if (difference > 0 && !typeUtils.isDefined($element.attr("title"))) { $element.attr("title", $element.text()); $element.data(CELL_HINT_VISIBLE, true); } } })); } var getOptions = function getOptions(event) { var $cell = $(event.currentTarget), $fieldItemContent = $(event.target).closest("." + FORM_FIELD_ITEM_CONTENT_CLASS), formItemOptions, rowOptions = $cell.parent().data("options"), options = rowOptions && rowOptions.cells && rowOptions.cells[$cell.index()], resultOptions; if (!$cell.closest("table").is(event.delegateTarget)) return; resultOptions = extend({}, options, { cellElement: getPublicElement($cell), event: event, eventType: event.type }); if ($fieldItemContent.length) { formItemOptions = $fieldItemContent.data("dx-form-item"); if (formItemOptions.column) { resultOptions.column = formItemOptions.column; resultOptions.columnIndex = that._columnsController.getVisibleIndex(resultOptions.column.index); } } return resultOptions; }; eventsEngine.on($table, "mouseover", ".dx-row > td", function (e) { var options = getOptions(e); options && that.executeAction("onCellHoverChanged", options); }); eventsEngine.on($table, "mouseout", ".dx-row > td", function (e) { var options = getOptions(e); options && that.executeAction("onCellHoverChanged", options); }); eventsEngine.on($table, clickEvent.name, ".dx-row > td", function (e) { var options = getOptions(e); options && that.executeAction("onCellClick", options); }); subscribeToRowClick(that, $table); return $table; }, _isNativeClick: commonUtils.noop, _rowClick: commonUtils.noop, _createColGroup: function _createColGroup(columns) { var i, j, colgroupElement = $("<colgroup>"), colspan; for (i = 0; i < columns.length; i++) { colspan = columns[i].colspan || 1; for (j = 0; j < colspan; j++) { colgroupElement.append(this._createCol(columns[i])); } } return colgroupElement; }, _createCol: function _createCol(column) { var width = column.visibleWidth || column.width; if (width === "adaptiveHidden") { width = HIDDEN_COLUMNS_WIDTH; } var col = $("<col>"); styleUtils.setWidth(col, width); return col; }, renderDelayedTemplates: function renderDelayedTemplates() { var templateParameters, delayedTemplates = this._delayedTemplates; while (delayedTemplates.length) { templateParameters = delayedTemplates.shift(); templateParameters.template.render(templateParameters.options); if (templateParameters.options.model && templateParameters.options.model.column) { this._updateCell(templateParameters.options.container, templateParameters.options.model); } } }, _processTemplate: function _processTemplate(template) { var that = this, templateID, renderingTemplate; if (template && template.render && !typeUtils.isRenderer(template)) { renderingTemplate = { allowRenderToDetachedContainer: template.allowRenderToDetachedContainer, render: function render(options) { template.render(options.container, options.model); } }; } else if (typeUtils.isFunction(template)) { renderingTemplate = { render: function render(options) { var renderedTemplate = template(getPublicElement(options.container), options.model); if (renderedTemplate && (renderedTemplate.nodeType || typeUtils.isRenderer(renderedTemplate))) { options.container.append(renderedTemplate); } } }; } else { templateID = typeUtils.isString(template) ? template : $(template).attr("id"); if (!templateID) { renderingTemplate = that.getTemplate(template); } else { if (!that._templatesCache[templateID]) { that._templatesCache[templateID] = that.getTemplate(template); } renderingTemplate = that._templatesCache[templateID]; } } return renderingTemplate; }, renderTemplate: function renderTemplate(container, template, options, allowRenderToDetachedContainer) { var that = this, renderingTemplate = that._processTemplate(template, options); if (renderingTemplate) { options.component = that.component; if (renderingTemplate.allowRenderToDetachedContainer || allowRenderToDetachedContainer) { renderingTemplate.render({ container: container, model: options }); return true; } else { that._delayedTemplates.push({ template: renderingTemplate, options: { container: container, model: options } }); } } return false; }, _appendRow: function _appendRow($table, $row, appendTemplate) { appendTemplate = appendTemplate || appendElementTemplate; appendTemplate.render({ content: $row, container: $table }); }, _resizeCore: function _resizeCore() { var that = this, scrollLeft = that._scrollLeft; if (scrollLeft >= 0) { that._scrollLeft = 0; that.scrollTo({ left: scrollLeft }); } }, _renderCore: function _renderCore(e) { var $root = this.element().parent(); if (!$root || $root.parent().length) { this.renderDelayedTemplates(e); } }, _renderTable: function _renderTable(options) { options = options || {}; var that = this, $table; options.columns = that._columnsController.getVisibleColumns(); var changeType = options.change && options.change.changeType; $table = that._createTable(options.columns, changeType === "append" || changeType === "prepend"); that._renderRows($table, options); return $table; }, _renderRows: function _renderRows($table, options) { var that = this, i, rows = that._getRows(options.change); for (i = 0; i < rows.length; i++) { that._renderRow($table, extend({ row: rows[i] }, options)); } }, _renderRow: function _renderRow($table, options) { var that = this, $row; options.row.cells = []; $row = that._createRow(options.row); that._renderCells($row, options); that._appendRow($table, $row); that._rowPrepared($row, extend({ columns: options.columns }, options.row)); }, _renderCells: function _renderCells($row, options) { var that = this, i, columnIndex = 0, row = options.row, columns = options.columns; for (i = 0; i < columns.length; i++) { that._renderCell($row, extend({ column: columns[i], columnIndex: columnIndex, value: row.values && row.values[columnIndex] }, options)); if (columns[i].colspan > 1) { columnIndex += columns[i].colspan; } else { columnIndex++; } } }, _renderCell: function _renderCell($row, options) { var that = this, cellOptions = that._getCellOptions(options), $cell; options.row.cells.push(cellOptions); $cell = that._createCell(cellOptions); if (cellOptions.rowType !== "freeSpace") { that.setAria("role", "gridcell", $cell); that.setAria("colindex", options.columnIndex + 1, $cell); that.setAria("selected", false, $cell); } that._renderCellContent($cell, cellOptions); $row.get(0).appendChild($cell.get(0)); return $cell; }, _renderCellContent: function _renderCellContent($cell, options) { var template = this._getCellTemplate(options); if (!template || this.renderTemplate($cell, template, options)) { this._updateCell($cell, options); } }, _getCellTemplate: function _getCellTemplate() {}, _getRows: function _getRows() { return []; }, _getCellOptions: function _getCellOptions(options) { return { column: options.column, columnIndex: options.columnIndex, rowType: options.row.rowType }; }, _cellPrepared: function _cellPrepared(cell, options) { options.cellElement = getPublicElement($(cell)); this.executeAction("onCellPrepared", options); }, _rowPrepared: function _rowPrepared($row, options) { dataUtils.data($row.get(0), "options", options); options.rowElement = getPublicElement($row); this.executeAction("onRowPrepared", options); }, _columnOptionChanged: function _columnOptionChanged(e) { var optionNames = e.optionNames; if (gridCoreUtils.checkChanges(optionNames, ["width", "visibleWidth"])) { var visibleColumns = this._columnsController.getVisibleColumns(); var widths = iteratorUtils.map(visibleColumns, function (column) { return column.visibleWidth || column.width || "auto"; }); this.setColumnWidths(widths); return; } if (!this._requireReady) { this.render(); } }, getTableElements: function getTableElements() { return this._tableElement || $(); }, _getTableElement: function _getTableElement() { return this._tableElement; }, _setTableElement: function _setTableElement(tableElement) { this._tableElement = tableElement; }, optionChanged: function optionChanged(args) { this.callBase(args); switch (args.name) { case "cellHintEnabled": case "onCellPrepared": case "onRowPrepared": case "onCellHoverChanged": this._invalidate(true, true); args.handled = true; break; } }, init: function init() { var that = this; that._scrollLeft = -1; that._columnsController = that.getController("columns"); that._dataController = that.getController("data"); that._delayedTemplates = []; that._templatesCache = {}; that.createAction("onCellClick"); that.createAction("onRowClick"); that.createAction("onCellHoverChanged", { excludeValidators: ["disabled", "readOnly"] }); that.createAction("onCellPrepared", { excludeValidators: ["designMode", "disabled", "readOnly"], category: "rendering" }); that.createAction("onRowPrepared", { excludeValidators: ["designMode", "disabled", "readOnly"], category: "rendering", afterExecute: function afterExecute(e) { that._afterRowPrepared(e); } }); that._columnsController.columnsChanged.add(that._columnOptionChanged.bind(that)); that._dataController && that._dataController.changed.add(that._handleDataChanged.bind(that)); }, _afterRowPrepared: commonUtils.noop, _handleDataChanged: function _handleDataChanged() {}, callbackNames: function callbackNames() { return ["scrollChanged"]; }, scrollTo: function scrollTo(pos) { var that = this, $element = that.element(), $scrollContainer = $element && $element.children("." + that.addWidgetPrefix(SCROLL_CONTAINER_CLASS)).not("." + that.addWidgetPrefix(CONTENT_FIXED_CLASS)); that._skipScrollChanged = false; if (typeUtils.isDefined(pos) && typeUtils.isDefined(pos.left) && that._scrollLeft !== pos.left) { that._scrollLeft = pos.left; $scrollContainer && $scrollContainer.scrollLeft(Math.round(pos.left)); that._skipScrollChanged = true; } }, _wrapTableInScrollContainer: function _wrapTableInScrollContainer($table) { var that = this, $scrollContainer; $scrollContainer = $("<div>"); eventsEngine.on($scrollContainer, "scroll", function () { !that._skipScrollChanged && that.scrollChanged.fire({ left: $scrollContainer.scrollLeft() }, that.name); that._skipScrollChanged = false; }); $scrollContainer.addClass(that.addWidgetPrefix(CONTENT_CLASS)).addClass(that.addWidgetPrefix(SCROLL_CONTAINER_CLASS)).append($table).appendTo(that.element()); that.setAria("role", "presentation", $scrollContainer); return $scrollContainer; }, _updateContent: function _updateContent($newTableElement) { this._setTableElement($newTableElement); this._wrapTableInScrollContainer($newTableElement); }, _findContentElement: commonUtils.noop, _getWidths: function _getWidths($cellElements) { var result = [], legacyRendering = this.option("legacyRendering"), width, clientRect; if ($cellElements) { iteratorUtils.each($cellElements, function (index, item) { width = item.offsetWidth; if (item.getBoundingClientRect) { clientRect = item.getBoundingClientRect(); if (clientRect.width > width - 1) { width = legacyRendering ? Math.ceil(clientRect.width) : clientRect.width; } } result.push(width); }); } return result; }, getColumnWidths: function getColumnWidths($tableElement) { var that = this, result = [], $cells; (this.option("forceApplyBindings") || noop)(); $tableElement = $tableElement || that._getTableElement(); if ($tableElement) { $cells = $tableElement.children("tbody").children(); for (var i = 0; i < $cells.length; i++) { var $cell = $cells.eq(i); if (!$cell.is("." + GROUP_ROW_CLASS) && !$cell.is("." + DETAIL_ROW_CLASS)) { $cells = $cell.children("td"); break; } } result = that._getWidths($cells); } return result; }, setColumnWidths: function setColumnWidths(widths, $tableElement, columns, fixed) { var $cols, i, width, minWidth, columnIndex, columnAutoWidth = this.option("columnAutoWidth"), legacyRendering = this.option("legacyRendering"); $tableElement = $tableElement || this._getTableElement(); if ($tableElement && $tableElement.length && widths) { columnIndex = 0; $cols = $tableElement.find("col"); if (!legacyRendering) { styleUtils.setWidth($cols, "auto"); } columns = columns || this.getColumns(null, $tableElement); for (i = 0; i < columns.length; i++) { if (!legacyRendering && columnAutoWidth && !fixed) { width = columns[i].width; if (width && !columns[i].command) { width = columns[i].visibleWidth || width; width = getWidthStyle(width); minWidth = getWidthStyle(columns[i].minWidth || width); var $rows = $rows || $tableElement.children().children(".dx-row"); for (var rowIndex = 0; rowIndex < $rows.length; rowIndex++) { var cell = $rows[rowIndex].cells[i]; if (cell) { cell.style.width = cell.style.maxWidth = width; cell.style.minWidth = minWidth; } } } } if (columns[i].colspan) { columnIndex += columns[i].colspan; continue; } width = widths[columnIndex]; if (width === "adaptiveHidden") { width = HIDDEN_COLUMNS_WIDTH; } if (typeof width === "number") { width = width.toFixed(3) + "px"; } styleUtils.setWidth($cols.eq(columnIndex), width || "auto"); columnIndex++; } } }, getCellElements: function getCellElements(rowIndex) { return this._getCellElementsCore(rowIndex); }, _getCellElementsCore: function _getCellElementsCore(rowIndex) { var $row = this._getRowElements().eq(rowIndex); return $row.children(); }, _getCellElement: function _getCellElement(rowIndex, columnIdentifier) { var that = this, $cell, $cells = that.getCellElements(rowIndex), columnVisibleIndex = that._getVisibleColumnIndex($cells, rowIndex, columnIdentifier); if ($cells.length && columnVisibleIndex >= 0) { $cell = $cells.eq(columnVisibleIndex); } if ($cell && $cell.length) { return $cell; } }, _getRowElement: function _getRowElement(rowIndex) { var that = this, $rowElement = $(), $tableElements = that.getTableElements(); iteratorUtils.each($tableElements, function (_, tableElement) { $rowElement = $rowElement.add(that._getRowElements($(tableElement)).eq(rowIndex)); }); if ($rowElement.length) { return $rowElement; } }, /** * @name GridBaseMethods.getCellElement * @publicName getCellElement(rowIndex, visibleColumnIndex) * @param1 rowIndex:number * @param2 visibleColumnIndex:number * @return dxElement|undefined */ /** * @name GridBaseMethods.getCellElement * @publicName getCellElement(rowIndex, dataField) * @param1 rowIndex:number * @param2 dataField:string * @return dxElement|undefined */ getCellElement: function getCellElement(rowIndex, columnIdentifier) { return getPublicElement(this._getCellElement(rowIndex, columnIdentifier)); }, /** * @name GridBaseMethods.getRowElement * @publicName getRowElement(rowIndex) * @param1 rowIndex:number * @return Array<Node>|jQuery|undefined */ getRowElement: function getRowElement(rowIndex) { var $rows = this._getRowElement(rowIndex), elements = []; if ($rows && !getPublicElement($rows).get) { for (var i = 0; i < $rows.length; i++) { elements.push($rows[i]); } } else { elements = $rows; } return elements; }, _getVisibleColumnIndex: function _getVisibleColumnIndex($cells, rowIndex, columnIdentifier) { var columnIndex; if (typeUtils.isString(columnIdentifier)) { columnIndex = this._columnsController.columnOption(columnIdentifier, "index"); return this._columnsController.getVisibleIndex(columnIndex); } return columnIdentifier; }, getColumnElements: function getColumnElements() {}, getColumns: function getColumns(rowIndex) { return this._columnsController.getVisibleColumns(rowIndex); }, getCell: function getCell(cellPosition, rows) { var $rows = rows || this._getRowElements(), $cells; if ($rows.length > 0 && cellPosition.rowIndex >= 0) { if (this.option("scrolling.mode") !== "virtual") { cellPosition.rowIndex = cellPosition.rowIndex < $rows.length ? cellPosition.rowIndex : $rows.length - 1; } $cells = this.getCellElements(cellPosition.rowIndex); if ($cells && $cells.length > 0) { return $cells.eq($cells.length > cellPosition.columnIndex ? cellPosition.columnIndex : $cells.length - 1); } } }, getRowsCount: function getRowsCount() { var tableElement = this._getTableElement(); if (tableElement && tableElement.length === 1) { return tableElement[0].rows.length; } return 0; }, _getRowElements: function _getRowElements(tableElement) { tableElement = tableElement || this._getTableElement(); return tableElement && tableElement.children("tbody").children("." + ROW_CLASS) || $(); }, getRowIndex: function getRowIndex($row) { return this._getRowElements().index($row); }, getBoundingRect: function getBoundingRect() {}, getName: function getName() {}, setScrollerSpacing: function setScrollerSpacing(width) { var that = this, $element = that.element(), rtlEnabled = that.option("rtlEnabled"); $element && $element.css(rtlEnabled ? { paddingLeft: width } : { paddingRight: width }); }, isScrollbarVisible: function isScrollbarVisible(isHorizontal) { var $element = this.element(), $tableElement = this._tableElement; if ($element && $tableElement) { return isHorizontal ? $tableElement.outerWidth() - $element.width() > 0 : $tableElement.outerHeight() - $element.height() > 0; } return false; } });