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' ;
2019-01-16 09:45:46 +00:00
import { siteRoot , gettext , thumbnailSizeForOriginal } from '../../utils/constants' ;
import { Utils } from '../../utils/utils' ;
2018-10-25 05:36:06 +00:00
import Loading from '../loading' ;
2018-10-13 09:07:54 +00:00
import DirentListItem from './dirent-list-item' ;
2018-12-19 03:41:45 +00:00
import ModalPortal from '../modal-portal' ;
import CreateFile from '../../components/dialog/create-file-dialog' ;
2019-01-16 09:45:46 +00:00
import Lightbox from 'react-image-lightbox' ;
import 'react-image-lightbox/style.css' ;
2018-12-19 03:41:45 +00:00
import '../../css/tip-for-new-md.css' ;
2019-01-25 07:44:04 +00:00
import toaster from '../toast' ;
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 ,
2019-01-16 09:45:46 +00:00
repoEncrypted : PropTypes . bool . isRequired ,
2018-11-28 04:41:49 +00:00
isRepoOwner : PropTypes . bool ,
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 ,
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-10-25 05:36:06 +00:00
onItemDetails : PropTypes . func . isRequired ,
2018-11-22 03:26:00 +00:00
updateDirent : PropTypes . func . isRequired ,
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 ,
2018-12-19 03:41:45 +00:00
isCreateFileDialogShow : false ,
fileType : ''
2018-10-13 09:07:54 +00:00
} ;
}
2018-10-25 05:36:06 +00:00
onFreezedItem = ( ) => {
2018-10-13 09:07:54 +00:00
this . setState ( { isItemFreezed : true } ) ;
}
2018-11-22 03:26:00 +00:00
2018-10-25 05:36:06 +00:00
onUnfreezedItem = ( ) => {
2018-10-13 09:07:54 +00:00
this . setState ( { isItemFreezed : false } ) ;
}
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 ) ;
}
2018-11-23 12:19:42 +00:00
onItemRenameToggle = ( ) => {
2018-10-25 05:36:06 +00:00
this . onFreezedItem ( ) ;
2018-10-13 09:07:54 +00:00
}
2018-11-29 09:55:14 +00:00
onItemDetails = ( dirent ) => {
this . props . onItemDetails ( dirent ) ;
2018-10-25 05:36:06 +00:00
}
2018-12-19 03:41:45 +00:00
onCreateFileToggle = ( ) => {
this . setState ( {
isCreateFileDialogShow : ! this . state . isCreateFileDialogShow ,
fileType : ''
} ) ;
}
onCreateMarkdownToggle = ( ) => {
this . setState ( {
isCreateFileDialogShow : ! this . state . isCreateFileDialogShow ,
fileType : '.md'
} ) ;
}
onAddFile = ( filePath , isDraft ) => {
this . setState ( { isCreateFileDialogShow : false } ) ;
this . props . onAddFile ( filePath , isDraft ) ;
}
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 ) ;
}
sortByTime = ( e ) => {
e . preventDefault ( ) ;
const sortBy = 'time' ;
const sortOrder = this . props . sortOrder == 'asc' ? 'desc' : 'asc' ;
this . props . sortItems ( sortBy , sortOrder ) ;
}
2019-01-16 09:45:46 +00:00
// for image popup
prepareImageItems = ( ) => {
let items = this . props . direntList . filter ( ( item ) => {
return Utils . imageCheck ( item . name ) ;
} ) ;
const useThumbnail = ! this . props . repoEncrypted ;
let prepareItem = ( item ) => {
const name = item . name ;
const fileExt = name . substr ( name . lastIndexOf ( '.' ) + 1 ) . toLowerCase ( ) ;
const isGIF = fileExt == 'gif' ;
const path = Utils . encodePath ( Utils . joinPath ( this . props . path , name ) ) ;
const repoID = this . props . repoID ;
let src ;
if ( useThumbnail && ! isGIF ) {
src = ` ${ siteRoot } thumbnail/ ${ repoID } / ${ thumbnailSizeForOriginal } ${ path } ` ;
} else {
src = ` ${ siteRoot } repo/ ${ repoID } /raw ${ path } ` ;
}
return {
'name' : name ,
'url' : ` ${ siteRoot } lib/ ${ repoID } /file ${ path } ` ,
'src' : src
} ;
}
return items . map ( ( item ) => { return prepareItem ( item ) ; } ) ;
}
showImagePopup = ( dirent ) => {
let items = this . props . direntList . filter ( ( item ) => {
return Utils . imageCheck ( item . name ) ;
} ) ;
this . setState ( {
isImagePopupOpen : true ,
imageItems : this . prepareImageItems ( ) ,
imageIndex : items . indexOf ( dirent )
} ) ;
}
moveToPrevImage = ( ) => {
const imageItemsLength = this . state . imageItems . length ;
this . setState ( ( prevState ) => ( {
imageIndex : ( prevState . imageIndex + imageItemsLength - 1 ) % imageItemsLength
} ) ) ;
}
moveToNextImage = ( ) => {
const imageItemsLength = this . state . imageItems . length ;
this . setState ( ( prevState ) => ( {
imageIndex : ( prevState . imageIndex + 1 ) % imageItemsLength
} ) ) ;
}
closeImagePopup = ( ) => {
this . setState ( {
isImagePopupOpen : false
} ) ;
}
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 ;
}
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 / > ) ;
}
2018-12-19 03:41:45 +00:00
if ( this . props . path == '/' && ! direntList . length ) {
return (
< Fragment >
< div className = "tip-for-new-md d-flex" >
< button className = "big-new-md-button" onClick = { this . onCreateMarkdownToggle } > < span className = "sf2-icon-plus add-md-icon" > < /span><br / > { gettext ( 'Markdown Document' ) } < / b u t t o n >
< p > { gettext ( 'You can create online document using Markdown format easily. When creating a document, you can mark it as draft. After finishing the draft, you can ask others to review it. They can view the document history in the review page and leave comments on the document.' ) } < / p >
< / d i v >
{ this . state . isCreateFileDialogShow && (
< ModalPortal >
< CreateFile
parentPath = { this . props . path }
fileType = { this . state . fileType }
onAddFile = { this . onAddFile }
2019-01-31 03:32:10 +00:00
checkDuplicatedName = { this . checkDuplicatedName }
2018-12-19 03:41:45 +00:00
addFileCancel = { this . onCreateFileToggle }
/ >
< / M o d a l P o r t a l >
) }
< / F r a g m e n t >
) ;
}
2019-01-04 07:06:27 +00:00
// sort
const sortByName = sortBy == 'name' ;
const sortByTime = sortBy == 'time' ;
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-01-16 09:45:46 +00:00
// for image popup
const imageItems = this . state . imageItems ;
const imageIndex = this . state . imageIndex ;
const imageItemsLength = imageItems . length ;
const imageCaption = imageItemsLength && (
< Fragment >
< span > { gettext ( "%curr% of %total%" ) . replace ( '%curr%' , imageIndex + 1 ) . replace ( '%total%' , imageItemsLength ) } < / s p a n >
< br / >
< a href = { imageItems [ imageIndex ] . url } target = "_blank" > { gettext ( "Open in New Tab" ) } < / a >
< / F r a g m e n t >
) ;
2018-10-13 09:07:54 +00:00
return (
2019-01-16 09:45:46 +00:00
< Fragment >
2018-11-23 12:19:42 +00:00
< table >
< thead >
< tr >
2018-12-28 03:12:24 +00:00
< th width = "3%" className = "text-center" >
2018-11-23 12:19:42 +00:00
< input type = "checkbox" className = "vam" onChange = { this . props . onAllItemSelected } checked = { this . props . isAllItemSelected } / >
< / t h >
2018-12-17 08:52:04 +00:00
< th width = "3%" > { /*icon */ } < / t h >
< th width = "5%" > { /*star */ } < / t h >
2019-01-04 07:06:27 +00:00
< th width = "39%" > < a className = "d-block table-sort-op" href = "#" onClick = { this . sortByName } > { gettext ( 'Name' ) } { sortByName && sortIcon } < / a > < / t h >
2018-12-17 08:52:04 +00:00
< th width = "6%" > { /*tag */ } < / t h >
< th width = "20%" > { /*operation */ } < / t h >
2018-11-23 12:19:42 +00:00
< th width = "11%" > { gettext ( 'Size' ) } < / t h >
2019-01-04 07:06:27 +00:00
< th width = "13%" > < a className = "d-block table-sort-op" href = "#" onClick = { this . sortByTime } > { gettext ( 'Last Update' ) } { sortByTime && sortIcon } < / a > < / t h >
2018-11-23 12:19:42 +00:00
< / t r >
< / t h e a d >
< tbody >
{
direntList . length !== 0 && direntList . map ( ( dirent , index ) => {
return (
< DirentListItem
key = { index }
dirent = { dirent }
path = { this . props . path }
2018-11-28 04:41:49 +00:00
repoID = { this . props . repoID }
2018-12-18 09:21:01 +00:00
currentRepoInfo = { this . props . currentRepoInfo }
2018-11-23 12:19:42 +00:00
isRepoOwner = { this . props . isRepoOwner }
2019-01-25 07:44:04 +00:00
direntList = { this . props . direntList }
2018-11-23 12:19:42 +00:00
onItemClick = { this . props . onItemClick }
onItemRenameToggle = { this . onItemRenameToggle }
onItemSelected = { this . props . onItemSelected }
onItemDelete = { this . props . onItemDelete }
2019-01-25 07:44:04 +00:00
onItemRename = { this . onItemRename }
2018-11-27 06:47:19 +00:00
onItemMove = { this . props . onItemMove }
onItemCopy = { this . props . onItemCopy }
2018-11-23 12:19:42 +00:00
updateDirent = { this . props . updateDirent }
isItemFreezed = { this . state . isItemFreezed }
onFreezedItem = { this . onFreezedItem }
onUnfreezedItem = { this . onUnfreezedItem }
2019-01-17 09:05:08 +00:00
onDirentClick = { this . props . onDirentClick }
2018-11-23 12:19:42 +00:00
onItemDetails = { this . onItemDetails }
2019-01-16 09:45:46 +00:00
showImagePopup = { this . showImagePopup }
2019-01-29 02:06:26 +00:00
repoEncrypted = { this . props . repoEncrypted }
enableDirPrivateShare = { this . props . enableDirPrivateShare }
isAdmin = { this . props . isAdmin }
isGroupOwnedRepo = { this . props . isGroupOwnedRepo }
2018-11-23 12:19:42 +00:00
/ >
) ;
} )
}
< / t b o d y >
< / t a b l e >
2019-01-16 09:45:46 +00:00
{ this . state . isImagePopupOpen && (
< Lightbox
mainSrc = { imageItems [ imageIndex ] . src }
imageTitle = { imageItems [ imageIndex ] . name }
imageCaption = { imageCaption }
nextSrc = { imageItems [ ( imageIndex + 1 ) % imageItemsLength ] . src }
prevSrc = { imageItems [ ( imageIndex + imageItemsLength - 1 ) % imageItemsLength ] . src }
onCloseRequest = { this . closeImagePopup }
onMovePrevRequest = { this . moveToPrevImage }
onMoveNextRequest = { this . moveToNextImage }
2019-01-19 04:15:26 +00:00
imagePadding = { 70 }
2019-01-16 09:45:46 +00:00
imageLoadErrorMessage = { gettext ( 'The image could not be loaded.' ) }
prevLabel = { gettext ( "Previous (Left arrow key)" ) }
nextLabel = { gettext ( "Next (Right arrow key)" ) }
closeLabel = { gettext ( "Close (Esc)" ) }
zoomInLabel = { gettext ( 'Zoom in' ) }
zoomOutLabel = { gettext ( 'Zoom out' ) }
/ >
) }
< / F r a g m e n t >
2018-10-13 09:07:54 +00:00
) ;
}
}
DirentListView . propTypes = propTypes ;
export default DirentListView ;