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' class SideNav extends React.Component { // TODO: should not use electron stuff v0.7 componentDidMount () { EventEmitter.on('side:preferences', this.handleMenuButtonClick) } componentWillUnmount () { EventEmitter.off('side:preferences', this.handleMenuButtonClick) } handleMenuButtonClick (e) { openModal(PreferencesModal) } handleHomeButtonClick (e) { const { router } = this.context router.push('/home') } handleStarredButtonClick (e) { const { router } = this.context router.push('/starred') } 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 = (
this.handleHomeButtonClick(e)} isStarredActive={isStarredActive} isTrashedActive={isTrashedActive} handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)} handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)} counterTotalNote={data.noteMap._map.size - data.trashedSet._set.size} counterStarredNote={data.starredSet._set.size} counterDelNote={data.trashedSet._set.size} handleFilterButtonContextMenu={this.handleFilterButtonContextMenu.bind(this)} />
) } else { component = (

{i18n.__('Tags')}

{this.tagListComponent(data)}
) } return component } tagListComponent () { const { data, location, config } = this.props const relatedTags = this.getRelatedTags(this.getActiveTags(location.pathname), data.noteMap) let tagList = _.sortBy(data.tagNoteMap.map( (tag, name) => ({ name, size: tag.size, related: relatedTags.has(name) }) ), ['name']).filter( tag => tag.size > 0 ) if (config.sortTagsBy === 'COUNTER') { tagList = _.sortBy(tagList, item => (0 - item.size)) } if (config.ui.showOnlyRelatedTags && (relatedTags.size > 0)) { tagList = tagList.filter( tag => tag.related ) } return ( tagList.map(tag => { return ( ) }) ) } getRelatedTags (activeTags, noteMap) { if (activeTags.length === 0) { return new Set() } const relatedNotes = noteMap.map( note => ({key: note.key, tags: note.tags}) ).filter( note => activeTags.every(tag => note.tags.includes(tag)) ) const relatedTags = new Set() relatedNotes.forEach(note => note.tags.map(tag => relatedTags.add(tag))) return relatedTags } getTagActive (path, tag) { return this.getActiveTags(path).includes(tag) } getActiveTags (path) { const pathSegments = path.split('/') const tags = pathSegments[pathSegments.length - 1] return (tags === 'alltags') ? [] : tags.split(' ').map(tag => decodeURIComponent(tag)) } handleClickTagListItem (name) { const { router } = this.context router.push(`/tags/${encodeURIComponent(name)}`) } handleSortTagsByChange (e) { const { dispatch } = this.props const config = { sortTagsBy: e.target.value } ConfigManager.set(config) dispatch({ type: 'SET_CONFIG', config }) } handleClickNarrowToTag (tag) { const { router } = this.context const { location } = this.props const listOfTags = this.getActiveTags(location.pathname) const indexOfTag = listOfTags.indexOf(tag) if (indexOfTag > -1) { listOfTags.splice(indexOfTag, 1) } else { listOfTags.push(tag) } router.push(`/tags/${listOfTags.map(tag => encodeURIComponent(tag)).join(' ')}`) } emptyTrash (entries) { const { dispatch } = this.props const deletionPromises = entries.map((note) => { return dataApi.deleteNote(note.storage, note.key) }) Promise.all(deletionPromises) .then((arrayOfStorageAndNoteKeys) => { arrayOfStorageAndNoteKeys.forEach(({ storageKey, noteKey }) => { dispatch({ type: 'DELETE_NOTE', storageKey, noteKey }) }) }) .catch((err) => { console.error('Cannot Delete note: ' + err) }) console.log('Trash emptied') } handleFilterButtonContextMenu (event) { const { data } = this.props const trashedNotes = data.trashedSet.toJS().map((uniqueKey) => data.noteMap.get(uniqueKey)) context.popup([ { label: i18n.__('Empty Trash'), click: () => this.emptyTrash(trashedNotes) } ]) } render () { const { data, location, config, dispatch } = this.props const isFolded = config.isSideNavFolded const storageList = data.storageMap.map((storage, key) => { const SortableStorageItem = SortableContainer(StorageItem) return }) const style = {} if (!isFolded) style.width = this.props.width const isTagActive = location.pathname.match(/tag/) return (
{this.SideNavComponent(isFolded, storageList)}
) } } SideNav.contextTypes = { router: PropTypes.shape({}) } SideNav.propTypes = { dispatch: PropTypes.func, storages: PropTypes.array, config: PropTypes.shape({ isSideNavFolded: PropTypes.bool }), location: PropTypes.shape({ pathname: PropTypes.string }) } export default CSSModules(SideNav, styles)