nexshop-web-contents
Version:
Nexshop Web Contents Project
291 lines (260 loc) • 12 kB
JavaScript
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,
};