Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions browser/main/Detail/TagSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class TagSelect extends React.Component {
}

this.handleAddTag = this.handleAddTag.bind(this)
this.handleRenameTag = this.handleRenameTag.bind(this)
this.onInputBlur = this.onInputBlur.bind(this)
this.onInputChange = this.onInputChange.bind(this)
this.onInputKeyDown = this.onInputKeyDown.bind(this)
Expand Down Expand Up @@ -82,6 +83,7 @@ class TagSelect extends React.Component {
this.buildSuggestions()

ee.on('editor:add-tag', this.handleAddTag)
ee.on('sidebar:rename-tag', this.handleRenameTag)
}

componentDidUpdate () {
Expand All @@ -90,12 +92,23 @@ class TagSelect extends React.Component {

componentWillUnmount () {
ee.off('editor:add-tag', this.handleAddTag)
ee.off('sidebar:rename-tag', this.handleRenameTag)
}

handleAddTag () {
this.refs.newTag.input.focus()
}

handleRenameTag (event, tagChange) {
const { value } = this.props
const { tag, updatedTag } = tagChange
const newTags = value.slice()

newTags[value.indexOf(tag)] = updatedTag
this.value = newTags
this.props.onChange()
}

handleTagLabelClick (tag) {
const { dispatch } = this.props

Expand Down
16 changes: 16 additions & 0 deletions browser/main/SideNav/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import dataApi from 'browser/main/lib/dataApi'
import styles from './SideNav.styl'
import { openModal } from 'browser/main/lib/modal'
import PreferencesModal from '../modals/PreferencesModal'
import RenameTagModal from 'browser/main/modals/RenameTagModal'
import ConfigManager from 'browser/main/lib/ConfigManager'
import StorageItem from './StorageItem'
import TagListItem from 'browser/components/TagListItem'
Expand Down Expand Up @@ -128,6 +129,11 @@ class SideNav extends React.Component {
click: this.displayColorPicker.bind(this, tag, e.target.getBoundingClientRect())
})

menu.push({
label: i18n.__('Rename Tag'),
click: this.handleRenameTagClick.bind(this, tag)
})

context.popup(menu)
}

Expand All @@ -151,6 +157,16 @@ class SideNav extends React.Component {
})
}

handleRenameTagClick (tagName) {
const { data, dispatch } = this.props

openModal(RenameTagModal, {
tagName,
data,
dispatch
})
}

handleColorPickerConfirm (color) {
const { dispatch, config: {coloredTags} } = this.props
const { colorPicker: { tagName } } = this.state
Expand Down
2 changes: 1 addition & 1 deletion browser/main/modals/RenameFolderModal.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './RenameFolderModal.styl'
import styles from './RenameModal.styl'
import dataApi from 'browser/main/lib/dataApi'
import { store } from 'browser/main/store'
import ModalEscButton from 'browser/components/ModalEscButton'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@
margin 0 auto
colorPrimaryButton()

.error
text-align center
color #F44336
height 20px

body[data-theme="dark"]
.root
modalDark()
Expand All @@ -63,3 +68,51 @@ body[data-theme="dark"]

.control-confirmButton
colorDarkPrimaryButton()

body[data-theme="solarized-dark"]
.root
modalSolarizedDark()

.header
background-color transparent
border-color $ui-dark-borderColor
color $ui-solarized-dark-text-color

.control-input
border 1px solid $ui-dark-borderColor
color white

.control-confirmButton
colorSolarizedDarkPrimaryButton()

body[data-theme="monokai"]
.root
modalMonokai()

.header
background-color transparent
border-color $ui-dark-borderColor
color $ui-monokai-text-color

.control-input
border 1px solid $ui-dark-borderColor
color white

.control-confirmButton
colorMonokaiPrimaryButton()

body[data-theme="dracula"]
.root
modalDracula()

.header
background-color transparent
border-color $ui-dark-borderColor
color $ui-dracula-text-color

.control-input
border 1px solid $ui-dark-borderColor
color white

.control-confirmButton
colorDraculaPrimaryButton()
154 changes: 154 additions & 0 deletions browser/main/modals/RenameTagModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './RenameModal.styl'
import dataApi from 'browser/main/lib/dataApi'
import ModalEscButton from 'browser/components/ModalEscButton'
import i18n from 'browser/lib/i18n'
import { hashHistory } from 'react-router'
import ee from 'browser/main/lib/eventEmitter'
import { isEmpty } from 'lodash'

class RenameTagModal extends React.Component {
constructor (props) {
super(props)

this.nameInput = null

this.handleChange = this.handleChange.bind(this)

this.setTextInputRef = el => {
this.nameInput = el
}

this.state = {
name: props.tagName,
oldName: props.tagName
}
}

componentDidMount () {
this.nameInput.focus()
this.nameInput.select()
}

handleChange (e) {
this.setState({
name: this.nameInput.value,
showerror: false,
errormessage: ''
})
}

handleKeyDown (e) {
if (e.keyCode === 27) {
this.props.close()
}
}

handleInputKeyDown (e) {
switch (e.keyCode) {
case 13:
this.handleConfirm()
}
}

handleConfirm () {
if (this.state.name.trim().length > 0) {
const { name, oldName } = this.state
this.renameTag(oldName, name)
}
}

showError (message) {
this.setState({
showerror: true,
errormessage: message
})
}

renameTag (tag, updatedTag) {
const { data, dispatch } = this.props

const notes = data.noteMap
.map(note => note)
.filter(note => note.tags.indexOf(tag) !== -1 && note.tags.indexOf(updatedTag))
.map(note => {
note = Object.assign({}, note)
note.tags = note.tags.slice()

note.tags[note.tags.indexOf(tag)] = updatedTag

return note
})

if (isEmpty(notes)) {
this.showError(i18n.__('Tag exists'))

return
}

Promise
.all(notes.map(note => dataApi.updateNote(note.storage, note.key, note)))
.then(updatedNotes => {
updatedNotes.forEach(note => {
dispatch({
type: 'UPDATE_NOTE',
note
})
})
})
.then(() => {
if (window.location.hash.includes(tag)) {
hashHistory.replace(`/tags/${updatedTag}`)
}
ee.emit('sidebar:rename-tag', { tag, updatedTag })
this.props.close()
})
}

render () {
const { close } = this.props
const { errormessage } = this.state

return (
<div styleName='root'
tabIndex='-1'
onKeyDown={(e) => this.handleKeyDown(e)}
>
<div styleName='header'>
<div styleName='title'>{i18n.__('Rename Tag')}</div>
</div>
<ModalEscButton handleEscButtonClick={close} />

<div styleName='control'>
<input styleName='control-input'
placeholder={i18n.__('Tag Name')}
ref={this.setTextInputRef}
value={this.state.name}
onChange={this.handleChange}
onKeyDown={(e) => this.handleInputKeyDown(e)}
/>
<button styleName='control-confirmButton'
onClick={() => this.handleConfirm()}
>
{i18n.__('Confirm')}
</button>
</div>
<div className='error' styleName='error'>{errormessage}</div>
</div>
)
}
}

RenameTagModal.propTypes = {
storage: PropTypes.shape({
key: PropTypes.string
}),
folder: PropTypes.shape({
key: PropTypes.string,
name: PropTypes.string
})
}

export default CSSModules(RenameTagModal, styles)