import PropTypes from 'prop-types' import React from 'react' import CSSModules from 'browser/lib/CSSModules' 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 ConfigManager from 'browser/main/lib/ConfigManager' import StorageItem from './StorageItem' import TagListItem from 'browser/components/TagListItem' import SideNavFilter from 'browser/components/SideNavFilter' import StorageList from 'browser/components/StorageList' import NavToggleButton from 'browser/components/NavToggleButton' import EventEmitter from 'browser/main/lib/eventEmitter' import PreferenceButton from './PreferenceButton' import ListButton from './ListButton' import TagButton from './TagButton' import {SortableContainer} from 'react-sortable-hoc' import i18n from 'browser/lib/i18n' import context from 'browser/lib/context' import { remote } from 'electron' import { confirmDeleteNote } from 'browser/lib/confirmDeleteNote' import ColorPicker from 'browser/components/ColorPicker' function matchActiveTags (tags, activeTags) { return _.every(activeTags, v => tags.indexOf(v) >= 0) } class SideNav extends React.Component { // TODO: should not use electron stuff v0.7 constructor (props) { super(props) this.state = { colorPicker: { show: false, color: null, tagName: null, targetRect: null } } this.dismissColorPicker = this.dismissColorPicker.bind(this) this.handleColorPickerConfirm = this.handleColorPickerConfirm.bind(this) this.handleColorPickerReset = this.handleColorPickerReset.bind(this) } componentDidMount () { EventEmitter.on('side:preferences', this.handleMenuButtonClick) } componentWillUnmount () { EventEmitter.off('side:preferences', this.handleMenuButtonClick) } deleteTag (tag) { const selectedButton = remote.dialog.showMessageBox(remote.getCurrentWindow(), { ype: 'warning', message: i18n.__('Confirm tag deletion'), detail: i18n.__('This will permanently remove this tag.'), buttons: [i18n.__('Confirm'), i18n.__('Cancel')] }) if (selectedButton === 0) { const { data, dispatch, location, params } = this.props const notes = data.noteMap .map(note => note) .filter(note => note.tags.indexOf(tag) !== -1) .map(note => { note = Object.assign({}, note) note.tags = note.tags.slice() note.tags.splice(note.tags.indexOf(tag), 1) return note }) Promise .all(notes.map(note => dataApi.updateNote(note.storage, note.key, note))) .then(updatedNotes => { updatedNotes.forEach(note => { dispatch({ type: 'UPDATE_NOTE', note }) }) if (location.pathname.match('/tags')) { const tags = params.tagname.split(' ') const index = tags.indexOf(tag) if (index !== -1) { tags.splice(index, 1) this.context.router.push(`/tags/${tags.map(tag => encodeURIComponent(tag)).join(' ')}`) } } }) } } handleMenuButtonClick (e) { openModal(PreferencesModal) } handleHomeButtonClick (e) { const { router } = this.context router.push('/home') } handleStarredButtonClick (e) { const { router } = this.context router.push('/starred') } handleTagContextMenu (e, tag) { const menu = [] menu.push({ label: i18n.__('Delete Tag'), click: this.deleteTag.bind(this, tag) }) menu.push({ label: i18n.__('Customize Color'), click: this.displayColorPicker.bind(this, tag, e.target.getBoundingClientRect()) }) context.popup(menu) } dismissColorPicker () { this.setState({ colorPicker: { show: false } }) } displayColorPicker (tagName, rect) { const { config } = this.props this.setState({ colorPicker: { show: true, color: config.coloredTags[tagName], tagName, targetRect: rect } }) } handleColorPickerConfirm (color) { const { dispatch, config: {coloredTags} } = this.props const { colorPicker: { tagName } } = this.state const newColoredTags = Object.assign({}, coloredTags, {[tagName]: color.hex}) const config = { coloredTags: newColoredTags } ConfigManager.set(config) dispatch({ type: 'SET_CONFIG', config }) this.dismissColorPicker() } handleColorPickerReset () { const { dispatch, config: {coloredTags} } = this.props const { colorPicker: { tagName } } = this.state const newColoredTags = Object.assign({}, coloredTags) delete newColoredTags[tagName] const config = { coloredTags: newColoredTags } ConfigManager.set(config) dispatch({ type: 'SET_CONFIG', config }) this.dismissColorPicker() } handleToggleButtonClick (e) { const { dispatch, config } = this.props ConfigManager.set({isSideNavFolded: !config.isSideNavFolded}) dispatch({ type: 'SET_IS_SIDENAV_FOLDED', isFolded: !config.isSideNavFolded }) } handleTrashedButtonClick (e) { const { router } = this.context router.push('/trashed') } handleSwitchFoldersButtonClick () { const { router } = this.context router.push('/home') } handleSwitchTagsButtonClick () { const { router } = this.context router.push('/alltags') } onSortEnd (storage) { return ({oldIndex, newIndex}) => { const { dispatch } = this.props dataApi .reorderFolder(storage.key, oldIndex, newIndex) .then((data) => { dispatch({ type: 'REORDER_FOLDER', storage: data.storage }) }) } } SideNavComponent (isFolded, storageList) { const { location, data, config } = this.props const isHomeActive = !!location.pathname.match(/^\/home$/) const isStarredActive = !!location.pathname.match(/^\/starred$/) const isTrashedActive = !!location.pathname.match(/^\/trashed$/) let component // TagsMode is not selected if (!location.pathname.match('/tags') && !location.pathname.match('/alltags')) { component = (
{i18n.__('Tags')}