1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-11 00:36:26 +00:00
Files
Boostnote/browser/main/modals/PreferencesModal/FolderItem.js
2019-05-29 12:20:49 +09:00

306 lines
8.2 KiB
JavaScript

import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import ReactDOM from 'react-dom'
import styles from './FolderItem.styl'
import dataApi from 'browser/main/lib/dataApi'
import { store } from 'browser/main/store'
import { SketchPicker } from 'react-color'
import { SortableElement, SortableHandle } from 'react-sortable-hoc'
import i18n from 'browser/lib/i18n'
class FolderItem extends React.Component {
constructor (props) {
super(props)
this.state = {
status: 'IDLE',
folder: {
showColumnPicker: false,
colorPickerPos: { left: 0, top: 0 },
color: props.color,
name: props.name
}
}
}
handleEditChange (e) {
const { folder } = this.state
folder.name = this.refs.nameInput.value
this.setState({
folder
})
}
handleConfirmButtonClick (e) {
this.confirm()
}
confirm () {
const { storage, folder } = this.props
dataApi
.updateFolder(storage.key, folder.key, {
color: this.state.folder.color,
name: this.state.folder.name
})
.then((data) => {
store.dispatch({
type: 'UPDATE_FOLDER',
storage: data.storage
})
this.setState({
status: 'IDLE'
})
})
}
handleColorButtonClick (e) {
const folder = Object.assign({}, this.state.folder, { showColumnPicker: true, colorPickerPos: { left: 0, top: 0 } })
this.setState({ folder }, function () {
// After the color picker has been painted, re-calculate its position
// by comparing its dimensions to the host dimensions.
const { hostBoundingBox } = this.props
const colorPickerNode = ReactDOM.findDOMNode(this.refs.colorPicker)
const colorPickerBox = colorPickerNode.getBoundingClientRect()
const offsetTop = hostBoundingBox.bottom - colorPickerBox.bottom
const folder = Object.assign({}, this.state.folder, {
colorPickerPos: {
left: 25,
top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics
}
})
this.setState({ folder })
})
}
handleColorChange (color) {
const folder = Object.assign({}, this.state.folder, { color: color.hex })
this.setState({ folder })
}
handleColorPickerClose (event) {
const folder = Object.assign({}, this.state.folder, { showColumnPicker: false })
this.setState({ folder })
}
handleCancelButtonClick (e) {
this.setState({
status: 'IDLE'
})
}
handleFolderItemBlur (e) {
let el = e.relatedTarget
while (el != null) {
if (el === this.refs.root) {
return false
}
el = el.parentNode
}
this.confirm()
}
renderEdit (e) {
const popover = { position: 'absolute', zIndex: 2 }
const cover = {
position: 'fixed',
top: 0,
right: 0,
bottom: 0,
left: 0
}
const pickerStyle = Object.assign({}, {
position: 'absolute'
}, this.state.folder.colorPickerPos)
return (
<div styleName='folderItem'
onBlur={(e) => this.handleFolderItemBlur(e)}
tabIndex='-1'
ref='root'
>
<div styleName='folderItem-left'>
<button styleName='folderItem-left-colorButton' style={{color: this.state.folder.color}}
onClick={(e) => !this.state.folder.showColumnPicker && this.handleColorButtonClick(e)}
>
{this.state.folder.showColumnPicker
? <div style={popover}>
<div style={cover}
onClick={() => this.handleColorPickerClose()}
/>
<div style={pickerStyle}>
<SketchPicker
ref='colorPicker'
color={this.state.folder.color}
onChange={(color) => this.handleColorChange(color)}
onChangeComplete={(color) => this.handleColorChange(color)}
/>
</div>
</div>
: null
}
<i className='fa fa-square' />
</button>
<input styleName='folderItem-left-nameInput'
value={this.state.folder.name}
ref='nameInput'
onChange={(e) => this.handleEditChange(e)}
/>
</div>
<div styleName='folderItem-right'>
<button styleName='folderItem-right-confirmButton'
onClick={(e) => this.handleConfirmButtonClick(e)}
>
{i18n.__('Confirm')}
</button>
<button styleName='folderItem-right-button'
onClick={(e) => this.handleCancelButtonClick(e)}
>
{i18n.__('Cancel')}
</button>
</div>
</div>
)
}
handleDeleteConfirmButtonClick (e) {
const { storage, folder } = this.props
dataApi
.deleteFolder(storage.key, folder.key)
.then((data) => {
store.dispatch({
type: 'DELETE_FOLDER',
storage: data.storage,
folderKey: data.folderKey
})
})
}
renderDelete () {
return (
<div styleName='folderItem'>
<div styleName='folderItem-left'>
{i18n.__('Are you sure to ')} <span styleName='folderItem-left-danger'>{i18n.__(' delete')}</span> {i18n.__('this folder?')}
</div>
<div styleName='folderItem-right'>
<button styleName='folderItem-right-dangerButton'
onClick={(e) => this.handleDeleteConfirmButtonClick(e)}
>
{i18n.__('Confirm')}
</button>
<button styleName='folderItem-right-button'
onClick={(e) => this.handleCancelButtonClick(e)}
>
{i18n.__('Cancel')}
</button>
</div>
</div>
)
}
handleEditButtonClick (e) {
const { folder: propsFolder } = this.props
const { folder: stateFolder } = this.state
const folder = Object.assign({}, stateFolder, propsFolder)
this.setState({
status: 'EDIT',
folder
}, () => {
this.refs.nameInput.select()
})
}
handleDeleteButtonClick (e) {
this.setState({
status: 'DELETE'
})
}
renderIdle () {
const { folder } = this.props
return (
<div styleName='folderItem'
onDoubleClick={(e) => this.handleEditButtonClick(e)}
>
<div styleName='folderItem-left'
style={{borderColor: folder.color}}
>
<span styleName='folderItem-left-name'>{folder.name}</span>
<span styleName='folderItem-left-key'>({folder.key})</span>
</div>
<div styleName='folderItem-right'>
<button styleName='folderItem-right-button'
onClick={(e) => this.handleEditButtonClick(e)}
>
{i18n.__('Edit')}
</button>
<button styleName='folderItem-right-button'
onClick={(e) => this.handleDeleteButtonClick(e)}
>
{i18n.__('Delete')}
</button>
</div>
</div>
)
}
render () {
switch (this.state.status) {
case 'DELETE':
return this.renderDelete()
case 'EDIT':
return this.renderEdit()
case 'IDLE':
default:
return this.renderIdle()
}
}
}
FolderItem.propTypes = {
hostBoundingBox: PropTypes.shape({
bottom: PropTypes.number,
height: PropTypes.number,
left: PropTypes.number,
right: PropTypes.number,
top: PropTypes.number,
width: PropTypes.number
}),
storage: PropTypes.shape({
key: PropTypes.string
}),
folder: PropTypes.shape({
key: PropTypes.string,
color: PropTypes.string,
name: PropTypes.string
})
}
class Handle extends React.Component {
render () {
return (
<div styleName='folderItem-drag-handle'>
<i className='fa fa-reorder' />
</div>
)
}
}
class SortableFolderItemComponent extends React.Component {
render () {
const StyledHandle = CSSModules(Handle, this.props.styles)
const DragHandle = SortableHandle(StyledHandle)
const StyledFolderItem = CSSModules(FolderItem, this.props.styles)
return (
<div>
<DragHandle />
<StyledFolderItem {...this.props} />
</div>
)
}
}
export default CSSModules(SortableElement(SortableFolderItemComponent), styles)