UNPKG

@alyzenpublic/react-keyed-file-browser

Version:

Folder based file browser given a flat keyed list of objects, powered by React.

277 lines (253 loc) 7.69 kB
import PropTypes from 'prop-types' import React from 'react' import { IMAGE_EXTENSIONS, VIDEO_EXTENSIONS, AUDIO_EXTENSIONS } from './constants.js' class BaseFile extends React.Component { static propTypes = { fileKey: PropTypes.string, url: PropTypes.string, newKey: PropTypes.string, isRenaming: PropTypes.bool, connectDragSource: PropTypes.func, connectDropTarget: PropTypes.func, isDragging: PropTypes.bool, action: PropTypes.string, browserProps: PropTypes.shape({ icons: PropTypes.object, select: PropTypes.func, beginAction: PropTypes.func, endAction: PropTypes.func, preview: PropTypes.func, createFiles: PropTypes.func, moveFile: PropTypes.func, moveFolder: PropTypes.func, renameFile: PropTypes.func, deleteFile: PropTypes.func, }), } state = { newName: this.getName(), } componentDidUpdate(oldProps, oldState) { if (!oldProps.isRenaming && this.props.isRenaming) { window.requestAnimationFrame(() => { const currentName = this.newNameRef.value const pointIndex = currentName.lastIndexOf('.') this.newNameRef.setSelectionRange(0, pointIndex || currentName.length) this.newNameRef.focus() }) } } getName() { let name = this.props.newKey || this.props.fileKey const slashIndex = name.lastIndexOf('/') if (slashIndex !== -1) { name = name.substr(slashIndex + 1) } return name } getExtension() { const blobs = this.props.fileKey.split('.') return blobs[blobs.length - 1].toLowerCase().trim() } isImage() { const extension = this.getExtension() for (let extensionIndex = 0; extensionIndex < IMAGE_EXTENSIONS.length; extensionIndex++) { const imageExtension = IMAGE_EXTENSIONS[extensionIndex] if (extension === imageExtension) { return true } } return false } isVideo() { const extension = this.getExtension() for (let extensionIndex = 0; extensionIndex < VIDEO_EXTENSIONS.length; extensionIndex++) { const videoExtension = VIDEO_EXTENSIONS[extensionIndex] if (extension === videoExtension) { return true } } return false } isAudio() { const extension = this.getExtension() for (let extensionIndex = 0; extensionIndex < AUDIO_EXTENSIONS.length; extensionIndex++) { const audioExtension = AUDIO_EXTENSIONS[extensionIndex] if (extension === audioExtension) { return true } } return false } isArchive() { return (this.getExtension() === 'zip' || this.getExtension() === 'rar' || this.getExtension() === '7z') } isExcel() { return (this.getExtension() === 'xlsx' || this.getExtension() === 'xls') } isWord() { return (this.getExtension() === 'docx' || this.getExtension() === 'doc') } isPowerPoint() { return (this.getExtension() === 'pptx' || this.getExtension() === 'ppt') } isText() { return (this.getExtension() === 'txt') } isPdf() { return (this.getExtension() === 'pdf') } handleFileClick = (event) => { event && event.preventDefault() this.props.browserProps.preview({ url: this.props.url, name: this.getName(), key: this.props.fileKey, extension: this.getExtension(), }) } handleItemClick = (event) => { event.stopPropagation() this.props.browserProps.select(this.props.fileKey, 'file') } handleItemDoubleClick = (event) => { event.stopPropagation() this.handleFileClick() } handleRenameClick = (event) => { if (!this.props.browserProps.renameFile) { return } this.props.browserProps.beginAction('rename', this.props.fileKey) } handleNewNameChange = (event) => { const newName = this.newNameRef.value this.setState({ newName: newName }) } handleRenameSubmit = (event) => { if (event) { event.preventDefault() } if (!this.props.browserProps.renameFile) { return } const newName = this.state.newName.trim() if (newName.length === 0) { // todo: move to props handler // window.notify({ // style: 'error', // title: 'Invalid new file name', // body: 'File name cannot be blank', // }) return } if (newName.indexOf('/') !== -1) { // todo: move to props handler // window.notify({ // style: 'error', // title: 'Invalid new file name', // body: 'File names cannot contain forward slashes.', // }) return } let newKey = newName const slashIndex = this.props.fileKey.lastIndexOf('/') if (slashIndex !== -1) { newKey = `${this.props.fileKey.substr(0, slashIndex)}/${newName}` } this.props.browserProps.renameFile(this.props.fileKey, newKey) } handleDeleteClick = (event) => { if (!this.props.browserProps.deleteFile) { return } this.props.browserProps.beginAction('delete', this.props.fileKey) } handleDeleteSubmit = (event) => { event.preventDefault() if (!this.props.browserProps.deleteFile) { return } this.props.browserProps.deleteFile(this.props.fileKey) } handleCancelEdit = (event) => { this.props.browserProps.endAction() } connectDND(render) { const inAction = (this.props.isDragging || this.props.action) if ( typeof this.props.browserProps.moveFile === 'function' && !inAction && !this.props.isRenaming ) { render = this.props.connectDragSource(render) } if ( typeof this.props.browserProps.createFiles === 'function' || typeof this.props.browserProps.moveFile === 'function' || typeof this.props.browserProps.moveFolder === 'function' ) { render = this.props.connectDropTarget(render) } return render } } const dragSource = { beginDrag(props) { props.browserProps.select(props.fileKey, 'file') return { key: props.fileKey, } }, endDrag(props, monitor, component) { if (!monitor.didDrop()) return const dropResult = monitor.getDropResult() const fileNameParts = props.fileKey.split('/') const fileName = fileNameParts[fileNameParts.length - 1] const newKey = `${dropResult.path}${fileName}` if (newKey !== props.fileKey && props.browserProps.renameFile) { props.browserProps.openFolder(dropResult.path) props.browserProps.renameFile(props.fileKey, newKey) } }, } function dragCollect(connect, monitor) { return { connectDragPreview: connect.dragPreview(), connectDragSource: connect.dragSource(), isDragging: monitor.isDragging(), } } const targetSource = { drop(props, monitor) { if (monitor.didDrop()) { return } const key = props.newKey || props.fileKey const slashIndex = key.lastIndexOf('/') const path = (slashIndex !== -1) ? key.substr(0, slashIndex + 1) : '' const item = monitor.getItem() if (item.files && props.browserProps.createFiles) { props.browserProps.createFiles(item.files, path) } return { path: path, } }, } function targetCollect(connect, monitor) { return { connectDropTarget: connect.dropTarget(), isOver: monitor.isOver({ shallow: true }), } } const BaseFileConnectors = { dragSource, dragCollect, targetSource, targetCollect, } export default BaseFile export { BaseFileConnectors, }