2020-10-20 21:50:53 +02:00
|
|
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
|
|
// See LICENSE.txt for license information.
|
2020-10-20 21:52:56 +02:00
|
|
|
import React from 'react'
|
2020-10-21 03:28:55 +02:00
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
import {BlockIcons} from '../blockIcons'
|
|
|
|
import {MutableCommentBlock} from '../blocks/commentBlock'
|
|
|
|
import {IOrderedBlock} from '../blocks/orderedBlock'
|
|
|
|
import {MutableTextBlock} from '../blocks/textBlock'
|
|
|
|
import {BoardTree} from '../viewModel/boardTree'
|
|
|
|
import {CardTree, MutableCardTree} from '../viewModel/cardTree'
|
|
|
|
import {Menu as OldMenu, MenuOption} from '../menu'
|
|
|
|
import mutator from '../mutator'
|
|
|
|
import {OctoListener} from '../octoListener'
|
|
|
|
import {IBlock} from '../blocks/block'
|
|
|
|
import {OctoUtils} from '../octoUtils'
|
|
|
|
import {PropertyMenu} from '../propertyMenu'
|
|
|
|
import {Utils} from '../utils'
|
2020-10-21 03:28:55 +02:00
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
import Button from './button'
|
|
|
|
import {Editable} from './editable'
|
|
|
|
import {MarkdownEditor} from './markdownEditor'
|
2020-10-15 19:46:32 +02:00
|
|
|
|
|
|
|
type Props = {
|
2020-10-20 21:50:53 +02:00
|
|
|
boardTree: BoardTree
|
2020-10-21 03:28:55 +02:00
|
|
|
cardId: string
|
2020-10-15 19:46:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type State = {
|
2020-10-20 21:50:53 +02:00
|
|
|
isHoverOnCover: boolean
|
|
|
|
cardTree?: CardTree
|
2020-10-15 19:46:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
export default class CardDetail extends React.Component<Props, State> {
|
2020-10-20 21:50:53 +02:00
|
|
|
private titleRef = React.createRef<Editable>()
|
2020-10-21 18:32:36 +02:00
|
|
|
private cardListener?: OctoListener
|
2020-10-20 21:50:53 +02:00
|
|
|
|
|
|
|
constructor(props: Props) {
|
2020-10-22 00:03:12 +02:00
|
|
|
super(props)
|
2020-10-20 21:50:53 +02:00
|
|
|
this.state = {isHoverOnCover: false}
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
this.cardListener = new OctoListener()
|
2020-10-22 00:03:12 +02:00
|
|
|
this.cardListener.open([this.props.cardId], async (blockId) => {
|
2020-10-21 03:28:55 +02:00
|
|
|
Utils.log(`cardListener.onChanged: ${blockId}`)
|
2020-10-20 21:50:53 +02:00
|
|
|
await cardTree.sync()
|
2020-10-22 00:03:12 +02:00
|
|
|
this.setState({...this.state, cardTree})
|
2020-10-20 21:52:56 +02:00
|
|
|
})
|
2020-10-22 00:03:12 +02:00
|
|
|
const cardTree = new MutableCardTree(this.props.cardId)
|
2020-10-20 21:50:53 +02:00
|
|
|
cardTree.sync().then(() => {
|
2020-10-22 00:03:12 +02:00
|
|
|
this.setState({...this.state, cardTree})
|
|
|
|
setTimeout(() => {
|
2020-10-20 21:50:53 +02:00
|
|
|
if (this.titleRef.current) {
|
|
|
|
this.titleRef.current.focus()
|
|
|
|
}
|
2020-10-22 00:03:12 +02:00
|
|
|
}, 0)
|
2020-10-20 21:52:56 +02:00
|
|
|
})
|
2020-10-20 21:50:53 +02:00
|
|
|
}
|
|
|
|
|
2020-10-21 18:32:36 +02:00
|
|
|
componentWillUnmount() {
|
|
|
|
this.cardListener?.close()
|
|
|
|
this.cardListener = undefined
|
|
|
|
}
|
|
|
|
|
2020-10-20 21:50:53 +02:00
|
|
|
render() {
|
2020-10-22 00:03:12 +02:00
|
|
|
const {boardTree} = this.props
|
2020-10-21 03:28:55 +02:00
|
|
|
const {cardTree} = this.state
|
2020-10-20 21:50:53 +02:00
|
|
|
const {board} = boardTree
|
2020-10-22 00:03:12 +02:00
|
|
|
if (!cardTree) {
|
|
|
|
return null
|
2020-10-20 21:50:53 +02:00
|
|
|
}
|
2020-10-21 03:28:55 +02:00
|
|
|
const {card, comments} = cardTree
|
2020-10-20 21:50:53 +02:00
|
|
|
|
2020-10-20 21:52:56 +02:00
|
|
|
const newCommentPlaceholderText = 'Add a comment...'
|
2020-10-20 21:50:53 +02:00
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
const backgroundRef = React.createRef<HTMLDivElement>()
|
2020-10-20 21:50:53 +02:00
|
|
|
const newCommentRef = React.createRef<Editable>()
|
|
|
|
const sendCommentButtonRef = React.createRef<HTMLDivElement>()
|
|
|
|
let contentElements
|
|
|
|
if (cardTree.contents.length > 0) {
|
|
|
|
contentElements =
|
|
|
|
(<div className='octo-content'>
|
|
|
|
{cardTree.contents.map((block) => {
|
2020-10-22 00:03:12 +02:00
|
|
|
if (block.type === 'text') {
|
|
|
|
const cardText = block.title
|
|
|
|
return (<div
|
2020-10-20 21:50:53 +02:00
|
|
|
key={block.id}
|
|
|
|
className='octo-block octo-hover-container'
|
2020-10-22 18:46:06 +02:00
|
|
|
>
|
2020-10-20 21:50:53 +02:00
|
|
|
<div className='octo-block-margin'>
|
2020-10-22 00:03:12 +02:00
|
|
|
<div
|
2020-10-20 21:50:53 +02:00
|
|
|
className='octo-button octo-hovercontrol square octo-hover-item'
|
|
|
|
onClick={(e) => {
|
|
|
|
this.showContentBlockMenu(e, block)
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<div className='imageOptions'/>
|
|
|
|
</div>
|
2020-10-22 00:03:12 +02:00
|
|
|
</div>
|
2020-10-20 21:50:53 +02:00
|
|
|
<MarkdownEditor
|
2020-10-22 00:03:12 +02:00
|
|
|
text={cardText}
|
|
|
|
placeholderText='Edit text...'
|
|
|
|
onChanged={(text) => {
|
2020-10-20 21:50:53 +02:00
|
|
|
Utils.log(`change text ${block.id}, ${text}`)
|
|
|
|
mutator.changeTitle(block, text, 'edit card text')
|
|
|
|
}}
|
2020-10-22 00:03:12 +02:00
|
|
|
/>
|
2020-10-20 21:50:53 +02:00
|
|
|
</div>)
|
2020-10-22 00:03:12 +02:00
|
|
|
} else if (block.type === 'image') {
|
|
|
|
const url = block.fields.url
|
|
|
|
return (<div
|
2020-10-20 21:50:53 +02:00
|
|
|
key={block.id}
|
|
|
|
className='octo-block octo-hover-container'
|
2020-10-22 18:46:06 +02:00
|
|
|
>
|
2020-10-20 21:50:53 +02:00
|
|
|
<div className='octo-block-margin'>
|
2020-10-22 00:03:12 +02:00
|
|
|
<div
|
2020-10-20 21:50:53 +02:00
|
|
|
className='octo-button octo-hovercontrol square octo-hover-item'
|
|
|
|
onClick={(e) => {
|
|
|
|
this.showContentBlockMenu(e, block)
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<div className='imageOptions'/>
|
|
|
|
</div>
|
2020-10-22 00:03:12 +02:00
|
|
|
</div>
|
|
|
|
<img
|
2020-10-20 21:50:53 +02:00
|
|
|
src={url}
|
|
|
|
alt={block.title}
|
2020-10-22 00:03:12 +02:00
|
|
|
/>
|
2020-10-20 21:50:53 +02:00
|
|
|
</div>)
|
2020-10-22 00:03:12 +02:00
|
|
|
}
|
2020-10-20 21:50:53 +02:00
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
return <div/>
|
|
|
|
})}
|
2020-10-20 21:50:53 +02:00
|
|
|
</div>)
|
2020-10-22 00:03:12 +02:00
|
|
|
} else {
|
2020-10-20 21:50:53 +02:00
|
|
|
contentElements = (<div className='octo-content'>
|
|
|
|
<div className='octo-block octo-hover-container'>
|
|
|
|
<div className='octo-block-margin'/>
|
|
|
|
<MarkdownEditor
|
|
|
|
text=''
|
|
|
|
placeholderText='Add a description...'
|
|
|
|
onChanged={(text) => {
|
2020-10-21 03:28:55 +02:00
|
|
|
const block = new MutableTextBlock()
|
|
|
|
block.parentId = card.id
|
|
|
|
block.title = text
|
|
|
|
block.order = cardTree.contents.length * 1000
|
2020-10-20 21:50:53 +02:00
|
|
|
mutator.insertBlock(block, 'add card text')
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>)
|
2020-10-22 00:03:12 +02:00
|
|
|
}
|
2020-10-20 21:50:53 +02:00
|
|
|
|
|
|
|
const icon = card.icon
|
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
// TODO: Replace this placeholder
|
2020-10-20 21:52:56 +02:00
|
|
|
const username = 'John Smith'
|
|
|
|
const userImageUrl = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" style="fill: rgb(192, 192, 192);"><rect width="100" height="100" /></svg>'
|
2020-10-20 21:50:53 +02:00
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
return (
|
2020-10-20 21:50:53 +02:00
|
|
|
<>
|
2020-10-22 00:03:12 +02:00
|
|
|
<div className='content'>
|
2020-10-20 21:50:53 +02:00
|
|
|
{icon ?
|
2020-10-22 00:03:12 +02:00
|
|
|
<div
|
2020-10-20 21:50:53 +02:00
|
|
|
className='octo-button octo-icon octo-card-icon'
|
|
|
|
onClick={(e) => {
|
|
|
|
this.iconClicked(e)
|
|
|
|
}}
|
|
|
|
>{icon}</div> :
|
|
|
|
undefined
|
2020-10-22 00:03:12 +02:00
|
|
|
}
|
2020-10-20 21:50:53 +02:00
|
|
|
<div
|
2020-10-22 00:03:12 +02:00
|
|
|
className='octo-hovercontrols'
|
|
|
|
onMouseOver={() => {
|
2020-10-20 21:50:53 +02:00
|
|
|
this.setState({...this.state, isHoverOnCover: true})
|
|
|
|
}}
|
2020-10-22 00:03:12 +02:00
|
|
|
onMouseLeave={() => {
|
2020-10-20 21:50:53 +02:00
|
|
|
this.setState({...this.state, isHoverOnCover: false})
|
|
|
|
}}
|
2020-10-22 00:03:12 +02:00
|
|
|
>
|
|
|
|
<Button
|
2020-10-20 21:50:53 +02:00
|
|
|
style={{display: (!icon && this.state.isHoverOnCover) ? null : 'none'}}
|
|
|
|
onClick={() => {
|
2020-10-22 00:03:12 +02:00
|
|
|
const newIcon = BlockIcons.shared.randomIcon()
|
2020-10-20 21:50:53 +02:00
|
|
|
mutator.changeIcon(card, newIcon)
|
|
|
|
}}
|
|
|
|
>Add Icon</Button>
|
2020-10-22 00:03:12 +02:00
|
|
|
</div>
|
2020-10-20 21:50:53 +02:00
|
|
|
|
|
|
|
<Editable
|
2020-10-22 00:03:12 +02:00
|
|
|
ref={this.titleRef}
|
|
|
|
className='title'
|
|
|
|
text={card.title}
|
|
|
|
placeholderText='Untitled'
|
|
|
|
onChanged={(text) => {
|
2020-10-20 21:50:53 +02:00
|
|
|
mutator.changeTitle(card, text)
|
|
|
|
}}
|
2020-10-22 00:03:12 +02:00
|
|
|
/>
|
2020-10-20 21:50:53 +02:00
|
|
|
|
|
|
|
{/* Property list */}
|
|
|
|
|
|
|
|
<div className='octo-propertylist'>
|
2020-10-22 00:03:12 +02:00
|
|
|
{board.cardProperties.map((propertyTemplate) => {
|
2020-10-20 21:50:53 +02:00
|
|
|
return (
|
|
|
|
<div
|
|
|
|
key={propertyTemplate.id}
|
|
|
|
className='octo-propertyrow'
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
className='octo-button octo-propertyname'
|
|
|
|
onClick={(e) => {
|
|
|
|
const menu = PropertyMenu.shared
|
2020-10-22 00:03:12 +02:00
|
|
|
menu.property = propertyTemplate
|
2020-10-20 21:50:53 +02:00
|
|
|
menu.onNameChanged = (propertyName) => {
|
2020-10-22 00:03:12 +02:00
|
|
|
Utils.log('menu.onNameChanged')
|
|
|
|
mutator.renameProperty(board, propertyTemplate.id, propertyName)
|
2020-10-20 21:52:56 +02:00
|
|
|
}
|
2020-10-20 21:50:53 +02:00
|
|
|
|
|
|
|
menu.onMenuClicked = async (command) => {
|
|
|
|
switch (command) {
|
2020-10-22 00:03:12 +02:00
|
|
|
case 'type-text':
|
|
|
|
await mutator.changePropertyType(board, propertyTemplate, 'text')
|
|
|
|
break
|
|
|
|
case 'type-number':
|
2020-10-20 21:50:53 +02:00
|
|
|
await mutator.changePropertyType(board, propertyTemplate, 'number')
|
2020-10-22 00:03:12 +02:00
|
|
|
break
|
2020-10-20 21:50:53 +02:00
|
|
|
case 'type-createdTime':
|
2020-10-22 00:03:12 +02:00
|
|
|
await mutator.changePropertyType(board, propertyTemplate, 'createdTime')
|
2020-10-20 21:52:56 +02:00
|
|
|
break
|
2020-10-22 00:03:12 +02:00
|
|
|
case 'type-updatedTime':
|
2020-10-20 21:50:53 +02:00
|
|
|
await mutator.changePropertyType(board, propertyTemplate, 'updatedTime')
|
2020-10-20 21:52:56 +02:00
|
|
|
break
|
2020-10-22 00:03:12 +02:00
|
|
|
case 'type-select':
|
2020-10-20 21:50:53 +02:00
|
|
|
await mutator.changePropertyType(board, propertyTemplate, 'select')
|
2020-10-20 21:52:56 +02:00
|
|
|
break
|
2020-10-20 21:50:53 +02:00
|
|
|
case 'delete':
|
|
|
|
await mutator.deleteProperty(boardTree, propertyTemplate.id)
|
2020-10-20 21:52:56 +02:00
|
|
|
break
|
2020-10-22 00:03:12 +02:00
|
|
|
default:
|
2020-10-20 21:50:53 +02:00
|
|
|
Utils.assertFailure(`Unhandled menu id: ${command}`)
|
2020-10-22 00:03:12 +02:00
|
|
|
}
|
|
|
|
}
|
2020-10-20 21:50:53 +02:00
|
|
|
menu.showAtElement(e.target as HTMLElement)
|
2020-10-22 00:03:12 +02:00
|
|
|
}}
|
2020-10-20 21:50:53 +02:00
|
|
|
>{propertyTemplate.name}</div>
|
|
|
|
{OctoUtils.propertyValueEditableElement(card, propertyTemplate)}
|
|
|
|
</div>
|
2020-10-22 00:03:12 +02:00
|
|
|
)
|
2020-10-20 21:50:53 +02:00
|
|
|
})}
|
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
<div
|
2020-10-20 21:50:53 +02:00
|
|
|
className='octo-button octo-propertyname'
|
|
|
|
style={{textAlign: 'left', width: '150px', color: 'rgba(55, 53, 37, 0.4)'}}
|
|
|
|
onClick={async () => {
|
|
|
|
// TODO: Show UI
|
2020-10-22 00:03:12 +02:00
|
|
|
await mutator.insertPropertyTemplate(boardTree)
|
|
|
|
}}
|
2020-10-20 21:50:53 +02:00
|
|
|
>+ Add a property</div>
|
2020-10-22 00:03:12 +02:00
|
|
|
</div>
|
2020-10-20 21:50:53 +02:00
|
|
|
|
|
|
|
{/* Comments */}
|
|
|
|
|
|
|
|
<hr/>
|
|
|
|
<div className='commentlist'>
|
2020-10-22 00:03:12 +02:00
|
|
|
{comments.map((comment) => {
|
2020-10-20 21:50:53 +02:00
|
|
|
const optionsButtonRef = React.createRef<HTMLDivElement>()
|
|
|
|
const showCommentMenu = (e: React.MouseEvent, activeComment: IBlock) => {
|
2020-10-22 00:03:12 +02:00
|
|
|
OldMenu.shared.options = [
|
|
|
|
{id: 'delete', name: 'Delete'},
|
2020-10-20 21:50:53 +02:00
|
|
|
]
|
2020-10-22 00:03:12 +02:00
|
|
|
OldMenu.shared.onMenuClicked = (id) => {
|
2020-10-20 21:50:53 +02:00
|
|
|
switch (id) {
|
2020-10-22 00:03:12 +02:00
|
|
|
case 'delete': {
|
|
|
|
mutator.deleteBlock(activeComment)
|
2020-10-20 21:52:56 +02:00
|
|
|
break
|
2020-10-20 21:50:53 +02:00
|
|
|
}
|
2020-10-22 00:03:12 +02:00
|
|
|
}
|
|
|
|
}
|
2020-10-20 21:50:53 +02:00
|
|
|
OldMenu.shared.showAtElement(e.target as HTMLElement)
|
2020-10-20 21:52:56 +02:00
|
|
|
}
|
2020-10-20 21:50:53 +02:00
|
|
|
|
|
|
|
return (<div
|
|
|
|
key={comment.id}
|
|
|
|
className='comment'
|
|
|
|
onMouseOver={() => {
|
|
|
|
optionsButtonRef.current.style.display = null
|
|
|
|
}}
|
|
|
|
onMouseLeave={() => {
|
2020-10-20 21:52:56 +02:00
|
|
|
optionsButtonRef.current.style.display = 'none'
|
2020-10-20 21:50:53 +02:00
|
|
|
}}
|
2020-10-22 18:46:06 +02:00
|
|
|
>
|
2020-10-20 21:50:53 +02:00
|
|
|
<div className='comment-header'>
|
|
|
|
<img
|
|
|
|
className='comment-avatar'
|
|
|
|
src={userImageUrl}
|
|
|
|
/>
|
|
|
|
<div className='comment-username'>{username}</div>
|
|
|
|
<div className='comment-date'>{(new Date(comment.createAt)).toLocaleTimeString()}</div>
|
|
|
|
<div
|
|
|
|
ref={optionsButtonRef}
|
|
|
|
className='octo-hoverbutton square'
|
|
|
|
style={{display: 'none'}}
|
|
|
|
onClick={(e) => {
|
|
|
|
showCommentMenu(e, comment)
|
|
|
|
}}
|
|
|
|
>...</div>
|
|
|
|
</div>
|
|
|
|
<div className='comment-text'>{comment.title}</div>
|
|
|
|
</div>)
|
2020-10-22 00:03:12 +02:00
|
|
|
})}
|
2020-10-20 21:50:53 +02:00
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
{/* New comment */}
|
2020-10-20 21:50:53 +02:00
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
<div className='commentrow'>
|
2020-10-20 21:50:53 +02:00
|
|
|
<img
|
2020-10-22 00:03:12 +02:00
|
|
|
className='comment-avatar'
|
|
|
|
src={userImageUrl}
|
|
|
|
/>
|
2020-10-20 21:50:53 +02:00
|
|
|
<Editable
|
2020-10-22 00:03:12 +02:00
|
|
|
ref={newCommentRef}
|
|
|
|
className='newcomment'
|
|
|
|
placeholderText={newCommentPlaceholderText}
|
|
|
|
onChanged={(text) => { }}
|
|
|
|
onFocus={() => {
|
2020-10-20 21:50:53 +02:00
|
|
|
sendCommentButtonRef.current.style.display = null
|
|
|
|
}}
|
2020-10-22 00:03:12 +02:00
|
|
|
onBlur={() => {
|
|
|
|
if (!newCommentRef.current.text) {
|
2020-10-20 21:52:56 +02:00
|
|
|
sendCommentButtonRef.current.style.display = 'none'
|
2020-10-22 00:03:12 +02:00
|
|
|
}
|
|
|
|
}}
|
|
|
|
onKeyDown={(e) => {
|
2020-10-20 21:50:53 +02:00
|
|
|
if (e.keyCode === 13 && !(e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey) {
|
2020-10-22 00:03:12 +02:00
|
|
|
sendCommentButtonRef.current.click()
|
2020-10-20 21:50:53 +02:00
|
|
|
}
|
2020-10-22 00:03:12 +02:00
|
|
|
}}
|
|
|
|
/>
|
2020-10-20 21:50:53 +02:00
|
|
|
|
|
|
|
<div
|
2020-10-22 00:03:12 +02:00
|
|
|
ref={sendCommentButtonRef}
|
|
|
|
className='octo-button filled'
|
|
|
|
style={{display: 'none'}}
|
|
|
|
onClick={(e) => {
|
|
|
|
const text = newCommentRef.current.text
|
2020-10-22 18:46:06 +02:00
|
|
|
Utils.log(`Send comment: ${newCommentRef.current.text}`)
|
2020-10-22 00:03:12 +02:00
|
|
|
this.sendComment(text)
|
|
|
|
newCommentRef.current.text = undefined
|
2020-10-20 21:50:53 +02:00
|
|
|
newCommentRef.current.blur()
|
|
|
|
}}
|
2020-10-22 00:03:12 +02:00
|
|
|
>Send</div>
|
2020-10-20 21:50:53 +02:00
|
|
|
</div>
|
2020-10-22 00:03:12 +02:00
|
|
|
</div>
|
2020-10-20 21:50:53 +02:00
|
|
|
|
|
|
|
<hr/>
|
|
|
|
</div>
|
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
{/* Content blocks */}
|
2020-10-20 21:50:53 +02:00
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
<div className='content fullwidth'>
|
2020-10-20 21:50:53 +02:00
|
|
|
{contentElements}
|
|
|
|
</div>
|
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
<div className='content'>
|
2020-10-20 21:50:53 +02:00
|
|
|
<div className='octo-hoverpanel octo-hover-container'>
|
2020-10-22 00:03:12 +02:00
|
|
|
<div
|
2020-10-20 21:50:53 +02:00
|
|
|
className='octo-button octo-hovercontrol octo-hover-item'
|
|
|
|
onClick={(e) => {
|
2020-10-22 00:03:12 +02:00
|
|
|
OldMenu.shared.options = [
|
|
|
|
{id: 'text', name: 'Text'},
|
2020-10-20 21:50:53 +02:00
|
|
|
{id: 'image', name: 'Image'},
|
2020-10-22 00:03:12 +02:00
|
|
|
]
|
2020-10-20 21:50:53 +02:00
|
|
|
OldMenu.shared.onMenuClicked = async (optionId: string, type?: string) => {
|
2020-10-22 00:03:12 +02:00
|
|
|
switch (optionId) {
|
2020-10-20 21:50:53 +02:00
|
|
|
case 'text':
|
2020-10-21 03:28:55 +02:00
|
|
|
const block = new MutableTextBlock()
|
|
|
|
block.parentId = card.id
|
|
|
|
block.order = cardTree.contents.length * 1000
|
2020-10-20 21:50:53 +02:00
|
|
|
await mutator.insertBlock(block, 'add text')
|
2020-10-22 00:03:12 +02:00
|
|
|
break
|
|
|
|
case 'image':
|
2020-10-20 21:50:53 +02:00
|
|
|
Utils.selectLocalFile(
|
|
|
|
(file) => {
|
2020-10-22 00:03:12 +02:00
|
|
|
mutator.createImageBlock(card.id, file, cardTree.contents.length * 1000)
|
2020-10-20 21:50:53 +02:00
|
|
|
},
|
2020-10-22 00:03:12 +02:00
|
|
|
'.jpg,.jpeg,.png')
|
|
|
|
break
|
2020-10-20 21:50:53 +02:00
|
|
|
}
|
|
|
|
}
|
2020-10-22 00:03:12 +02:00
|
|
|
OldMenu.shared.showAtElement(e.target as HTMLElement)
|
2020-10-20 21:50:53 +02:00
|
|
|
}}
|
|
|
|
>Add content</div>
|
2020-10-22 00:03:12 +02:00
|
|
|
</div>
|
2020-10-20 21:50:53 +02:00
|
|
|
</div>
|
2020-10-22 00:03:12 +02:00
|
|
|
</>
|
2020-10-20 21:50:53 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
async sendComment(text: string) {
|
2020-10-21 03:28:55 +02:00
|
|
|
const {cardId} = this.props
|
2020-10-20 21:50:53 +02:00
|
|
|
|
2020-10-21 03:28:55 +02:00
|
|
|
Utils.assertValue(cardId)
|
2020-10-20 21:50:53 +02:00
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
const block = new MutableCommentBlock({parentId: cardId, title: text})
|
2020-10-20 21:50:53 +02:00
|
|
|
await mutator.insertBlock(block, 'add comment')
|
|
|
|
}
|
|
|
|
|
|
|
|
private showContentBlockMenu(e: React.MouseEvent, block: IOrderedBlock) {
|
|
|
|
const {cardTree} = this.state
|
2020-10-22 00:03:12 +02:00
|
|
|
const {cardId} = this.props
|
|
|
|
const index = cardTree.contents.indexOf(block)
|
2020-10-20 21:50:53 +02:00
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
const options: MenuOption[] = []
|
|
|
|
if (index > 0) {
|
2020-10-20 21:50:53 +02:00
|
|
|
options.push({id: 'moveUp', name: 'Move up'})
|
2020-10-22 00:03:12 +02:00
|
|
|
}
|
|
|
|
if (index < cardTree.contents.length - 1) {
|
2020-10-20 21:50:53 +02:00
|
|
|
options.push({id: 'moveDown', name: 'Move down'})
|
|
|
|
}
|
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
options.push(
|
2020-10-20 21:50:53 +02:00
|
|
|
{id: 'insertAbove', name: 'Insert above', type: 'submenu'},
|
2020-10-22 00:03:12 +02:00
|
|
|
{id: 'delete', name: 'Delete'},
|
2020-10-20 21:50:53 +02:00
|
|
|
)
|
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
OldMenu.shared.options = options
|
|
|
|
OldMenu.shared.subMenuOptions.set('insertAbove', [
|
2020-10-20 21:50:53 +02:00
|
|
|
{id: 'text', name: 'Text'},
|
2020-10-22 00:03:12 +02:00
|
|
|
{id: 'image', name: 'Image'},
|
2020-10-20 21:50:53 +02:00
|
|
|
])
|
|
|
|
OldMenu.shared.onMenuClicked = (optionId: string, type?: string) => {
|
2020-10-22 00:03:12 +02:00
|
|
|
switch (optionId) {
|
2020-10-20 21:50:53 +02:00
|
|
|
case 'moveUp': {
|
|
|
|
if (index < 1) {
|
|
|
|
Utils.logError(`Unexpected index ${index}`); return
|
|
|
|
}
|
2020-10-22 00:03:12 +02:00
|
|
|
const previousBlock = cardTree.contents[index - 1]
|
|
|
|
const newOrder = OctoUtils.getOrderBefore(previousBlock, cardTree.contents)
|
2020-10-20 21:50:53 +02:00
|
|
|
Utils.log(`moveUp ${newOrder}`)
|
2020-10-22 00:03:12 +02:00
|
|
|
mutator.changeOrder(block, newOrder, 'move up')
|
2020-10-20 21:52:56 +02:00
|
|
|
break
|
2020-10-20 21:50:53 +02:00
|
|
|
}
|
2020-10-22 00:03:12 +02:00
|
|
|
case 'moveDown': {
|
2020-10-20 21:50:53 +02:00
|
|
|
if (index >= cardTree.contents.length - 1) {
|
|
|
|
Utils.logError(`Unexpected index ${index}`); return
|
|
|
|
}
|
2020-10-22 00:03:12 +02:00
|
|
|
const nextBlock = cardTree.contents[index + 1]
|
|
|
|
const newOrder = OctoUtils.getOrderAfter(nextBlock, cardTree.contents)
|
2020-10-20 21:50:53 +02:00
|
|
|
Utils.log(`moveDown ${newOrder}`)
|
|
|
|
mutator.changeOrder(block, newOrder, 'move down')
|
2020-10-20 21:52:56 +02:00
|
|
|
break
|
2020-10-20 21:50:53 +02:00
|
|
|
}
|
2020-10-22 00:03:12 +02:00
|
|
|
case 'insertAbove-text': {
|
2020-10-21 03:28:55 +02:00
|
|
|
const newBlock = new MutableTextBlock()
|
|
|
|
newBlock.parentId = cardId
|
2020-10-20 21:50:53 +02:00
|
|
|
|
|
|
|
// TODO: Handle need to reorder all blocks
|
|
|
|
newBlock.order = OctoUtils.getOrderBefore(block, cardTree.contents)
|
|
|
|
Utils.log(`insert block ${block.id}, order: ${block.order}`)
|
|
|
|
mutator.insertBlock(newBlock, 'insert card text')
|
2020-10-22 00:03:12 +02:00
|
|
|
break
|
2020-10-20 21:50:53 +02:00
|
|
|
}
|
2020-10-22 00:03:12 +02:00
|
|
|
case 'insertAbove-image': {
|
|
|
|
Utils.selectLocalFile(
|
|
|
|
(file) => {
|
|
|
|
mutator.createImageBlock(cardId, file, OctoUtils.getOrderBefore(block, cardTree.contents))
|
2020-10-20 21:50:53 +02:00
|
|
|
},
|
|
|
|
'.jpg,.jpeg,.png')
|
|
|
|
|
2020-10-22 00:03:12 +02:00
|
|
|
break
|
|
|
|
}
|
2020-10-20 21:50:53 +02:00
|
|
|
case 'delete': {
|
|
|
|
mutator.deleteBlock(block)
|
2020-10-20 21:52:56 +02:00
|
|
|
break
|
2020-10-20 21:50:53 +02:00
|
|
|
}
|
2020-10-22 00:03:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
OldMenu.shared.showAtElement(e.target as HTMLElement)
|
2020-10-20 21:50:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private iconClicked(e: React.MouseEvent) {
|
2020-10-21 03:28:55 +02:00
|
|
|
const {cardTree} = this.state
|
|
|
|
const {card} = cardTree
|
2020-10-20 21:50:53 +02:00
|
|
|
|
|
|
|
OldMenu.shared.options = [
|
|
|
|
{id: 'random', name: 'Random'},
|
2020-10-22 00:03:12 +02:00
|
|
|
{id: 'remove', name: 'Remove Icon'},
|
2020-10-20 21:50:53 +02:00
|
|
|
]
|
|
|
|
OldMenu.shared.onMenuClicked = (optionId: string, type?: string) => {
|
2020-10-22 00:03:12 +02:00
|
|
|
switch (optionId) {
|
2020-10-20 21:50:53 +02:00
|
|
|
case 'remove':
|
|
|
|
mutator.changeIcon(card, undefined, 'remove icon')
|
2020-10-22 00:03:12 +02:00
|
|
|
break
|
|
|
|
case 'random':
|
2020-10-20 21:50:53 +02:00
|
|
|
const newIcon = BlockIcons.shared.randomIcon()
|
|
|
|
mutator.changeIcon(card, newIcon)
|
2020-10-22 00:03:12 +02:00
|
|
|
break
|
|
|
|
}
|
2020-10-20 21:50:53 +02:00
|
|
|
}
|
|
|
|
OldMenu.shared.showAtElement(e.target as HTMLElement)
|
|
|
|
}
|
|
|
|
|
|
|
|
close() {
|
|
|
|
OldMenu.shared.hide()
|
|
|
|
PropertyMenu.shared.hide()
|
|
|
|
}
|
2020-10-15 19:46:32 +02:00
|
|
|
}
|