import PropTypes from 'prop-types'; import React from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import InlineSVG from 'react-inlinesvg'; import classNames from 'classnames'; import * as IDEActions from '../actions/ide'; import * as FileActions from '../actions/files'; const downArrowUrl = require('../../../images/down-filled-triangle.svg'); const folderRightUrl = require('../../../images/triangle-arrow-right.svg'); const folderDownUrl = require('../../../images/triangle-arrow-down.svg'); const fileUrl = require('../../../images/file.svg'); export class FileNode extends React.Component { constructor(props) { super(props); this.renderChild = this.renderChild.bind(this); this.handleKeyPress = this.handleKeyPress.bind(this); this.handleFileNameChange = this.handleFileNameChange.bind(this); this.validateFileName = this.validateFileName.bind(this); this.handleFileClick = this.handleFileClick.bind(this); this.toggleFileOptions = this.toggleFileOptions.bind(this); this.hideFileOptions = this.hideFileOptions.bind(this); this.showEditFileName = this.showEditFileName.bind(this); this.hideEditFileName = this.hideEditFileName.bind(this); this.onBlurComponent = this.onBlurComponent.bind(this); this.onFocusComponent = this.onFocusComponent.bind(this); this.state = { isOptionsOpen: false, isEditingName: false, isFocused: false, updatedName: this.props.name }; } onFocusComponent() { this.setState({ isFocused: true }); } onBlurComponent() { this.setState({ isFocused: false }); setTimeout(() => { if (!this.state.isFocused) { this.hideFileOptions(); } }, 200); } get updatedName() { return this.state.updatedName || this.props.name; } commitFileNameChange() { const { updatedName } = this.state; const { name, updateFileName, id } = this.props; if (updatedName !== name) { updateFileName(id, updatedName); } } handleFileClick(e) { e.stopPropagation(); if (this.updatedName !== 'root' && !this.isDeleting) { this.props.setSelectedFile(this.props.id); } } handleFileNameChange(event) { const newname = event.target.value; this.setState({ updatedName: newname }); } handleKeyPress(event) { if (event.key === 'Enter') { this.hideEditFileName(); } } validateFileName() { const oldFileExtension = this.originalFileName.match(/\.[0-9a-z]+$/i); const newFileExtension = this.updatedName.match(/\.[0-9a-z]+$/i); const hasPeriod = this.updatedName.match(/\.+/); const newFileName = this.updatedName; const hasNoExtension = oldFileExtension && !newFileExtension; const hasExtensionIfFolder = this.props.fileType === 'folder' && hasPeriod; const notSameExtension = oldFileExtension && newFileExtension && oldFileExtension[0].toLowerCase() !== newFileExtension[0].toLowerCase(); const hasEmptyFilename = newFileName === ''; const hasOnlyExtension = newFileExtension && newFileName === newFileExtension[0]; if (hasEmptyFilename || hasNoExtension || notSameExtension || hasOnlyExtension || hasExtensionIfFolder) { this.setState({ updatedName: this.originalFileName }); this.props.updateFileName(this.props.id, this.originalFileName); } else this.commitFileNameChange(); } toggleFileOptions(e) { e.preventDefault(); if (!this.props.canEdit) { return; } if (this.state.isOptionsOpen) { this.setState({ isOptionsOpen: false }); } else { this[`fileOptions-${this.props.id}`].focus(); this.setState({ isOptionsOpen: true }); } } hideFileOptions() { this.setState({ isOptionsOpen: false }); } showEditFileName() { this.setState({ isEditingName: true }); } hideEditFileName() { this.setState({ isEditingName: false }); } renderChild(childId) { return (