UNPKG

nexshop-web-contents

Version:

Nexshop Web Contents Project

291 lines (260 loc) 12 kB
import React, {Component} from 'react'; import PropTypes from 'prop-types'; import Divider from 'material-ui/Divider'; import {ContextMenu, ContextMenuItemView} from 'nexshop-web-elements'; import ContentsItemView from "./contents-item-view"; import FolderView from "./folder-view"; const BREADCRUMB_HEIGHT = 50; export default class ContentsView extends Component { constructor(props) { super(props); this.state = { dropping: false, contextMenuOpenPosition: {x: 0, y: 0}, type: 'folder', }; this.dragCounter = 0; this.onDragEnter = this.onDragEnter.bind(this); this.onDragLeave = this.onDragLeave.bind(this); this.onDrop = this.onDrop.bind(this); this.onPreview = this.onPreview.bind(this); this.onDelete = this.onDelete.bind(this); this.onContextMenu = this.onContextMenu.bind(this); this.getContentsScrollTop = this.getContentsScrollTop.bind(this); this.onMoveToClick = this.onMoveToClick.bind(this); this.getFolderPath = this.getFolderPath.bind(this); this.onTagToClick = this.onTagToClick.bind(this); } isValidFile(files) { return files.every(file => ['jpg', 'mp4', 'png', 'gif'].indexOf(file.name.split('.').pop().toLowerCase()) > -1); } onDragEnter(event) { event.preventDefault(); this.dragCounter++; if (this.state.dropping) return; let {dataTransfer: {types}} = event; this.setState({ dropping: types.every((type) => type === 'Files') }); } onDragLeave(event) { event.preventDefault(); this.dragCounter--; if (this.dragCounter === 0) { this.setState({ dropping: false }); } } onDrop(event) { event.preventDefault(); const {selectUploadFiles, uploadFilesAsync, openFloatingView} = this.props; const files = [...event.dataTransfer.files]; const {breadcrumb} = this.props; const currentFolderId = breadcrumb[breadcrumb.length - 1].id; this.dragCounter = 0; this.setState({ dropping: false }, () => { if (this.isValidFile(files)) { selectUploadFiles(files); uploadFilesAsync(files, currentFolderId); openFloatingView(); } }); } onPreview(contentsItemId) { this.props.onPreview(contentsItemId); } onDelete(index) { const {willBeDeletedContentsItem, openDialog} = this.props; openDialog('delete-contents-item'); willBeDeletedContentsItem(index, this.props.contents[index]); } onMoveToClick() { const {closePopup, openDialog} = this.props; openDialog('move-to'); closePopup(); } onTagToClick() { const {closePopup, openDialog} = this.props; openDialog('manage-tag'); closePopup(); } onContextMenu(e, index, type) { e.preventDefault(); this.setState({ contextMenuOpenPosition: { x: e.pageX - 40, y: e.pageY - 160 + this.getContentsScrollTop() }, index, type }); this.props.onContextMenuClicked(type, index) } getContentsScrollTop() { return this.contentWrapper ? this.contentWrapper.scrollTop : 0; } getFolderPath() { const {breadcrumb} = this.props; let folderPath = ''; breadcrumb.map((folder, index) => { folderPath = folderPath.concat(folder.name); if (index !== breadcrumb.length - 1) { folderPath = folderPath.concat(' > '); } }); return folderPath; } render() { const { contents, folders, closePopup, contextMenuVisibility, onContentsClick, onFolderItemDoubleClick, updateFolderAsync, updateFolderData, onContentItemDoubleClick, updateContentsItemAsync, updateContentsItemData, selectedContentsItemIds = [], breadcrumb, onBreadcrumbItemClick, searchOption, rename, copyToClick, } = this.props; const {dropping, contextMenuOpenPosition, type, index} = this.state; return ( <div className="contents-wrapper" ref={(el) => this.contentWrapper = el} onDragEnter={this.onDragEnter} onDragLeave={this.onDragLeave} onDrop={this.onDrop} onDragOver={(e) => { e.preventDefault() }}> <div className="contents-breadcrumb"> { (searchOption.name || searchOption.type !== 'all') ? <div className="contents-search-result"> Search result <span className="contents-search-result-count">{contents.length}</span> </div> : breadcrumb.map((item, index) => ( <div className="contents-breadcrumb-item" key={item.id}> <span onClick={() => { onBreadcrumbItemClick(item.id, index) }}>{item.name}</span> {index + 1 < breadcrumb.length && <div className="contents-breadcrumb-item-arrow"/>} </div> )) } </div> <div className="contents"> <table className="contents-table"> <thead> <tr> <th className="contents-thumbnail"/> <th className="contents-name">NAME</th> <th className="contents-tag">TAG</th> <th className="contents-in-use"/> <th className="contents-owner">OWNER</th> <th className="contents-update">UPDATE</th> <th className="contents-size">SIZE</th> <th/> </tr> </thead> <tbody> { folders.map((item, index) => ( <FolderView key={item.id} folder={item} onClick={() => onContentsClick('folder', index)} onDoubleClick={() => onFolderItemDoubleClick(item)} onContextMenu={(e) => this.onContextMenu(e, index, 'folder')} updateFolderAsync={updateFolderAsync} updateFolderData={updateFolderData} selectedContentsItemIds={selectedContentsItemIds} /> )) } { contents.map((item, index) => ( <ContentsItemView key={item.id} contentsItem={item} onClick={() => onContentsClick(item.type, index)} onDoubleClick={() => onContentItemDoubleClick(index)} onDelete={() => this.onDelete(index)} onPreview={() => this.onPreview(item.id)} onContextMenu={(e) => this.onContextMenu(e, index, item.type)} updateContentsItemAsync={updateContentsItemAsync} updateContentsItemData={updateContentsItemData} selectedContentsItemIds={selectedContentsItemIds} searchKeyword={searchOption.name} /> )) } </tbody> </table> <ContextMenu popupStyle={{top: contextMenuOpenPosition.y + 'px', left: contextMenuOpenPosition.x + 'px'}} isShow={contextMenuVisibility} onClose={closePopup} > <ContextMenuItemView key="move" text="Move To" onClick={this.onMoveToClick}/> { type !== 'folder' && [ <ContextMenuItemView key="copy" text="Make a copy" onClick={() => copyToClick(type, index)}/>, ( (type === 'video' || type === 'image') && [ <Divider key="div1" style={{marginTop: '5px', marginBottom: '5px'}}/>, <ContextMenuItemView key="tag" text="Manage Tag" onClick={this.onTagToClick}/> ] ) ] } <Divider key="div2" style={{marginTop: '5px', marginBottom: '5px'}}/> <ContextMenuItemView text="Rename" onClick={() => rename(type)}/> </ContextMenu> { dropping && <div className="contents-drop-area" style={{ top: `${this.getContentsScrollTop() <= BREADCRUMB_HEIGHT ? 0 : this.getContentsScrollTop() - BREADCRUMB_HEIGHT}px`, height: `calc(100vh - 110px - ${this.getContentsScrollTop() <= BREADCRUMB_HEIGHT ? BREADCRUMB_HEIGHT - this.getContentsScrollTop() : 0}px)` }}> <div className="contents-drop-message">Drop you files to upload to "{this.getFolderPath()}" </div> </div> } </div> </div> ); } }; ContentsView.propTypes = { onPreview: PropTypes.func.isRequired, willBeDeletedContentsItem: PropTypes.func.isRequired, openDialog: PropTypes.func.isRequired, selectUploadFiles: PropTypes.func.isRequired, uploadFilesAsync: PropTypes.func.isRequired, openFloatingView: PropTypes.func.isRequired, contents: PropTypes.array.isRequired, folders: PropTypes.array.isRequired, onContentsClick: PropTypes.func.isRequired, updateFolderAsync: PropTypes.func.isRequired, onContentItemDoubleClick: PropTypes.func.isRequired, onContextMenuClicked: PropTypes.func.isRequired, contextMenuVisibility: PropTypes.bool.isRequired, closePopup: PropTypes.func.isRequired, rename: PropTypes.func.isRequired, updateFolderData: PropTypes.func.isRequired, onFolderItemDoubleClick: PropTypes.func.isRequired, breadcrumb: PropTypes.array.isRequired, onBreadcrumbItemClick: PropTypes.func.isRequired, updateContentsItemAsync: PropTypes.func.isRequired, updateContentsItemData: PropTypes.func.isRequired, selectedContentsItemIds: PropTypes.array, searchOption: PropTypes.object, copyToClick: PropTypes.func.isRequired, };