Migrating property menu to the new menu system

This commit is contained in:
Jesús Espino 2020-10-26 10:52:33 +01:00
parent 4aa5a6a79b
commit eea16494cb
3 changed files with 136 additions and 145 deletions

View file

@ -4,14 +4,12 @@ import React from 'react'
import {FormattedMessage, IntlShape, injectIntl} from 'react-intl'
import {BlockIcons} from '../blockIcons'
import {MutableCommentBlock} from '../blocks/commentBlock'
import {MutableTextBlock} from '../blocks/textBlock'
import {BoardTree} from '../viewModel/boardTree'
import {CardTree, MutableCardTree} from '../viewModel/cardTree'
import mutator from '../mutator'
import {OctoListener} from '../octoListener'
import {OctoUtils} from '../octoUtils'
import {PropertyMenu} from '../propertyMenu'
import {Utils} from '../utils'
import MenuWrapper from '../widgets/menuWrapper'
@ -22,6 +20,7 @@ import {Editable} from './editable'
import {MarkdownEditor} from './markdownEditor'
import ContentBlock from './contentBlock'
import CommentsList from './commentsList'
import PropertyMenu from './propertyMenu'
import './cardDetail.scss'
@ -168,43 +167,13 @@ class CardDetail extends React.Component<Props, State> {
key={propertyTemplate.id}
className='octo-propertyrow'
>
<div
className='octo-button octo-propertyname'
onClick={(e) => {
const menu = PropertyMenu.shared
menu.property = propertyTemplate
menu.onNameChanged = (propertyName) => {
Utils.log('menu.onNameChanged')
mutator.renameProperty(board, propertyTemplate.id, propertyName)
}
menu.onMenuClicked = async (command) => {
switch (command) {
case 'type-text':
await mutator.changePropertyType(board, propertyTemplate, 'text')
break
case 'type-number':
await mutator.changePropertyType(board, propertyTemplate, 'number')
break
case 'type-createdTime':
await mutator.changePropertyType(board, propertyTemplate, 'createdTime')
break
case 'type-updatedTime':
await mutator.changePropertyType(board, propertyTemplate, 'updatedTime')
break
case 'type-select':
await mutator.changePropertyType(board, propertyTemplate, 'select')
break
case 'delete':
await mutator.deleteProperty(boardTree, propertyTemplate.id)
break
default:
Utils.assertFailure(`Unhandled menu id: ${command}`)
}
}
menu.showAtElement(e.target as HTMLElement)
}}
>{propertyTemplate.name}</div>
<MenuWrapper>
<div className='octo-button octo-propertyname'>{propertyTemplate.name}</div>
<PropertyMenu
property={propertyTemplate}
boardTree={boardTree}
/>
</MenuWrapper>
{OctoUtils.propertyValueEditableElement(card, propertyTemplate)}
</div>
)
@ -276,10 +245,6 @@ class CardDetail extends React.Component<Props, State> {
</>
)
}
close() {
PropertyMenu.shared.hide()
}
}
export default injectIntl(CardDetail)

View file

@ -0,0 +1,128 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react'
import {IPropertyTemplate, PropertyType} from '../blocks/board'
import {BoardTree} from '../viewModel/boardTree'
import {Utils} from '../utils'
import mutator from '../mutator'
import Menu from '../widgets/menu'
type Props = {
property: IPropertyTemplate
boardTree: BoardTree
}
type State = {
name: string
}
export default class PropertyMenu extends React.Component<Props, State> {
private nameTextbox = React.createRef<HTMLInputElement>()
public shouldComponentUpdate(): boolean {
return true
}
constructor(props: Props) {
super(props)
this.state = {
name: (this.props.property && this.props.property.name) || '',
}
}
public componentDidMount(): void {
this.nameTextbox.current.focus()
document.execCommand('selectAll', false, null)
}
private typeDisplayName(type: PropertyType): string {
switch (type) {
case 'text': return 'Text'
case 'number': return 'Number'
case 'select': return 'Select'
case 'multiSelect': return 'Multi Select'
case 'person': return 'Person'
case 'file': return 'File or Media'
case 'checkbox': return 'Checkbox'
case 'url': return 'URL'
case 'email': return 'Email'
case 'phone': return 'Phone'
case 'createdTime': return 'Created Time'
case 'createdBy': return 'Created By'
case 'updatedTime': return 'Updated Time'
case 'updatedBy': return 'Updated By'
default: {
Utils.assertFailure(`typeDisplayName, unhandled type: ${type}`)
return type
}
}
}
private saveName = (): void => {
if (this.state.name !== this.props.property.name) {
Utils.log('menu.onNameChanged')
mutator.renameProperty(this.props.boardTree.board, this.props.property.id, this.state.name)
}
}
public render(): JSX.Element {
const {boardTree, property} = this.props
const {board} = boardTree
return (
<Menu>
<input
ref={this.nameTextbox}
type='text'
className='menu-textbox'
onClick={(e) => e.stopPropagation()}
onChange={(e) => this.setState({name: e.target.value})}
value={this.state.name}
onBlur={this.saveName}
onKeyDown={(e) => {
if (e.keyCode === 13 || e.keyCode === 27) {
this.saveName()
e.stopPropagation()
}
}}
/>
<Menu.SubMenu
id='type'
name={this.typeDisplayName(this.props.property.type)}
>
<Menu.Text
id='text'
name='Text'
onClick={() => mutator.changePropertyType(board, property, 'text')}
/>
<Menu.Text
id='number'
name='Number'
onClick={() => mutator.changePropertyType(board, property, 'number')}
/>
<Menu.Text
id='select'
name='Select'
onClick={() => mutator.changePropertyType(board, property, 'select')}
/>
<Menu.Text
id='createdTime'
name='Created Time'
onClick={() => mutator.changePropertyType(board, property, 'createdTime')}
/>
<Menu.Text
id='updatedTime'
name='Updated Time'
onClick={() => mutator.changePropertyType(board, property, 'updatedTime')}
/>
</Menu.SubMenu>
<Menu.Text
id='delete'
name='Delete'
onClick={() => mutator.deleteProperty(boardTree, property.id)}
/>
</Menu>
)
}
}

View file

@ -1,102 +0,0 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {IPropertyTemplate, PropertyType} from './blocks/board'
import {Menu} from './menu'
import {Utils} from './utils'
class PropertyMenu extends Menu {
static shared = new PropertyMenu()
property: IPropertyTemplate
onNameChanged?: (name: string) => void
private nameTextbox: HTMLElement
constructor() {
super()
const typeMenuOptions = [
{id: 'text', name: 'Text'},
{id: 'number', name: 'Number'},
{id: 'select', name: 'Select'},
{id: 'createdTime', name: 'Created Time'},
{id: 'updatedTime', name: 'Updated Time'},
]
this.subMenuOptions.set('type', typeMenuOptions)
}
createMenuElement(): HTMLElement {
const menu = Utils.htmlToElement('<div class="menu noselect" style="min-width: 200px;"></div>')
const ul = menu.appendChild(Utils.htmlToElement('<ul class="menu-options"></ul>'))
const nameTextbox = ul.appendChild(Utils.htmlToElement('<li class="menu-textbox"></li>'))
this.nameTextbox = nameTextbox
let propertyValue = this.property ? this.property.name : ''
nameTextbox.innerText = propertyValue
nameTextbox.contentEditable = 'true'
nameTextbox.onclick = (e) => {
e.stopPropagation()
}
nameTextbox.onblur = () => {
if (nameTextbox.innerText !== propertyValue) {
propertyValue = nameTextbox.innerText
if (this.onNameChanged) {
this.onNameChanged(nameTextbox.innerText)
}
}
}
nameTextbox.onmouseenter = () => {
this.hideSubMenu()
}
nameTextbox.onkeydown = (e) => {
if (e.keyCode === 13 || e.keyCode === 27) {
nameTextbox.blur()
e.stopPropagation()
}
}
ul.appendChild(Utils.htmlToElement('<li class="menu-separator"></li>'))
this.appendMenuOptions(ul)
return menu
}
showAt(left: number, top: number): void {
this.options = [
{id: 'type', name: this.typeDisplayName(this.property.type), type: 'submenu'},
{id: 'delete', name: 'Delete'},
]
super.showAt(left, top)
setTimeout(() => {
this.nameTextbox.focus()
document.execCommand('selectAll', false, null)
}, 20)
}
private typeDisplayName(type: PropertyType): string {
switch (type) {
case 'text': return 'Text'
case 'number': return 'Number'
case 'select': return 'Select'
case 'multiSelect': return 'Multi Select'
case 'person': return 'Person'
case 'file': return 'File or Media'
case 'checkbox': return 'Checkbox'
case 'url': return 'URL'
case 'email': return 'Email'
case 'phone': return 'Phone'
case 'createdTime': return 'Created Time'
case 'createdBy': return 'Created By'
case 'updatedTime': return 'Updated Time'
case 'updatedBy': return 'Updated By'
default: {
Utils.assertFailure(`typeDisplayName, unhandled type: ${type}`)
return type
}
}
}
}
export {PropertyMenu}