UNPKG

devextreme

Version:

JavaScript/TypeScript Component Suite for Responsive Web Development

482 lines (481 loc) • 21.2 kB
/** * DevExtreme (esm/__internal/ui/file_manager/ui.file_manager.item_list.details.js) * Version: 25.2.8 * Build date: Mon Jun 08 2026 * * Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import messageLocalization from "../../../common/core/localization/message"; import $ from "../../../core/renderer"; import { Deferred } from "../../../core/utils/deferred"; import { extend } from "../../../core/utils/extend"; import { isDefined, isFunction, isString } from "../../../core/utils/type"; import DataGrid from "../../../ui/data_grid"; import { OPERATIONS } from "../../ui/file_manager/file_items_controller"; import { extendAttributes, getDisplayFileSize } from "../../ui/file_manager/ui.file_manager.common"; import FileManagerFileActionsButton from "../../ui/file_manager/ui.file_manager.file_actions_button"; import FileManagerItemListBase from "../../ui/file_manager/ui.file_manager.item_list"; const FILE_MANAGER_DETAILS_ITEM_LIST_CLASS = "dx-filemanager-details"; const FILE_MANAGER_DETAILS_ITEM_THUMBNAIL_CLASS = "dx-filemanager-details-item-thumbnail"; const FILE_MANAGER_DETAILS_ITEM_NAME_CLASS = "dx-filemanager-details-item-name"; const FILE_MANAGER_DETAILS_ITEM_NAME_WRAPPER_CLASS = "dx-filemanager-details-item-name-wrapper"; const FILE_MANAGER_DETAILS_ITEM_IS_DIRECTORY_CLASS = "dx-filemanager-details-item-is-directory"; const FILE_MANAGER_PARENT_DIRECTORY_ITEM = "dx-filemanager-parent-directory-item"; const DATA_GRID_DATA_ROW_CLASS = "dx-data-row"; const DEFAULT_COLUMN_CONFIGS = { thumbnail: { caption: "", calculateSortValue: "isDirectory", width: 36, alignment: "center", cssClass: "dx-filemanager-details-item-is-directory" }, name: { caption: messageLocalization.format("dxFileManager-listDetailsColumnCaptionName") }, dateModified: { caption: messageLocalization.format("dxFileManager-listDetailsColumnCaptionDateModified"), width: 110, hidingPriority: 1 }, size: { caption: messageLocalization.format("dxFileManager-listDetailsColumnCaptionFileSize"), width: 90, alignment: "right", hidingPriority: 0 }, isParentFolder: { caption: "isParentFolder", visible: false, sortIndex: 0, sortOrder: "asc" } }; class FileManagerDetailsItemList extends FileManagerItemListBase { _initMarkup() { this._itemCount = 0; this._focusedItem = null; this._hasParentDirectoryItem = false; this._parentDirectoryItemKey = null; this._selectAllCheckBox = null; this._selectAllCheckBoxUpdating = false; this.$element().addClass("dx-filemanager-details"); this._createFilesView(); this._contextMenu.option("onContextMenuHidden", () => this._onContextMenuHidden()); super._initMarkup() } _createFilesView() { const $filesView = $("<div>").appendTo(this.$element()); const selectionMode = this._isMultipleSelectionMode() ? "multiple" : "none"; this._filesView = this._createComponent($filesView, DataGrid, { dataSource: this._createDataSource(), hoverStateEnabled: true, selection: { mode: selectionMode, showCheckBoxesMode: this._isDesktop() ? "onClick" : "none" }, selectedRowKeys: this.option("selectedItemKeys"), focusedRowKey: this.option("focusedItemKey"), focusedRowEnabled: true, allowColumnResizing: true, scrolling: { mode: "virtual" }, sorting: { mode: "single", showSortIndexes: false }, loadPanel: { shading: true }, height: "100%", showColumnLines: false, showRowLines: false, columnHidingEnabled: false, columns: this._createColumns(), onEditorPreparing: this._onEditorPreparing.bind(this), onRowPrepared: this._onRowPrepared.bind(this), onContextMenuPreparing: this._onContextMenuPreparing.bind(this), onSelectionChanged: this._onFilesViewSelectionChanged.bind(this), onFocusedRowChanged: this._onFilesViewFocusedRowChanged.bind(this), onOptionChanged: this._onFilesViewOptionChanged.bind(this), onContentReady: this._onContentReady.bind(this) }) } _createColumns() { let { detailColumns: columns } = this.option(); columns = columns.slice(0); columns = columns.map(column => { let extendedItem = column; if (isString(column)) { extendedItem = { dataField: column } } return this._getPreparedColumn(extendedItem) }); const customizeDetailColumns = this.option("customizeDetailColumns"); if (isFunction(customizeDetailColumns)) { columns = customizeDetailColumns(columns) } columns.push(this._getPreparedColumn({ dataField: "isParentFolder" })); columns.forEach(column => this._updateColumnDataField(column)); return columns } _getPreparedColumn(columnOptions) { const result = {}; let resultCssClass = ""; if (this._isDefaultColumn(columnOptions.dataField)) { const defaultConfig = extend(true, {}, DEFAULT_COLUMN_CONFIGS[columnOptions.dataField]); resultCssClass = defaultConfig.cssClass || ""; switch (columnOptions.dataField) { case "thumbnail": defaultConfig.cellTemplate = this._createThumbnailColumnCell.bind(this); defaultConfig.calculateSortValue = `fileItem.${defaultConfig.calculateSortValue}`; break; case "name": defaultConfig.cellTemplate = this._createNameColumnCell.bind(this); defaultConfig.caption = messageLocalization.format("dxFileManager-listDetailsColumnCaptionName"); break; case "size": defaultConfig.calculateCellValue = this._calculateSizeColumnCellValue.bind(this); defaultConfig.caption = messageLocalization.format("dxFileManager-listDetailsColumnCaptionFileSize"); defaultConfig.calculateSortValue = rowData => rowData.fileItem.isDirectory ? -1 : rowData.fileItem.size; break; case "dateModified": defaultConfig.caption = messageLocalization.format("dxFileManager-listDetailsColumnCaptionDateModified") } extend(true, result, defaultConfig) } extendAttributes(result, columnOptions, ["alignment", "caption", "dataField", "dataType", "hidingPriority", "sortIndex", "sortOrder", "visible", "visibleIndex", "width"]); if (columnOptions.cssClass) { resultCssClass = `${resultCssClass} ${columnOptions.cssClass}` } if (resultCssClass) { result.cssClass = resultCssClass } return result } _updateColumnDataField(column) { const dataItemSuffix = this._isDefaultColumn(column.dataField) ? "" : "dataItem."; column.dataField = `fileItem.${dataItemSuffix}${column.dataField}`; return column } _isDefaultColumn(columnDataField) { return !!DEFAULT_COLUMN_CONFIGS[columnDataField] } _onFileItemActionButtonClick(e) { var _this$_activeFileActi; const { component: component, element: element, event: event } = e; null === event || void 0 === event || event.stopPropagation(); const $row = component.$element().closest(this._getItemSelector()); const fileItemInfo = $row.data("item"); this._selectItem(fileItemInfo); const target = { itemData: fileItemInfo, itemElement: $row, isActionButton: true }; const items = this._getFileItemsForContextMenu(fileItemInfo); this._showContextMenu(items, element, event, target); this._activeFileActionsButton = component; null === (_this$_activeFileActi = this._activeFileActionsButton) || void 0 === _this$_activeFileActi || _this$_activeFileActi.setActive(true) } _onContextMenuHidden() { if (this._activeFileActionsButton) { this._activeFileActionsButton.setActive(false) } } _getItemThumbnailCssClass() { return "dx-filemanager-details-item-thumbnail" } _getItemSelector() { return ".dx-data-row" } _onItemDblClick(e) { const $row = $(e.currentTarget); const fileItemInfo = $row.data("item"); this._raiseSelectedItemOpened(fileItemInfo) } _isAllItemsSelected() { var _this$_filesView; const selectableItemsCount = this._hasParentDirectoryItem ? this._itemCount - 1 : this._itemCount; const { selectedRowKeys: selectedRowKeys } = (null === (_this$_filesView = this._filesView) || void 0 === _this$_filesView ? void 0 : _this$_filesView.option()) ?? {}; if (!(null !== selectedRowKeys && void 0 !== selectedRowKeys && selectedRowKeys.length)) { return false } return selectedRowKeys.length >= selectableItemsCount ? true : void 0 } _onEditorPreparing(_ref) { let { component: component, command: command, row: row, parentType: parentType, editorOptions: editorOptions } = _ref; if (!this._filesView) { this._filesView = component } if ("select" === command && row) { if (this._isParentDirectoryItem(row.data)) { editorOptions.disabled = true } } else if ("headerRow" === parentType) { editorOptions.onInitialized = _ref2 => { let { component: component } = _ref2; this._selectAllCheckBox = component }; editorOptions.value = this._isAllItemsSelected(); editorOptions.onValueChanged = args => this._onSelectAllCheckBoxValueChanged(args) } } _onSelectAllCheckBoxValueChanged(_ref3) { let { event: event, previousValue: previousValue, value: value } = _ref3; if (!event) { if (previousValue && !this._selectAllCheckBoxUpdating && this._selectAllCheckBox) { this._selectAllCheckBox.option("value", previousValue) } return } if (this._isAllItemsSelected() === value) { return } if (value) { var _this$_filesView2; null === (_this$_filesView2 = this._filesView) || void 0 === _this$_filesView2 || _this$_filesView2.selectAll() } else { var _this$_filesView3; null === (_this$_filesView3 = this._filesView) || void 0 === _this$_filesView3 || _this$_filesView3.deselectAll() } event.preventDefault() } _onRowPrepared(_ref4) { let { rowType: rowType, rowElement: rowElement, data: data } = _ref4; if ("data" === rowType) { const $row = $(rowElement); $row.data("item", data); if (this._isParentDirectoryItem(data)) { $row.addClass(FILE_MANAGER_PARENT_DIRECTORY_ITEM) } } } _onContextMenuPreparing(e) { var _this$_filesView4; if (!this._isDesktop()) { return } let fileItems = null; let item = {}; if (e.row && "data" === e.row.rowType) { item = e.row.data; this._selectItem(item); fileItems = this._getFileItemsForContextMenu(item) } const eventArgs = extend({}, { targetElement: "content" === e.target && isDefined(e.row) ? null === (_this$_filesView4 = this._filesView) || void 0 === _this$_filesView4 ? void 0 : _this$_filesView4.getRowElement(e.rowIndex) : void 0, itemData: item, options: this._contextMenu.option(), event: e.event, isActionButton: false, cancel: false }); this._raiseContextMenuShowing(eventArgs); e.items = eventArgs.cancel ? [] : this._contextMenu.createContextMenuItems(fileItems, null, item) } _onFilesViewSelectionChanged(_ref5) { let { component: component, selectedRowsData: selectedRowsData, selectedRowKeys: selectedRowKeys, currentSelectedRowKeys: currentSelectedRowKeys, currentDeselectedRowKeys: currentDeselectedRowKeys } = _ref5; this._filesView = this._filesView || component; if (this._selectAllCheckBox) { this._selectAllCheckBoxUpdating = true; this._selectAllCheckBox.option("value", this._isAllItemsSelected()); this._selectAllCheckBoxUpdating = false } const selectedItems = selectedRowsData.map(itemInfo => itemInfo.fileItem); this._tryRaiseSelectionChanged({ selectedItemInfos: selectedRowsData, selectedItems: selectedItems, selectedItemKeys: selectedRowKeys, currentSelectedItemKeys: currentSelectedRowKeys, currentDeselectedItemKeys: currentDeselectedRowKeys }) } _onFilesViewFocusedRowChanged(e) { var _e$row2; if (!this._isMultipleSelectionMode()) { var _e$row; this._selectItemSingleSelection(null === (_e$row = e.row) || void 0 === _e$row ? void 0 : _e$row.data) } const fileSystemItem = (null === (_e$row2 = e.row) || void 0 === _e$row2 ? void 0 : _e$row2.data.fileItem) || null; this._onFocusedItemChanged({ item: fileSystemItem, itemKey: null === fileSystemItem || void 0 === fileSystemItem ? void 0 : fileSystemItem.key, itemElement: e.rowElement }) } _onFilesViewOptionChanged(_ref6) { let { fullName: fullName } = _ref6; if (fullName.indexOf("sortOrder") > -1) { var _this$_filesView5; null === (_this$_filesView5 = this._filesView) || void 0 === _this$_filesView5 || _this$_filesView5.columnOption("isParentFolder", { sortOrder: "asc", sortIndex: 0 }) } } _resetFocus() { this._setFocusedItemKey(void 0) } _createThumbnailColumnCell(container, cellInfo) { var _this$_getItemThumbna; null === (_this$_getItemThumbna = this._getItemThumbnailContainer(cellInfo.data)) || void 0 === _this$_getItemThumbna || _this$_getItemThumbna.appendTo(container) } _createNameColumnCell(container, cellInfo) { const $button = $("<div>"); const $name = $("<span>").text(cellInfo.data.fileItem.name).addClass("dx-filemanager-details-item-name"); const $wrapper = $("<div>").append($name, $button).addClass("dx-filemanager-details-item-name-wrapper"); $(container).append($wrapper); this._createComponent($button, FileManagerFileActionsButton, { onClick: e => this._onFileItemActionButtonClick(e) }) } _calculateSizeColumnCellValue(rowData) { return rowData.fileItem.isDirectory ? "" : getDisplayFileSize(rowData.fileItem.size) } _selectItem(fileItemInfo) { const selectItemFunc = this._isMultipleSelectionMode() ? this._selectItemMultipleSelection : this._selectItemSingleSelection; selectItemFunc.call(this, fileItemInfo) } _deselectItem(item) { var _this$_filesView6; null === (_this$_filesView6 = this._filesView) || void 0 === _this$_filesView6 || _this$_filesView6.deselectRows([item.fileItem.key]) } _selectItemSingleSelection(fileItemInfo) { if (!this._focusedItem || !fileItemInfo || this._focusedItem.fileItem.key !== fileItemInfo.fileItem.key) { const oldFocusedItem = this._focusedItem; this._focusedItem = fileItemInfo; const deselectedKeys = []; if (oldFocusedItem) { deselectedKeys.push(oldFocusedItem.fileItem.key) } const selectedItems = []; const selectedKeys = []; if (fileItemInfo && !this._isParentDirectoryItem(fileItemInfo)) { selectedItems.push(fileItemInfo.fileItem); selectedKeys.push(fileItemInfo.fileItem.key) } this._raiseSelectionChanged({ selectedItems: selectedItems, selectedItemKeys: selectedKeys, currentSelectedItemKeys: [...selectedKeys], currentDeselectedItemKeys: deselectedKeys }) } } _selectItemMultipleSelection(_ref7) { var _this$_filesView7; let { fileItem: fileItem } = _ref7; if (!(null !== (_this$_filesView7 = this._filesView) && void 0 !== _this$_filesView7 && _this$_filesView7.isRowSelected(fileItem.key))) { var _this$_filesView8, _this$_filesView9; const selectionController = null === (_this$_filesView8 = this._filesView) || void 0 === _this$_filesView8 ? void 0 : _this$_filesView8.getController("selection"); const preserve = selectionController.isSelectionWithCheckboxes(); null === (_this$_filesView9 = this._filesView) || void 0 === _this$_filesView9 || _this$_filesView9.selectRows([fileItem.key], preserve) } } _setSelectedItemKeys(itemKeys) { var _this$_filesView0; null === (_this$_filesView0 = this._filesView) || void 0 === _this$_filesView0 || _this$_filesView0.option("selectedRowKeys", itemKeys) } _setFocusedItemKey(itemKey) { var _this$_filesView1; null === (_this$_filesView1 = this._filesView) || void 0 === _this$_filesView1 || _this$_filesView1.option("focusedRowKey", itemKey) } clearSelection() { if (this._isMultipleSelectionMode()) { var _this$_filesView10; null === (_this$_filesView10 = this._filesView) || void 0 === _this$_filesView10 || _this$_filesView10.clearSelection() } else { var _this$_filesView11; null === (_this$_filesView11 = this._filesView) || void 0 === _this$_filesView11 || _this$_filesView11.option("focusedRowIndex", -1) } } refresh(options, operation) { var _this$_filesView12, _this$_refreshDeferre; const actualOptions = { dataSource: this._createDataSource() }; if (options && Object.prototype.hasOwnProperty.call(options, "focusedItemKey")) { if (isDefined(options.focusedItemKey)) { actualOptions.focusedRowKey = options.focusedItemKey } else { actualOptions.focusedRowIndex = -1 } } const hasNoScrollTarget = !isDefined(actualOptions.focusedRowKey) && -1 === actualOptions.focusedRowIndex; if (hasNoScrollTarget && operation === OPERATIONS.NAVIGATION) { actualOptions.paging = { pageIndex: 0 }; this._needResetScrollPosition = true } null === (_this$_filesView12 = this._filesView) || void 0 === _this$_filesView12 || _this$_filesView12.option(actualOptions); this._refreshDeferred = new Deferred; return null === (_this$_refreshDeferre = this._refreshDeferred) || void 0 === _this$_refreshDeferre ? void 0 : _this$_refreshDeferre.promise() } _getScrollable() { var _this$_filesView13; return null === (_this$_filesView13 = this._filesView) || void 0 === _this$_filesView13 ? void 0 : _this$_filesView13.getScrollable() } getSelectedItems() { if (this._isMultipleSelectionMode()) { var _this$_filesView14; return null === (_this$_filesView14 = this._filesView) || void 0 === _this$_filesView14 ? void 0 : _this$_filesView14.getSelectedRowsData() } return this._focusedItem && !this._isParentDirectoryItem(this._focusedItem) ? [this._focusedItem] : [] } } export default FileManagerDetailsItemList;