2018-12-19 03:41:45 +00:00
import React , { Fragment } from 'react' ;
2018-10-13 09:07:54 +00:00
import PropTypes from 'prop-types' ;
2023-09-20 03:13:34 +00:00
import { siteRoot , gettext , username , enableSeadoc } from '../../utils/constants' ;
2019-01-16 09:45:46 +00:00
import { Utils } from '../../utils/utils' ;
2019-04-11 13:04:47 +00:00
import TextTranslation from '../../utils/text-translation' ;
import URLDecorator from '../../utils/url-decorator' ;
2018-10-25 05:36:06 +00:00
import Loading from '../loading' ;
2019-01-25 07:44:04 +00:00
import toaster from '../toast' ;
2019-04-11 13:04:47 +00:00
import ModalPortal from '../modal-portal' ;
import CreateFile from '../dialog/create-file-dialog' ;
import CreateFolder from '../dialog/create-folder-dialog' ;
import ImageDialog from '../dialog/image-dialog' ;
import ZipDownloadDialog from '../dialog/zip-download-dialog' ;
import MoveDirentDialog from '../dialog/move-dirent-dialog' ;
import CopyDirentDialog from '../dialog/copy-dirent-dialog' ;
import DirentListItem from './dirent-list-item' ;
import ContextMenu from '../context-menu/context-menu' ;
import { hideMenu , showMenu } from '../context-menu/actions' ;
2019-07-26 06:55:09 +00:00
import DirentsDraggedPreview from '../draggable/dirents-dragged-preview' ;
2018-10-13 09:07:54 +00:00
const propTypes = {
2018-11-22 03:26:00 +00:00
path : PropTypes . string . isRequired ,
2018-11-28 04:41:49 +00:00
repoID : PropTypes . string . isRequired ,
2018-12-18 09:21:01 +00:00
currentRepoInfo : PropTypes . object ,
2018-11-28 04:41:49 +00:00
isAllItemSelected : PropTypes . bool . isRequired ,
isDirentListLoading : PropTypes . bool . isRequired ,
2018-10-13 09:07:54 +00:00
direntList : PropTypes . array . isRequired ,
2019-01-04 09:15:15 +00:00
sortBy : PropTypes . string . isRequired ,
sortOrder : PropTypes . string . isRequired ,
sortItems : PropTypes . func . isRequired ,
2018-12-19 03:41:45 +00:00
onAddFile : PropTypes . func . isRequired ,
2019-04-11 13:04:47 +00:00
onAddFolder : PropTypes . func . isRequired ,
2018-10-13 09:07:54 +00:00
onItemDelete : PropTypes . func . isRequired ,
2018-11-23 12:19:42 +00:00
onAllItemSelected : PropTypes . func . isRequired ,
onItemSelected : PropTypes . func . isRequired ,
2018-10-25 05:36:06 +00:00
onItemRename : PropTypes . func . isRequired ,
2018-10-13 09:07:54 +00:00
onItemClick : PropTypes . func . isRequired ,
2018-11-27 06:47:19 +00:00
onItemMove : PropTypes . func . isRequired ,
onItemCopy : PropTypes . func . isRequired ,
2019-01-17 09:05:08 +00:00
onDirentClick : PropTypes . func . isRequired ,
2018-11-22 03:26:00 +00:00
updateDirent : PropTypes . func . isRequired ,
2019-04-11 13:04:47 +00:00
selectedDirentList : PropTypes . array . isRequired ,
onItemsMove : PropTypes . func . isRequired ,
onItemsCopy : PropTypes . func . isRequired ,
2023-09-14 06:36:58 +00:00
onItemConvert : PropTypes . func . isRequired ,
2019-04-11 13:04:47 +00:00
onItemsDelete : PropTypes . func . isRequired ,
2024-02-02 12:52:58 +00:00
repoTags : PropTypes . array . isRequired ,
2019-04-17 02:48:44 +00:00
onFileTagChanged : PropTypes . func ,
2019-05-14 02:15:09 +00:00
enableDirPrivateShare : PropTypes . bool . isRequired ,
isGroupOwnedRepo : PropTypes . bool . isRequired ,
2019-06-24 03:28:25 +00:00
userPerm : PropTypes . string ,
2019-05-29 04:02:07 +00:00
showDirentDetail : PropTypes . func . isRequired ,
2023-05-18 09:46:59 +00:00
loadDirentList : PropTypes . func ,
2023-09-13 00:40:50 +00:00
fullDirentList : PropTypes . array ,
posX : PropTypes . string ,
posY : PropTypes . string ,
2018-10-13 09:07:54 +00:00
} ;
class DirentListView extends React . Component {
constructor ( props ) {
super ( props ) ;
this . state = {
isItemFreezed : false ,
2019-01-16 09:45:46 +00:00
isImagePopupOpen : false ,
imageItems : [ ] ,
imageIndex : 0 ,
2019-04-08 03:35:46 +00:00
fileType : '' ,
2019-04-11 13:04:47 +00:00
isCreateFileDialogShow : false ,
isCreateFolderDialogShow : false ,
isMoveDialogShow : false ,
isCopyDialogShow : false ,
isProgressDialogShow : false ,
2019-09-09 05:46:28 +00:00
downloadItems : [ ] ,
2019-04-11 13:04:47 +00:00
isMutipleOperation : true ,
2019-04-13 02:45:11 +00:00
activeDirent : null ,
2019-05-05 09:20:37 +00:00
isListDropTipShow : false ,
2019-07-26 06:55:09 +00:00
isShowDirentsDraggablePreview : false ,
2018-10-13 09:07:54 +00:00
} ;
2019-02-27 05:53:36 +00:00
2019-06-21 10:35:11 +00:00
this . enteredCounter = 0 ; // Determine whether to enter the child element to avoid dragging bubbling bugs。
2019-02-27 05:53:36 +00:00
this . isRepoOwner = props . currentRepoInfo . owner _email === username ;
this . isAdmin = props . currentRepoInfo . is _admin ;
this . repoEncrypted = props . currentRepoInfo . encrypted ;
2018-10-13 09:07:54 +00:00
2019-04-11 13:04:47 +00:00
this . clickedDirent = null ;
this . direntItems = [ ] ;
this . currentItemRef = null ;
2019-04-08 03:35:46 +00:00
2019-04-11 13:04:47 +00:00
this . zipToken = null ;
2021-09-13 02:37:07 +00:00
const { userPerm } = props ;
this . canDrop = userPerm === 'rw' ;
const { isCustomPermission , customPermission } = Utils . getUserPermission ( userPerm ) ;
if ( isCustomPermission ) {
const { modify } = customPermission . permission ;
this . canDrop = modify ;
}
2019-04-08 03:35:46 +00:00
}
2019-04-22 04:18:35 +00:00
freezeItem = ( ) => {
2018-10-13 09:07:54 +00:00
this . setState ( { isItemFreezed : true } ) ;
2023-09-13 00:40:50 +00:00
} ;
2018-11-22 03:26:00 +00:00
2019-04-22 04:18:35 +00:00
unfreezeItem = ( ) => {
2018-10-13 09:07:54 +00:00
this . setState ( { isItemFreezed : false } ) ;
2023-09-13 00:40:50 +00:00
} ;
2018-10-13 09:07:54 +00:00
2019-01-25 07:44:04 +00:00
onItemRename = ( dirent , newName ) => {
let isDuplicated = this . props . direntList . some ( item => {
return item . name === newName ;
} ) ;
if ( isDuplicated ) {
2019-01-29 03:32:54 +00:00
let errMessage = gettext ( 'The name "{name}" is already taken. Please choose a different name.' ) ;
2019-01-25 07:44:04 +00:00
errMessage = errMessage . replace ( '{name}' , Utils . HTMLescape ( newName ) ) ;
toaster . danger ( errMessage ) ;
return false ;
}
this . props . onItemRename ( dirent , newName ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-01-25 07:44:04 +00:00
2018-11-23 12:19:42 +00:00
onItemRenameToggle = ( ) => {
2019-04-22 04:18:35 +00:00
this . freezeItem ( ) ;
2023-09-13 00:40:50 +00:00
} ;
2018-10-13 09:07:54 +00:00
2019-04-13 02:45:11 +00:00
onItemSelected = ( dirent ) => {
this . setState ( { activeDirent : null } ) ;
this . props . onItemSelected ( dirent ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-13 02:45:11 +00:00
onDirentClick = ( dirent ) => {
2023-05-18 09:46:59 +00:00
hideMenu ( ) ;
2019-04-13 02:45:11 +00:00
if ( this . props . selectedDirentList . length > 0 && ! this . state . activeDirent ) {
return ;
}
this . setState ( { activeDirent : dirent } ) ;
this . props . onDirentClick ( dirent ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-13 02:45:11 +00:00
2019-01-04 07:06:27 +00:00
sortByName = ( e ) => {
e . preventDefault ( ) ;
const sortBy = 'name' ;
const sortOrder = this . props . sortOrder == 'asc' ? 'desc' : 'asc' ;
this . props . sortItems ( sortBy , sortOrder ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-01-04 07:06:27 +00:00
sortByTime = ( e ) => {
e . preventDefault ( ) ;
const sortBy = 'time' ;
const sortOrder = this . props . sortOrder == 'asc' ? 'desc' : 'asc' ;
this . props . sortItems ( sortBy , sortOrder ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-01-04 07:06:27 +00:00
2019-05-29 05:57:12 +00:00
sortBySize = ( e ) => {
e . preventDefault ( ) ;
const sortBy = 'size' ;
const sortOrder = this . props . sortOrder == 'asc' ? 'desc' : 'asc' ;
this . props . sortItems ( sortBy , sortOrder ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-05-29 05:57:12 +00:00
2019-01-16 09:45:46 +00:00
// for image popup
2019-04-09 09:24:44 +00:00
prepareImageItem = ( item ) => {
const name = item . name ;
const repoID = this . props . repoID ;
2023-09-11 09:19:17 +00:00
const path = Utils . encodePath ( Utils . joinPath ( this . props . path , name ) ) ;
const src = ` ${ siteRoot } repo/ ${ repoID } /raw ${ path } ` ;
2019-01-16 09:45:46 +00:00
2019-04-09 09:24:44 +00:00
return {
'name' : name ,
'url' : ` ${ siteRoot } lib/ ${ repoID } /file ${ path } ` ,
'src' : src
} ;
2023-09-13 00:40:50 +00:00
} ;
2019-01-16 09:45:46 +00:00
2019-04-09 09:24:44 +00:00
showImagePopup = ( curItem ) => {
2021-06-16 10:02:48 +00:00
let items = this . props . fullDirentList . filter ( ( item ) => {
2019-01-16 09:45:46 +00:00
return Utils . imageCheck ( item . name ) ;
} ) ;
2019-04-09 09:24:44 +00:00
const imageItems = items . map ( ( item ) => {
return this . prepareImageItem ( item ) ;
} ) ;
2019-01-16 09:45:46 +00:00
this . setState ( {
isImagePopupOpen : true ,
2019-04-09 09:24:44 +00:00
imageItems : imageItems ,
imageIndex : items . indexOf ( curItem )
2019-01-16 09:45:46 +00:00
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-01-16 09:45:46 +00:00
moveToPrevImage = ( ) => {
const imageItemsLength = this . state . imageItems . length ;
this . setState ( ( prevState ) => ( {
imageIndex : ( prevState . imageIndex + imageItemsLength - 1 ) % imageItemsLength
} ) ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-01-16 09:45:46 +00:00
moveToNextImage = ( ) => {
const imageItemsLength = this . state . imageItems . length ;
this . setState ( ( prevState ) => ( {
imageIndex : ( prevState . imageIndex + 1 ) % imageItemsLength
} ) ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-01-16 09:45:46 +00:00
closeImagePopup = ( ) => {
2019-04-12 12:21:54 +00:00
this . setState ( { isImagePopupOpen : false } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-01-16 09:45:46 +00:00
2023-09-20 03:13:34 +00:00
onCreateFileToggle = ( fileType ) => {
this . setState ( {
isCreateFileDialogShow : ! this . state . isCreateFileDialogShow ,
fileType : fileType || ''
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
onCreateFolderToggle = ( ) => {
this . setState ( { isCreateFolderDialogShow : ! this . state . isCreateFolderDialogShow } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
onAddFolder = ( dirPath ) => {
this . setState ( { isCreateFolderDialogShow : false } ) ;
this . props . onAddFolder ( dirPath ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
2019-01-31 03:32:10 +00:00
checkDuplicatedName = ( newName ) => {
let direntList = this . props . direntList ;
let isDuplicated = direntList . some ( object => {
return object . name === newName ;
} ) ;
return isDuplicated ;
2023-09-13 00:40:50 +00:00
} ;
2019-01-31 03:32:10 +00:00
2019-04-11 13:04:47 +00:00
onMoveToggle = ( ) => {
this . setState ( { isMoveDialogShow : ! this . state . isMoveDialogShow } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
onCopyToggle = ( ) => {
this . setState ( { isCopyDialogShow : ! this . state . isCopyDialogShow } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
onItemsDownload = ( ) => {
let { path , repoID , selectedDirentList } = this . props ;
if ( selectedDirentList . length ) {
if ( selectedDirentList . length === 1 && ! selectedDirentList [ 0 ] . isDir ( ) ) {
let direntPath = Utils . joinPath ( path , selectedDirentList [ 0 ] . name ) ;
let url = URLDecorator . getUrl ( { type : 'download_file_url' , repoID : repoID , filePath : direntPath } ) ;
location . href = url ;
return ;
}
2019-09-09 05:46:28 +00:00
2019-04-11 13:04:47 +00:00
let selectedDirentNames = selectedDirentList . map ( dirent => {
return dirent . name ;
} ) ;
2019-09-09 05:46:28 +00:00
this . setState ( {
2020-11-02 05:56:35 +00:00
isProgressDialogShow : true ,
2019-09-09 05:46:28 +00:00
downloadItems : selectedDirentNames
2019-04-11 13:04:47 +00:00
} ) ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
2019-09-09 05:46:28 +00:00
onCloseZipDownloadDialog = ( ) => {
this . setState ( { isProgressDialogShow : false } ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
// common contextmenu handle
onMouseDown = ( event ) => {
if ( event . button === 2 ) {
2024-02-23 08:21:51 +00:00
event . stopPropagation ( ) ;
2019-04-11 13:04:47 +00:00
return ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
handleContextClick = ( event , id , menuList , currentObject = null ) => {
event . preventDefault ( ) ;
event . stopPropagation ( ) ;
let x = event . clientX || ( event . touches && event . touches [ 0 ] . pageX ) ;
let y = event . clientY || ( event . touches && event . touches [ 0 ] . pageY ) ;
if ( this . props . posX ) {
2019-05-14 02:15:09 +00:00
x -= this . props . posX ;
2019-04-11 13:04:47 +00:00
}
if ( this . props . posY ) {
2019-05-14 02:15:09 +00:00
y -= this . props . posY ;
2019-04-11 13:04:47 +00:00
}
hideMenu ( ) ;
let showMenuConfig = {
id : id ,
position : { x , y } ,
target : event . target ,
currentObject : currentObject ,
menuList : menuList ,
} ;
2019-06-21 06:22:45 +00:00
if ( menuList . length === 0 ) {
return ;
}
2019-04-11 13:04:47 +00:00
showMenu ( showMenuConfig ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
// table-container contextmenu handle
2019-04-13 05:35:33 +00:00
onContainerClick = ( ) => {
2023-05-18 09:46:59 +00:00
hideMenu ( ) ;
2019-04-13 05:35:33 +00:00
if ( this . state . activeDirent ) {
this . onDirentClick ( null ) ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-04-13 05:35:33 +00:00
2019-04-11 13:04:47 +00:00
onContainerMouseDown = ( event ) => {
this . onMouseDown ( event ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
onContainerContextMenu = ( event ) => {
2019-06-24 03:28:25 +00:00
event . preventDefault ( ) ;
// Display menu items based on the permissions of the current path
let permission = this . props . userPerm ;
2021-09-13 02:37:07 +00:00
const { isCustomPermission , customPermission } = Utils . getUserPermission ( this . props . userPerm ) ;
if ( permission !== 'admin' && permission !== 'rw' && ! isCustomPermission ) {
2019-06-24 03:28:25 +00:00
return ;
}
2023-09-20 03:13:34 +00:00
const {
NEW _FOLDER , NEW _FILE ,
NEW _MARKDOWN _FILE ,
NEW _EXCEL _FILE ,
NEW _POWERPOINT _FILE ,
NEW _WORD _FILE ,
NEW _SEADOC _FILE
} = TextTranslation ;
const direntsContainerMenuList = [
NEW _FOLDER , NEW _FILE , 'Divider' ,
NEW _MARKDOWN _FILE ,
NEW _EXCEL _FILE ,
NEW _POWERPOINT _FILE ,
NEW _WORD _FILE
] ;
if ( enableSeadoc ) {
direntsContainerMenuList . push ( NEW _SEADOC _FILE ) ;
}
2019-04-11 13:04:47 +00:00
if ( this . props . selectedDirentList . length === 0 ) {
2019-05-14 02:15:09 +00:00
let id = 'dirent-container-menu' ;
2022-11-08 14:35:41 +00:00
2021-09-13 02:37:07 +00:00
// custom permission judgement
if ( isCustomPermission ) {
2022-11-08 14:35:41 +00:00
const { create : canCreate } = customPermission . permission ;
if ( ! canCreate ) return ;
2021-09-13 02:37:07 +00:00
}
2023-09-20 03:13:34 +00:00
let menuList = direntsContainerMenuList ;
2019-04-11 13:04:47 +00:00
this . handleContextClick ( event , id , menuList ) ;
} else {
if ( this . props . selectedDirentList . length === 1 ) {
2019-04-13 02:45:11 +00:00
if ( ! this . state . activeDirent ) {
let id = 'dirent-item-menu' ;
let dirent = this . props . selectedDirentList [ 0 ] ;
let menuList = this . getDirentItemMenuList ( dirent , true ) ;
this . handleContextClick ( event , id , menuList , dirent ) ;
} else {
this . onDirentClick ( null ) ;
event . preventDefault ( ) ;
event . persist ( ) ;
2021-09-13 02:37:07 +00:00
// custom permission judgement
if ( isCustomPermission ) {
const { modify } = customPermission . permission ;
if ( ! modify ) return ;
}
2019-04-13 02:45:11 +00:00
setTimeout ( ( ) => {
2019-05-14 02:15:09 +00:00
let id = 'dirent-container-menu' ;
2023-09-20 03:13:34 +00:00
let menuList = direntsContainerMenuList ;
2019-04-13 02:45:11 +00:00
this . handleContextClick ( event , id , menuList ) ;
} , 0 ) ;
}
2019-04-11 13:04:47 +00:00
} else {
let id = 'dirents-menu' ;
2021-09-13 02:37:07 +00:00
let menuList = [ ] ;
if ( isCustomPermission ) {
2023-07-22 07:54:25 +00:00
const { modify : canModify , copy : canCopy , download : canDownload , delete : canDelete } = customPermission . permission ;
2021-09-13 02:37:07 +00:00
canModify && menuList . push ( TextTranslation . MOVE ) ;
canCopy && menuList . push ( TextTranslation . COPY ) ;
canDownload && menuList . push ( TextTranslation . DOWNLOAD ) ;
canDelete && menuList . push ( TextTranslation . DELETE ) ;
} else {
menuList = [ TextTranslation . MOVE , TextTranslation . COPY , TextTranslation . DOWNLOAD , TextTranslation . DELETE ] ;
}
2019-04-11 13:04:47 +00:00
this . handleContextClick ( event , id , menuList ) ;
}
}
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
onContainerMenuItemClick = ( operation ) => {
switch ( operation ) {
case 'New Folder' :
this . onCreateFolderToggle ( ) ;
break ;
case 'New File' :
this . onCreateFileToggle ( ) ;
break ;
2023-09-20 03:13:34 +00:00
case 'New Markdown File' :
this . onCreateFileToggle ( '.md' ) ;
break ;
case 'New Excel File' :
this . onCreateFileToggle ( '.xlsx' ) ;
break ;
case 'New PowerPoint File' :
this . onCreateFileToggle ( '.pptx' ) ;
break ;
case 'New Word File' :
this . onCreateFileToggle ( '.docx' ) ;
break ;
case 'New SeaDoc File' :
this . onCreateFileToggle ( '.sdoc' ) ;
break ;
2020-11-02 05:56:35 +00:00
default :
2019-04-11 13:04:47 +00:00
break ;
}
hideMenu ( ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
onDirentsMenuItemClick = ( operation ) => {
switch ( operation ) {
case 'Move' :
this . onMoveToggle ( ) ;
break ;
case 'Copy' :
this . onCopyToggle ( ) ;
break ;
case 'Download' :
this . onItemsDownload ( ) ;
break ;
case 'Delete' :
this . props . onItemsDelete ( ) ;
break ;
2020-11-02 05:56:35 +00:00
default :
2019-04-11 13:04:47 +00:00
break ;
}
hideMenu ( ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
// table-thread contextmenu handle -- Shield event
onThreadMouseDown = ( event ) => {
this . onMouseDown ( event ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
onThreadContextMenu = ( event ) => {
event . stopPropagation ( ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
// table-dirent-item contextmenu handle
onItemMouseDown = ( event ) => {
this . onMouseDown ( event ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
onItemContextMenu = ( event , dirent ) => {
2019-06-24 03:28:25 +00:00
// Display menu items according to the current dirent permission
2019-04-13 02:45:11 +00:00
if ( this . props . selectedDirentList . length > 1 ) {
return ;
}
this . onDirentClick ( dirent ) ;
2019-04-13 01:57:44 +00:00
let id = 'dirent-item-menu' ;
let menuList = this . getDirentItemMenuList ( dirent , true ) ;
this . handleContextClick ( event , id , menuList , dirent ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
setDirentItemRef = ( index ) => item => {
this . direntItems [ index ] = item ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
onMenuItemClick = ( operation , currentObject , event ) => {
let index = this . getDirentIndex ( currentObject ) ;
this . direntItems [ index ] . onMenuItemClick ( operation , event ) ;
hideMenu ( ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
onShowMenu = ( e ) => {
2019-04-22 04:18:35 +00:00
this . freezeItem ( ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
onHideMenu = ( e ) => {
2019-04-22 04:18:35 +00:00
this . unfreezeItem ( ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
// contextmenu utils
getDirentIndex = ( dirent ) => {
let direntList = this . props . direntList ;
let index = 0 ;
for ( let i = 0 ; i < direntList . length ; i ++ ) {
if ( direntList [ i ] . name === dirent . name ) {
index = i ;
break ;
}
2020-11-02 05:56:35 +00:00
}
2019-04-11 13:04:47 +00:00
return index ;
2023-09-13 00:40:50 +00:00
} ;
2019-04-11 13:04:47 +00:00
getDirentItemMenuList = ( dirent , isContextmenu ) => {
2019-09-04 06:21:57 +00:00
const isRepoOwner = this . isRepoOwner ;
const currentRepoInfo = this . props . currentRepoInfo ;
return Utils . getDirentOperationList ( isRepoOwner , currentRepoInfo , dirent , isContextmenu ) ;
2023-09-13 00:40:50 +00:00
} ;
2020-11-02 05:56:35 +00:00
2019-05-05 09:20:37 +00:00
onTableDragEnter = ( e ) => {
2021-09-13 02:37:07 +00:00
if ( Utils . isIEBrower ( ) || ! this . canDrop ) {
2019-06-04 07:59:25 +00:00
return false ;
}
2019-06-21 10:03:54 +00:00
this . enteredCounter ++ ;
if ( this . enteredCounter !== 0 ) {
2019-07-26 06:55:09 +00:00
if ( this . state . isListDropTipShow ) {
return ;
}
2019-05-05 09:20:37 +00:00
this . setState ( { isListDropTipShow : true } ) ;
}
2023-09-13 00:40:50 +00:00
} ;
2019-05-05 09:20:37 +00:00
onTableDragOver = ( e ) => {
2021-09-13 02:37:07 +00:00
if ( Utils . isIEBrower ( ) || ! this . canDrop ) {
2019-06-04 07:59:25 +00:00
return false ;
}
2019-08-09 09:04:48 +00:00
if ( e . dataTransfer . dropEffect === 'copy' ) {
return ;
}
2019-05-05 09:20:37 +00:00
e . preventDefault ( ) ;
e . dataTransfer . dropEffect = 'move' ;
2023-09-13 00:40:50 +00:00
} ;
2019-05-05 09:20:37 +00:00
onTableDragLeave = ( e ) => {
2021-09-13 02:37:07 +00:00
if ( Utils . isIEBrower ( ) || ! this . canDrop ) {
2019-06-04 07:59:25 +00:00
return false ;
}
2019-06-21 10:03:54 +00:00
this . enteredCounter -- ;
if ( this . enteredCounter === 0 ) {
2019-05-14 02:15:09 +00:00
this . setState ( { isListDropTipShow : false } ) ;
2019-05-05 09:20:37 +00:00
}
2023-09-13 00:40:50 +00:00
} ;
2019-05-05 09:20:37 +00:00
tableDrop = ( e ) => {
2021-09-13 02:37:07 +00:00
if ( Utils . isIEBrower ( ) || ! this . canDrop ) {
2019-06-04 07:59:25 +00:00
return false ;
}
2019-05-05 09:20:37 +00:00
e . persist ( ) ;
2019-06-21 10:03:54 +00:00
this . enteredCounter = 0 ;
2019-05-05 09:20:37 +00:00
this . setState ( { isListDropTipShow : false } ) ;
if ( e . dataTransfer . files . length ) { // uploaded files
return ;
}
let dragStartItemData = e . dataTransfer . getData ( 'applicaiton/drag-item-info' ) ;
dragStartItemData = JSON . parse ( dragStartItemData ) ;
let { nodeDirent , nodeParentPath , nodeRootPath } = dragStartItemData ;
2019-06-21 06:07:52 +00:00
if ( Array . isArray ( dragStartItemData ) ) { //selected items
return ;
}
2019-05-27 09:13:15 +00:00
2019-06-21 06:07:52 +00:00
if ( nodeRootPath === this . props . path || nodeParentPath === this . props . path ) {
return ;
}
2019-05-27 09:13:15 +00:00
2019-06-21 06:07:52 +00:00
if ( this . props . path . indexOf ( nodeRootPath ) !== - 1 ) {
return ;
2019-05-05 09:20:37 +00:00
}
2019-06-21 06:07:52 +00:00
this . props . onItemMove ( this . props . currentRepoInfo , nodeDirent , this . props . path , nodeParentPath ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-05-05 09:20:37 +00:00
2019-07-26 06:55:09 +00:00
onShowDirentsDraggablePreview = ( ) => {
this . setState ( {
isShowDirentsDraggablePreview : true ,
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-07-26 06:55:09 +00:00
onHideDirentsDraggablePreview = ( ) => {
this . setState ( {
isShowDirentsDraggablePreview : false
} ) ;
2023-09-13 00:40:50 +00:00
} ;
2019-07-26 06:55:09 +00:00
2018-10-13 09:07:54 +00:00
render ( ) {
2019-01-04 07:06:27 +00:00
const { direntList , sortBy , sortOrder } = this . props ;
2018-10-25 05:36:06 +00:00
if ( this . props . isDirentListLoading ) {
return ( < Loading / > ) ;
}
2019-01-04 07:06:27 +00:00
// sort
const sortByName = sortBy == 'name' ;
const sortByTime = sortBy == 'time' ;
2019-05-29 05:57:12 +00:00
const sortBySize = sortBy == 'size' ;
2019-01-04 07:06:27 +00:00
const sortIcon = sortOrder == 'asc' ? < span className = "fas fa-caret-up" > < / s p a n > : < s p a n c l a s s N a m e = " f a s f a - c a r e t - d o w n " > < / s p a n > ;
2019-08-30 10:10:48 +00:00
const isDesktop = Utils . isDesktop ( ) ;
2018-10-13 09:07:54 +00:00
return (
2020-11-02 05:56:35 +00:00
< div
2021-09-13 02:37:07 +00:00
className = { ` table-container ${ ( this . state . isListDropTipShow && this . canDrop ) ? 'table-drop-active' : '' } ` }
2020-11-02 05:56:35 +00:00
onMouseDown = { this . onContainerMouseDown }
onContextMenu = { this . onContainerContextMenu }
2019-05-05 09:20:37 +00:00
onClick = { this . onContainerClick }
onDragEnter = { this . onTableDragEnter }
onDragOver = { this . onTableDragOver }
onDragLeave = { this . onTableDragLeave }
onDrop = { this . tableDrop }
>
2019-08-30 10:10:48 +00:00
< table className = { ` table-hover ${ isDesktop ? '' : 'table-thead-hidden' } ` } >
{ isDesktop ? (
2020-11-02 05:56:35 +00:00
< thead onMouseDown = { this . onThreadMouseDown } onContextMenu = { this . onThreadContextMenu } >
< tr >
< th width = "3%" className = "pl10" >
2024-04-22 02:36:42 +00:00
< input type = "checkbox" className = "vam" onChange = { this . props . onAllItemSelected } checked = { this . props . isAllItemSelected } aria - label = { this . props . isAllItemSelected ? gettext ( 'Unselect all items' ) : gettext ( 'Select all items' ) } / >
2020-11-02 05:56:35 +00:00
< / t h >
< th width = "3%" className = "pl10" > { /*icon */ } < / t h >
< th width = "5%" className = "pl10" > { /*star */ } < / t h >
< th width = "39%" > < a className = "d-block table-sort-op" href = "#" onClick = { this . sortByName } > { gettext ( 'Name' ) } { sortByName && sortIcon } < / a > < / t h >
< th width = "6%" > { /*tag */ } < / t h >
< th width = "18%" > { /*operation */ } < / t h >
< th width = "11%" > < a className = "d-block table-sort-op" href = "#" onClick = { this . sortBySize } > { gettext ( 'Size' ) } { sortBySize && sortIcon } < / a > < / t h >
< th width = "15%" > < a className = "d-block table-sort-op" href = "#" onClick = { this . sortByTime } > { gettext ( 'Last Update' ) } { sortByTime && sortIcon } < / a > < / t h >
< / t r >
< / t h e a d >
2019-08-30 10:10:48 +00:00
) : (
< thead >
< tr >
< th width = "12%" > < / t h >
< th width = "80%" > < / t h >
< th width = "8%" > < / t h >
< / t r >
< / t h e a d >
) }
2019-01-31 09:37:02 +00:00
< tbody >
2019-04-11 13:04:47 +00:00
{ direntList . map ( ( dirent , index ) => {
return (
< DirentListItem
ref = { this . setDirentItemRef ( index ) }
key = { index }
dirent = { dirent }
path = { this . props . path }
repoID = { this . props . repoID }
currentRepoInfo = { this . props . currentRepoInfo }
isAdmin = { this . isAdmin }
isRepoOwner = { this . isRepoOwner }
repoEncrypted = { this . repoEncrypted }
enableDirPrivateShare = { this . props . enableDirPrivateShare }
isGroupOwnedRepo = { this . props . isGroupOwnedRepo }
onItemClick = { this . props . onItemClick }
onItemRenameToggle = { this . onItemRenameToggle }
2019-04-13 02:45:11 +00:00
onItemSelected = { this . onItemSelected }
2019-04-11 13:04:47 +00:00
onItemDelete = { this . props . onItemDelete }
onItemRename = { this . onItemRename }
onItemMove = { this . props . onItemMove }
onItemCopy = { this . props . onItemCopy }
2023-09-14 06:36:58 +00:00
onItemConvert = { this . props . onItemConvert }
2019-04-11 13:04:47 +00:00
updateDirent = { this . props . updateDirent }
isItemFreezed = { this . state . isItemFreezed }
2019-04-22 04:18:35 +00:00
freezeItem = { this . freezeItem }
unfreezeItem = { this . unfreezeItem }
2019-04-13 02:45:11 +00:00
onDirentClick = { this . onDirentClick }
2019-04-11 13:04:47 +00:00
showImagePopup = { this . showImagePopup }
onItemMouseDown = { this . onItemMouseDown }
onItemContextMenu = { this . onItemContextMenu }
2019-04-12 12:21:54 +00:00
selectedDirentList = { this . props . selectedDirentList }
2019-04-13 02:45:11 +00:00
activeDirent = { this . state . activeDirent }
2024-02-02 12:52:58 +00:00
repoTags = { this . props . repoTags }
2019-04-17 02:48:44 +00:00
onFileTagChanged = { this . props . onFileTagChanged }
2019-04-21 02:43:34 +00:00
getDirentItemMenuList = { this . getDirentItemMenuList }
2019-05-29 04:02:07 +00:00
showDirentDetail = { this . props . showDirentDetail }
2019-06-17 08:11:54 +00:00
onItemsMove = { this . props . onItemsMove }
2019-07-26 06:55:09 +00:00
onShowDirentsDraggablePreview = { this . onShowDirentsDraggablePreview }
2021-09-18 04:35:23 +00:00
loadDirentList = { this . props . loadDirentList }
2019-04-11 13:04:47 +00:00
/ >
) ;
} ) }
2019-01-31 09:37:02 +00:00
< / t b o d y >
< / t a b l e >
2019-04-11 13:04:47 +00:00
< Fragment >
2020-11-02 05:56:35 +00:00
< ContextMenu
2019-04-11 13:04:47 +00:00
id = { 'dirent-container-menu' }
onMenuItemClick = { this . onContainerMenuItemClick }
/ >
2020-11-02 05:56:35 +00:00
< ContextMenu
2019-04-11 13:04:47 +00:00
id = { 'dirent-item-menu' }
onMenuItemClick = { this . onMenuItemClick }
onShowMenu = { this . onShowMenu }
onHideMenu = { this . onHideMenu }
/ >
< ContextMenu
id = { 'dirents-menu' }
onMenuItemClick = { this . onDirentsMenuItemClick }
/ >
2020-11-02 05:56:35 +00:00
{ this . state . isShowDirentsDraggablePreview &&
2019-07-26 06:55:09 +00:00
< ModalPortal >
2020-11-02 05:56:35 +00:00
< DirentsDraggedPreview
2019-07-26 06:55:09 +00:00
selectedDirentList = { this . props . selectedDirentList }
onHideDirentsDraggablePreview = { this . onHideDirentsDraggablePreview }
dragStartPosition = { this . state . dragStartPosition }
/ >
< / M o d a l P o r t a l >
}
2019-04-11 13:04:47 +00:00
{ this . state . isImagePopupOpen && (
< ModalPortal >
< ImageDialog
imageItems = { this . state . imageItems }
imageIndex = { this . state . imageIndex }
closeImagePopup = { this . closeImagePopup }
moveToPrevImage = { this . moveToPrevImage }
moveToNextImage = { this . moveToNextImage }
/ >
< / M o d a l P o r t a l >
) }
{ this . state . isCreateFolderDialogShow && (
< ModalPortal >
< CreateFolder
parentPath = { this . props . path }
onAddFolder = { this . onAddFolder }
checkDuplicatedName = { this . checkDuplicatedName }
addFolderCancel = { this . onCreateFolderToggle }
/ >
< / M o d a l P o r t a l >
2020-11-02 05:56:35 +00:00
) }
2019-04-11 13:04:47 +00:00
{ this . state . isCreateFileDialogShow && (
< ModalPortal >
< CreateFile
parentPath = { this . props . path }
fileType = { this . state . fileType }
2023-07-22 07:54:25 +00:00
onAddFile = { this . props . onAddFile }
2019-04-11 13:04:47 +00:00
checkDuplicatedName = { this . checkDuplicatedName }
2023-07-22 07:54:25 +00:00
toggleDialog = { this . onCreateFileToggle }
2019-04-11 13:04:47 +00:00
/ >
< / M o d a l P o r t a l >
) }
2020-11-02 05:56:35 +00:00
{ this . state . isMoveDialogShow &&
< MoveDirentDialog
2019-04-11 13:04:47 +00:00
path = { this . props . path }
repoID = { this . props . repoID }
repoEncrypted = { this . props . currentRepoInfo . encrypted }
isMutipleOperation = { this . state . isMutipleOperation }
selectedDirentList = { this . props . selectedDirentList }
onItemsMove = { this . props . onItemsMove }
onCancelMove = { this . onMoveToggle }
2019-04-09 09:24:44 +00:00
/ >
2019-04-11 13:04:47 +00:00
}
{ this . state . isCopyDialogShow &&
< CopyDirentDialog
path = { this . props . path }
repoID = { this . props . repoID }
repoEncrypted = { this . props . currentRepoInfo . encrypted }
selectedDirentList = { this . props . selectedDirentList }
isMutipleOperation = { this . state . isMutipleOperation }
onItemsCopy = { this . props . onItemsCopy }
onCancelCopy = { this . onCopyToggle }
/ >
}
{ this . state . isProgressDialogShow &&
2020-11-02 05:56:35 +00:00
< ZipDownloadDialog
2019-09-09 05:46:28 +00:00
repoID = { this . props . repoID }
path = { this . props . path }
target = { this . state . downloadItems }
2020-11-02 05:56:35 +00:00
toggleDialog = { this . onCloseZipDownloadDialog }
2019-09-09 05:46:28 +00:00
/ >
2019-04-11 13:04:47 +00:00
}
< / F r a g m e n t >
< / d i v >
2018-10-13 09:07:54 +00:00
) ;
}
}
DirentListView . propTypes = propTypes ;
export default DirentListView ;