mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-14 02:06:29 +00:00
Mutable
INIT_ALL, NOTE_MOVE, NOTE_UPDATE(create/update) done
This commit is contained in:
@@ -34,7 +34,7 @@ class NoteItem extends React.Component {
|
|||||||
? 'root--active'
|
? 'root--active'
|
||||||
: 'root'
|
: 'root'
|
||||||
}
|
}
|
||||||
key={note.uniqueKey}
|
key={note.storage + '-' + note.key}
|
||||||
onClick={(e) => this.handleClick(e)}
|
onClick={(e) => this.handleClick(e)}
|
||||||
>
|
>
|
||||||
<div styleName='border'/>
|
<div styleName='border'/>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class NoteList extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<NoteItem
|
<NoteItem
|
||||||
note={note}
|
note={note}
|
||||||
key={`${note.storage}-${note.folder}-${note.key}`}
|
key={`${note.storage}-${note.key}`}
|
||||||
storage={storage}
|
storage={storage}
|
||||||
folder={folder}
|
folder={folder}
|
||||||
isActive={index === _index}
|
isActive={index === _index}
|
||||||
|
|||||||
87
browser/lib/Mutable.js
Normal file
87
browser/lib/Mutable.js
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
class MutableMap {
|
||||||
|
constructor (iterable) {
|
||||||
|
this._map = new Map(iterable)
|
||||||
|
}
|
||||||
|
|
||||||
|
get (...args) {
|
||||||
|
return this._map.get(...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
set (...args) {
|
||||||
|
return this._map.set(...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete (...args) {
|
||||||
|
return this._map.delete(...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
has (...args) {
|
||||||
|
return this._map.has(...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
clear (...args) {
|
||||||
|
return this._map.clear(...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
forEach (...args) {
|
||||||
|
return this._map.forEach(...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
[Symbol.iterator] () {
|
||||||
|
return this._map[Symbol.iterator]()
|
||||||
|
}
|
||||||
|
|
||||||
|
map (cb) {
|
||||||
|
let result = []
|
||||||
|
for (let [key, value] of this._map) {
|
||||||
|
result.push(cb(value, key))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MutableSet {
|
||||||
|
constructor (iterable) {
|
||||||
|
if (iterable instanceof MutableSet) {
|
||||||
|
this._set = new Set(iterable._set)
|
||||||
|
} else {
|
||||||
|
this._set = new Set(iterable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add (...args) {
|
||||||
|
return this._set.add(...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
delete (...args) {
|
||||||
|
return this._set.delete(...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
forEach (...args) {
|
||||||
|
return this._map.forEach(...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
[Symbol.iterator] () {
|
||||||
|
return this._set[Symbol.iterator]()
|
||||||
|
}
|
||||||
|
|
||||||
|
map (cb) {
|
||||||
|
let result = []
|
||||||
|
this._set.forEach(function (value, key) {
|
||||||
|
result.push(cb(value, key))
|
||||||
|
})
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
toJS () {
|
||||||
|
return Array.from(this._set)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Mutable = {
|
||||||
|
Map: MutableMap,
|
||||||
|
Set: MutableSet
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Mutable
|
||||||
@@ -184,12 +184,12 @@ class FolderSelect extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { className, storages, value } = this.props
|
let { className, data, value } = this.props
|
||||||
let splitted = value.split('-')
|
let splitted = value.split('-')
|
||||||
let storageKey = splitted.shift()
|
let storageKey = splitted.shift()
|
||||||
let folderKey = splitted.shift()
|
let folderKey = splitted.shift()
|
||||||
let options = []
|
let options = []
|
||||||
storages.forEach((storage, index) => {
|
data.storageMap.forEach((storage, index) => {
|
||||||
storage.folders.forEach((folder) => {
|
storage.folders.forEach((folder) => {
|
||||||
options.push({
|
options.push({
|
||||||
storage: storage,
|
storage: storage,
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
|
|
||||||
componentWillReceiveProps (nextProps) {
|
componentWillReceiveProps (nextProps) {
|
||||||
if (nextProps.note.key !== this.props.note.key && !this.isMovingNote) {
|
if (nextProps.note.key !== this.props.note.key && !this.isMovingNote) {
|
||||||
|
if (this.saveQueue != null) this.saveNow()
|
||||||
this.setState({
|
this.setState({
|
||||||
note: Object.assign({}, nextProps.note),
|
note: Object.assign({}, nextProps.note),
|
||||||
isDeleting: false
|
isDeleting: false
|
||||||
@@ -45,6 +46,10 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
if (this.saveQueue != null) this.saveNow()
|
||||||
|
}
|
||||||
|
|
||||||
findTitle (value) {
|
findTitle (value) {
|
||||||
let splitted = value.split('\n')
|
let splitted = value.split('\n')
|
||||||
let title = null
|
let title = null
|
||||||
@@ -91,15 +96,23 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
save () {
|
save () {
|
||||||
clearTimeout(this.saveQueue)
|
clearTimeout(this.saveQueue)
|
||||||
this.saveQueue = setTimeout(() => {
|
this.saveQueue = setTimeout(() => {
|
||||||
|
this.saveNow()
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
saveNow () {
|
||||||
let { note, dispatch } = this.props
|
let { note, dispatch } = this.props
|
||||||
dispatch({
|
clearTimeout(this.saveQueue)
|
||||||
type: 'UPDATE_NOTE',
|
this.saveQueue = null
|
||||||
note: this.state.note
|
|
||||||
})
|
|
||||||
|
|
||||||
dataApi
|
dataApi
|
||||||
.updateNote(note.storage, note.folder, note.key, this.state.note)
|
.updateNote(note.storage, note.key, this.state.note)
|
||||||
}, 1000)
|
.then((note) => {
|
||||||
|
dispatch({
|
||||||
|
type: 'UPDATE_NOTE',
|
||||||
|
note: note
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFolderChange (e) {
|
handleFolderChange (e) {
|
||||||
@@ -110,7 +123,7 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
let newFolderKey = splitted.shift()
|
let newFolderKey = splitted.shift()
|
||||||
|
|
||||||
dataApi
|
dataApi
|
||||||
.moveNote(note.storage, note.folder, note.key, newStorageKey, newFolderKey)
|
.moveNote(note.storage, note.key, newStorageKey, newFolderKey)
|
||||||
.then((newNote) => {
|
.then((newNote) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
isMovingNote: true,
|
isMovingNote: true,
|
||||||
@@ -119,13 +132,13 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
let { dispatch, location } = this.props
|
let { dispatch, location } = this.props
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'MOVE_NOTE',
|
type: 'MOVE_NOTE',
|
||||||
note: note,
|
originNote: note,
|
||||||
newNote: newNote
|
note: newNote
|
||||||
})
|
})
|
||||||
hashHistory.replace({
|
hashHistory.replace({
|
||||||
pathname: location.pathname,
|
pathname: location.pathname,
|
||||||
query: {
|
query: {
|
||||||
key: newNote.uniqueKey
|
key: newNote.storage + '-' + newNote.key
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -210,7 +223,7 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { storages, config } = this.props
|
let { data, config } = this.props
|
||||||
let { note } = this.state
|
let { note } = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -243,7 +256,7 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
<FolderSelect styleName='info-left-top-folderSelect'
|
<FolderSelect styleName='info-left-top-folderSelect'
|
||||||
value={this.state.note.storage + '-' + this.state.note.folder}
|
value={this.state.note.storage + '-' + this.state.note.folder}
|
||||||
ref='folder'
|
ref='folder'
|
||||||
storages={storages}
|
data={data}
|
||||||
onChange={(e) => this.handleFolderChange(e)}
|
onChange={(e) => this.handleFolderChange(e)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
|
|
||||||
componentWillReceiveProps (nextProps) {
|
componentWillReceiveProps (nextProps) {
|
||||||
if (nextProps.note.key !== this.props.note.key) {
|
if (nextProps.note.key !== this.props.note.key) {
|
||||||
|
if (this.saveQueue != null) this.saveNow()
|
||||||
let nextNote = Object.assign({
|
let nextNote = Object.assign({
|
||||||
description: ''
|
description: ''
|
||||||
}, nextProps.note, {
|
}, nextProps.note, {
|
||||||
@@ -67,6 +68,10 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
if (this.saveQueue != null) this.saveNow()
|
||||||
|
}
|
||||||
|
|
||||||
findTitle (value) {
|
findTitle (value) {
|
||||||
let splitted = value.split('\n')
|
let splitted = value.split('\n')
|
||||||
let title = null
|
let title = null
|
||||||
@@ -113,15 +118,23 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
save () {
|
save () {
|
||||||
clearTimeout(this.saveQueue)
|
clearTimeout(this.saveQueue)
|
||||||
this.saveQueue = setTimeout(() => {
|
this.saveQueue = setTimeout(() => {
|
||||||
|
this.saveNow()
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
saveNow () {
|
||||||
let { note, dispatch } = this.props
|
let { note, dispatch } = this.props
|
||||||
dispatch({
|
clearTimeout(this.saveQueue)
|
||||||
type: 'UPDATE_NOTE',
|
this.saveQueue = null
|
||||||
note: this.state.note
|
|
||||||
})
|
|
||||||
|
|
||||||
dataApi
|
dataApi
|
||||||
.updateNote(note.storage, note.folder, note.key, this.state.note)
|
.updateNote(note.storage, note.key, this.state.note)
|
||||||
}, 1000)
|
.then((note) => {
|
||||||
|
dispatch({
|
||||||
|
type: 'UPDATE_NOTE',
|
||||||
|
note: note
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFolderChange (e) {
|
handleFolderChange (e) {
|
||||||
@@ -132,7 +145,7 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
let newFolderKey = splitted.shift()
|
let newFolderKey = splitted.shift()
|
||||||
|
|
||||||
dataApi
|
dataApi
|
||||||
.moveNote(note.storage, note.folder, note.key, newStorageKey, newFolderKey)
|
.moveNote(note.storage, note.key, newStorageKey, newFolderKey)
|
||||||
.then((newNote) => {
|
.then((newNote) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
isMovingNote: true,
|
isMovingNote: true,
|
||||||
@@ -141,13 +154,13 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
let { dispatch, location } = this.props
|
let { dispatch, location } = this.props
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'MOVE_NOTE',
|
type: 'MOVE_NOTE',
|
||||||
note: note,
|
originNote: note,
|
||||||
newNote: newNote
|
note: newNote
|
||||||
})
|
})
|
||||||
hashHistory.replace({
|
hashHistory.replace({
|
||||||
pathname: location.pathname,
|
pathname: location.pathname,
|
||||||
query: {
|
query: {
|
||||||
key: newNote.uniqueKey
|
key: newNote.storage + '-' + newNote.key
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -321,7 +334,7 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { storages, config } = this.props
|
let { data, config } = this.props
|
||||||
let { note } = this.state
|
let { note } = this.state
|
||||||
|
|
||||||
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
||||||
@@ -434,7 +447,7 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
<FolderSelect styleName='info-left-top-folderSelect'
|
<FolderSelect styleName='info-left-top-folderSelect'
|
||||||
value={this.state.note.storage + '-' + this.state.note.folder}
|
value={this.state.note.storage + '-' + this.state.note.folder}
|
||||||
ref='folder'
|
ref='folder'
|
||||||
storages={storages}
|
data={data}
|
||||||
onChange={(e) => this.handleFolderChange(e)}
|
onChange={(e) => this.handleFolderChange(e)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -31,19 +31,14 @@ class Detail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { location, notes, config } = this.props
|
let { location, data, config } = this.props
|
||||||
let note = null
|
let note = null
|
||||||
if (location.query.key != null) {
|
if (location.query.key != null) {
|
||||||
let splitted = location.query.key.split('-')
|
let splitted = location.query.key.split('-')
|
||||||
let storageKey = splitted.shift()
|
let storageKey = splitted.shift()
|
||||||
let folderKey = splitted.shift()
|
|
||||||
let noteKey = splitted.shift()
|
let noteKey = splitted.shift()
|
||||||
|
|
||||||
note = _.find(notes, {
|
note = data.noteMap.get(storageKey + '-' + noteKey)
|
||||||
storage: storageKey,
|
|
||||||
folder: folderKey,
|
|
||||||
key: noteKey
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (note == null) {
|
if (note == null) {
|
||||||
@@ -67,7 +62,7 @@ class Detail extends React.Component {
|
|||||||
ref='root'
|
ref='root'
|
||||||
{..._.pick(this.props, [
|
{..._.pick(this.props, [
|
||||||
'dispatch',
|
'dispatch',
|
||||||
'storages',
|
'data',
|
||||||
'style',
|
'style',
|
||||||
'ignorePreviewPointerEvents',
|
'ignorePreviewPointerEvents',
|
||||||
'location'
|
'location'
|
||||||
@@ -83,7 +78,7 @@ class Detail extends React.Component {
|
|||||||
ref='root'
|
ref='root'
|
||||||
{..._.pick(this.props, [
|
{..._.pick(this.props, [
|
||||||
'dispatch',
|
'dispatch',
|
||||||
'storages',
|
'data',
|
||||||
'style',
|
'style',
|
||||||
'ignorePreviewPointerEvents',
|
'ignorePreviewPointerEvents',
|
||||||
'location'
|
'location'
|
||||||
@@ -95,7 +90,6 @@ class Detail extends React.Component {
|
|||||||
|
|
||||||
Detail.propTypes = {
|
Detail.propTypes = {
|
||||||
dispatch: PropTypes.func,
|
dispatch: PropTypes.func,
|
||||||
storages: PropTypes.array,
|
|
||||||
style: PropTypes.shape({
|
style: PropTypes.shape({
|
||||||
left: PropTypes.number
|
left: PropTypes.number
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ class Main extends React.Component {
|
|||||||
<SideNav
|
<SideNav
|
||||||
{..._.pick(this.props, [
|
{..._.pick(this.props, [
|
||||||
'dispatch',
|
'dispatch',
|
||||||
'storages',
|
'data',
|
||||||
'config',
|
'config',
|
||||||
'location'
|
'location'
|
||||||
])}
|
])}
|
||||||
@@ -112,9 +112,8 @@ class Main extends React.Component {
|
|||||||
<TopBar style={{width: this.state.listWidth}}
|
<TopBar style={{width: this.state.listWidth}}
|
||||||
{..._.pick(this.props, [
|
{..._.pick(this.props, [
|
||||||
'dispatch',
|
'dispatch',
|
||||||
'storages',
|
|
||||||
'config',
|
'config',
|
||||||
'notes',
|
'data',
|
||||||
'params',
|
'params',
|
||||||
'location'
|
'location'
|
||||||
])}
|
])}
|
||||||
@@ -122,8 +121,7 @@ class Main extends React.Component {
|
|||||||
<NoteList style={{width: this.state.listWidth}}
|
<NoteList style={{width: this.state.listWidth}}
|
||||||
{..._.pick(this.props, [
|
{..._.pick(this.props, [
|
||||||
'dispatch',
|
'dispatch',
|
||||||
'storages',
|
'data',
|
||||||
'notes',
|
|
||||||
'config',
|
'config',
|
||||||
'params',
|
'params',
|
||||||
'location'
|
'location'
|
||||||
@@ -140,8 +138,7 @@ class Main extends React.Component {
|
|||||||
style={{left: this.state.listWidth + 1}}
|
style={{left: this.state.listWidth + 1}}
|
||||||
{..._.pick(this.props, [
|
{..._.pick(this.props, [
|
||||||
'dispatch',
|
'dispatch',
|
||||||
'storages',
|
'data',
|
||||||
'notes',
|
|
||||||
'config',
|
'config',
|
||||||
'params',
|
'params',
|
||||||
'location'
|
'location'
|
||||||
@@ -159,7 +156,7 @@ class Main extends React.Component {
|
|||||||
|
|
||||||
Main.propTypes = {
|
Main.propTypes = {
|
||||||
dispatch: PropTypes.func,
|
dispatch: PropTypes.func,
|
||||||
repositories: PropTypes.array
|
data: PropTypes.shape({}).isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect((x) => x)(CSSModules(Main, styles))
|
export default connect((x) => x)(CSSModules(Main, styles))
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class NoteList extends React.Component {
|
|||||||
router.replace({
|
router.replace({
|
||||||
pathname: location.pathname,
|
pathname: location.pathname,
|
||||||
query: {
|
query: {
|
||||||
key: this.notes[0].uniqueKey
|
key: this.notes[0].storage + '-' + this.notes[0].key
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -52,7 +52,7 @@ class NoteList extends React.Component {
|
|||||||
// Auto scroll
|
// Auto scroll
|
||||||
if (_.isString(location.query.key)) {
|
if (_.isString(location.query.key)) {
|
||||||
let targetIndex = _.findIndex(this.notes, (note) => {
|
let targetIndex = _.findIndex(this.notes, (note) => {
|
||||||
return note.uniqueKey === location.query.key
|
return note != null && note.storage + '-' + note.key === location.query.key
|
||||||
})
|
})
|
||||||
if (targetIndex > -1) {
|
if (targetIndex > -1) {
|
||||||
let list = this.refs.root
|
let list = this.refs.root
|
||||||
@@ -153,30 +153,33 @@ class NoteList extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getNotes () {
|
getNotes () {
|
||||||
let { storages, notes, params, location } = this.props
|
let { data, params, location } = this.props
|
||||||
|
|
||||||
if (location.pathname.match(/\/home/)) {
|
if (location.pathname.match(/\/home/)) {
|
||||||
return notes
|
return data.noteMap.map((note) => note)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (location.pathname.match(/\/starred/)) {
|
if (location.pathname.match(/\/starred/)) {
|
||||||
return notes
|
return data.starredSet.toJS()
|
||||||
.filter((note) => note.isStarred)
|
.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
let storageKey = params.storageKey
|
let storageKey = params.storageKey
|
||||||
let folderKey = params.folderKey
|
let folderKey = params.folderKey
|
||||||
let storage = _.find(storages, {key: storageKey})
|
let storage = data.storageMap.get(storageKey)
|
||||||
if (storage == null) return []
|
if (storage == null) return []
|
||||||
|
|
||||||
let folder = _.find(storage.folders, {key: folderKey})
|
let folder = _.find(storage.folders, {key: folderKey})
|
||||||
if (folder == null) {
|
if (folder == null) {
|
||||||
return notes
|
return data.storeageNoteMap
|
||||||
.filter((note) => note.storage === storageKey)
|
.get(storage.key)
|
||||||
|
.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
return notes
|
let folderNoteKeyList = data.folderNoteMap
|
||||||
.filter((note) => note.folder === folderKey)
|
.get(storage.key + '-' + folder.key)
|
||||||
|
return folderNoteKeyList
|
||||||
|
.map((uniqueKey) => data.noteMap.get(uniqueKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNoteClick (uniqueKey) {
|
handleNoteClick (uniqueKey) {
|
||||||
@@ -194,13 +197,14 @@ class NoteList extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { location, storages, notes } = this.props
|
let { location, data, notes } = this.props
|
||||||
this.notes = notes = this.getNotes()
|
this.notes = notes = this.getNotes()
|
||||||
.sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt))
|
.sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt))
|
||||||
|
|
||||||
let noteList = notes
|
let noteList = notes
|
||||||
.map((note) => {
|
.map((note) => {
|
||||||
let storage = _.find(storages, {key: note.storage})
|
if (note == null) return null
|
||||||
|
let storage = data.storageMap.get(note.storage)
|
||||||
let folder = _.find(storage.folders, {key: note.folder})
|
let folder = _.find(storage.folders, {key: note.folder})
|
||||||
let tagElements = _.isArray(note.tags)
|
let tagElements = _.isArray(note.tags)
|
||||||
? note.tags.map((tag) => {
|
? note.tags.map((tag) => {
|
||||||
@@ -212,14 +216,14 @@ class NoteList extends React.Component {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
: []
|
: []
|
||||||
let isActive = location.query.key === note.uniqueKey
|
let isActive = location.query.key === note.storage + '-' + note.key
|
||||||
return (
|
return (
|
||||||
<div styleName={isActive
|
<div styleName={isActive
|
||||||
? 'item--active'
|
? 'item--active'
|
||||||
: 'item'
|
: 'item'
|
||||||
}
|
}
|
||||||
key={note.uniqueKey}
|
key={note.storage + '-' + note.key}
|
||||||
onClick={(e) => this.handleNoteClick(note.uniqueKey)(e)}
|
onClick={(e) => this.handleNoteClick(note.storage + '-' + note.key)(e)}
|
||||||
>
|
>
|
||||||
<div styleName='item-border'/>
|
<div styleName='item-border'/>
|
||||||
<div styleName='item-info'>
|
<div styleName='item-info'>
|
||||||
|
|||||||
@@ -36,12 +36,13 @@ class SideNav extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
let { storages, location, config } = this.props
|
let { data, location, config } = this.props
|
||||||
|
|
||||||
let isFolded = config.isSideNavFolded
|
let isFolded = config.isSideNavFolded
|
||||||
let isHomeActive = location.pathname.match(/^\/home$/)
|
let isHomeActive = location.pathname.match(/^\/home$/)
|
||||||
let isStarredActive = location.pathname.match(/^\/starred$/)
|
let isStarredActive = location.pathname.match(/^\/starred$/)
|
||||||
let storageList = storages.map((storage) => {
|
|
||||||
|
let storageList = data.storageMap.map((storage, key) => {
|
||||||
return <StorageItem
|
return <StorageItem
|
||||||
key={storage.key}
|
key={storage.key}
|
||||||
storage={storage}
|
storage={storage}
|
||||||
|
|||||||
@@ -33,9 +33,16 @@ class TopBar extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleNewPostButtonClick (e) {
|
handleNewPostButtonClick (e) {
|
||||||
let { storages, params, dispatch, location } = this.props
|
let { data, params, dispatch, location } = this.props
|
||||||
let storage = _.find(storages, {key: params.storageKey})
|
let storage = data.storageMap.get(params.storageKey)
|
||||||
if (storage == null) storage = storages[0]
|
|
||||||
|
// Find first storage
|
||||||
|
if (storage == null) {
|
||||||
|
for (let kv of data.storageMap) {
|
||||||
|
storage = kv[1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
if (storage == null) throw new Error('No storage to create a note')
|
if (storage == null) throw new Error('No storage to create a note')
|
||||||
let folder = _.find(storage.folders, {key: params.folderKey})
|
let folder = _.find(storage.folders, {key: params.folderKey})
|
||||||
if (folder == null) folder = storage.folders[0]
|
if (folder == null) folder = storage.folders[0]
|
||||||
|
|||||||
@@ -24,23 +24,26 @@ class NewNoteModal extends React.Component {
|
|||||||
handleMarkdownNoteButtonClick (e) {
|
handleMarkdownNoteButtonClick (e) {
|
||||||
let { storage, folder, dispatch, location } = this.props
|
let { storage, folder, dispatch, location } = this.props
|
||||||
dataApi
|
dataApi
|
||||||
.createMarkdownNote(storage, folder, {
|
.createNote(storage, {
|
||||||
|
type: 'MARKDOWN_NOTE',
|
||||||
|
folder: folder,
|
||||||
title: '',
|
title: '',
|
||||||
content: ''
|
content: ''
|
||||||
})
|
})
|
||||||
.then((note) => {
|
.then((note) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'CREATE_NOTE',
|
type: 'UPDATE_NOTE',
|
||||||
note: note
|
note: note
|
||||||
})
|
})
|
||||||
hashHistory.push({
|
hashHistory.push({
|
||||||
pathname: location.pathname,
|
pathname: location.pathname,
|
||||||
query: {key: note.uniqueKey}
|
query: {key: note.storage + '-' + note.key}
|
||||||
})
|
})
|
||||||
ee.emit('detail:focus')
|
ee.emit('detail:focus')
|
||||||
this.props.close()
|
this.props.close()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMarkdownNoteButtonKeyDown (e) {
|
handleMarkdownNoteButtonKeyDown (e) {
|
||||||
if (e.keyCode === 9) {
|
if (e.keyCode === 9) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@@ -50,8 +53,11 @@ class NewNoteModal extends React.Component {
|
|||||||
|
|
||||||
handleSnippetNoteButtonClick (e) {
|
handleSnippetNoteButtonClick (e) {
|
||||||
let { storage, folder, dispatch, location } = this.props
|
let { storage, folder, dispatch, location } = this.props
|
||||||
|
|
||||||
dataApi
|
dataApi
|
||||||
.createSnippetNote(storage, folder, {
|
.createNote(storage, {
|
||||||
|
type: 'SNIPPET_NOTE',
|
||||||
|
folder: folder,
|
||||||
title: '',
|
title: '',
|
||||||
description: '',
|
description: '',
|
||||||
snippets: [{
|
snippets: [{
|
||||||
@@ -62,12 +68,12 @@ class NewNoteModal extends React.Component {
|
|||||||
})
|
})
|
||||||
.then((note) => {
|
.then((note) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'CREATE_NOTE',
|
type: 'UPDATE_NOTE',
|
||||||
note: note
|
note: note
|
||||||
})
|
})
|
||||||
hashHistory.push({
|
hashHistory.push({
|
||||||
pathname: location.pathname,
|
pathname: location.pathname,
|
||||||
query: {key: note.uniqueKey}
|
query: {key: note.storage + '-' + note.key}
|
||||||
})
|
})
|
||||||
ee.emit('detail:focus')
|
ee.emit('detail:focus')
|
||||||
this.props.close()
|
this.props.close()
|
||||||
|
|||||||
@@ -1,94 +1,270 @@
|
|||||||
import { combineReducers, createStore } from 'redux'
|
import { combineReducers, createStore } from 'redux'
|
||||||
import { routerReducer } from 'react-router-redux'
|
import { routerReducer } from 'react-router-redux'
|
||||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||||
|
import { Map, Set } from 'browser/lib/Mutable'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
function storages (state = [], action) {
|
function defaultDataMap () {
|
||||||
console.info('REDUX >> ', action)
|
return {
|
||||||
|
storageMap: new Map(),
|
||||||
|
noteMap: new Map(),
|
||||||
|
starredSet: new Set(),
|
||||||
|
storeageNoteMap: new Map(),
|
||||||
|
folderNoteMap: new Map(),
|
||||||
|
tagNoteMap: new Map()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function data (state = defaultDataMap(), action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'INIT_ALL':
|
case 'INIT_ALL':
|
||||||
return action.storages
|
state = defaultDataMap()
|
||||||
case 'ADD_STORAGE':
|
|
||||||
{
|
|
||||||
let storages = state.slice()
|
|
||||||
|
|
||||||
storages.push(action.storage)
|
action.storages.forEach((storage) => {
|
||||||
|
state.storageMap.set(storage.key, storage)
|
||||||
|
})
|
||||||
|
|
||||||
return storages
|
action.notes.forEach((note) => {
|
||||||
}
|
let uniqueKey = note.storage + '-' + note.key
|
||||||
case 'ADD_FOLDER':
|
let folderKey = note.storage + '-' + note.folder
|
||||||
case 'REMOVE_FOLDER':
|
state.noteMap.set(uniqueKey, note)
|
||||||
case 'UPDATE_STORAGE':
|
|
||||||
case 'RENAME_STORAGE':
|
|
||||||
{
|
|
||||||
let storages = state.slice()
|
|
||||||
storages = storages
|
|
||||||
.filter((storage) => storage.key !== action.storage.key)
|
|
||||||
storages.push(action.storage)
|
|
||||||
|
|
||||||
return storages
|
if (note.isStarred) {
|
||||||
|
state.starredSet.add(uniqueKey)
|
||||||
}
|
}
|
||||||
case 'REMOVE_STORAGE':
|
|
||||||
{
|
|
||||||
let storages = state.slice()
|
|
||||||
storages = storages
|
|
||||||
.filter((storage) => storage.key !== action.key)
|
|
||||||
|
|
||||||
return storages
|
let storageNoteList = state.storeageNoteMap.get(note.storage)
|
||||||
|
if (storageNoteList == null) {
|
||||||
|
storageNoteList = new Set(storageNoteList)
|
||||||
|
state.storeageNoteMap.set(note.storage, storageNoteList)
|
||||||
}
|
}
|
||||||
|
storageNoteList.add(uniqueKey)
|
||||||
|
|
||||||
|
let folderNoteList = state.folderNoteMap.get(folderKey)
|
||||||
|
if (folderNoteList == null) {
|
||||||
|
folderNoteList = new Set(folderNoteList)
|
||||||
|
state.folderNoteMap.set(folderKey, folderNoteList)
|
||||||
}
|
}
|
||||||
|
folderNoteList.add(uniqueKey)
|
||||||
|
|
||||||
|
note.tags.forEach((tag) => {
|
||||||
|
let tagNoteList = state.tagNoteMap.get(tag)
|
||||||
|
if (tagNoteList == null) {
|
||||||
|
tagNoteList = new Set(tagNoteList)
|
||||||
|
state.tagNoteMap.set(tag, tagNoteList)
|
||||||
|
}
|
||||||
|
tagNoteList.add(uniqueKey)
|
||||||
|
})
|
||||||
|
})
|
||||||
return state
|
return state
|
||||||
}
|
|
||||||
|
|
||||||
function notes (state = [], action) {
|
|
||||||
switch (action.type) {
|
|
||||||
case 'INIT_ALL':
|
|
||||||
return action.notes
|
|
||||||
case 'ADD_STORAGE':
|
|
||||||
{
|
|
||||||
let notes = state.concat(action.notes)
|
|
||||||
return notes
|
|
||||||
}
|
|
||||||
case 'REMOVE_STORAGE':
|
|
||||||
{
|
|
||||||
let notes = state.slice()
|
|
||||||
notes = notes
|
|
||||||
.filter((note) => note.storage !== action.key)
|
|
||||||
|
|
||||||
return notes
|
|
||||||
}
|
|
||||||
case 'REMOVE_FOLDER':
|
|
||||||
{
|
|
||||||
let notes = state.slice()
|
|
||||||
notes = notes
|
|
||||||
.filter((note) => note.storage !== action.storage.key || note.folder !== action.key)
|
|
||||||
|
|
||||||
return notes
|
|
||||||
}
|
|
||||||
case 'CREATE_NOTE':
|
|
||||||
{
|
|
||||||
let notes = state.slice()
|
|
||||||
notes.push(action.note)
|
|
||||||
return notes
|
|
||||||
}
|
|
||||||
case 'UPDATE_NOTE':
|
case 'UPDATE_NOTE':
|
||||||
{
|
{
|
||||||
let notes = state.slice()
|
let note = action.note
|
||||||
notes = notes.filter((note) => note.key !== action.note.key || note.folder !== action.note.folder || note.storage !== action.note.storage)
|
let uniqueKey = note.storage + '-' + note.key
|
||||||
notes.push(action.note)
|
let folderKey = note.storage + '-' + note.folder
|
||||||
return notes
|
let oldNote = state.noteMap.get(uniqueKey)
|
||||||
|
|
||||||
|
state = Object.assign({}, state)
|
||||||
|
state.noteMap = new Map(state.noteMap)
|
||||||
|
state.noteMap.set(uniqueKey, note)
|
||||||
|
|
||||||
|
if (oldNote == null || oldNote.isStarred !== note.isStarred) {
|
||||||
|
state.starredSet = new Set(state.starredSet)
|
||||||
|
if (note.isStarred) {
|
||||||
|
state.starredSet.add(uniqueKey)
|
||||||
|
} else {
|
||||||
|
state.starredSet.delete(uniqueKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update storageNoteMap if oldNote doesn't exist
|
||||||
|
if (oldNote == null) {
|
||||||
|
state.storeageNoteMap = new Map(state.storeageNoteMap)
|
||||||
|
let noteSet = state.storeageNoteMap.get(note.storage)
|
||||||
|
noteSet = new Set(noteSet)
|
||||||
|
noteSet.add(uniqueKey)
|
||||||
|
state.folderNoteMap.set(folderKey, noteSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update foldermap if folder changed or post created
|
||||||
|
if (oldNote == null || oldNote.folder !== note.folder) {
|
||||||
|
state.folderNoteMap = new Map(state.folderNoteMap)
|
||||||
|
let folderNoteList = state.folderNoteMap.get(folderKey)
|
||||||
|
folderNoteList = new Set(folderNoteList)
|
||||||
|
folderNoteList.add(uniqueKey)
|
||||||
|
state.folderNoteMap.set(folderKey, folderNoteList)
|
||||||
|
|
||||||
|
if (oldNote != null) {
|
||||||
|
let oldFolderKey = oldNote.storage + '-' + oldNote.folder
|
||||||
|
let oldFolderNoteList = state.folderNoteMap.get(oldFolderKey)
|
||||||
|
oldFolderNoteList = new Set(oldFolderNoteList)
|
||||||
|
oldFolderNoteList.delete(uniqueKey)
|
||||||
|
state.folderNoteMap.set(oldFolderKey, oldFolderNoteList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldNote != null) {
|
||||||
|
let discardedTags = _.difference(oldNote.tags, note.tags)
|
||||||
|
let addedTags = _.difference(note.tags, oldNote.tags)
|
||||||
|
if (discardedTags.length + addedTags.length > 0) {
|
||||||
|
state.tagNoteMap = new Map(state.tagNoteMap)
|
||||||
|
|
||||||
|
discardedTags.forEach((tag) => {
|
||||||
|
let tagNoteList = state.tagNoteMap.get(tag)
|
||||||
|
if (tagNoteList != null) {
|
||||||
|
tagNoteList = new Set(tagNoteList)
|
||||||
|
tagNoteList.delete(uniqueKey)
|
||||||
|
state.tagNoteMap.set(tag, tagNoteList)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
addedTags.forEach((tag) => {
|
||||||
|
let tagNoteList = state.tagNoteMap.get(tag)
|
||||||
|
tagNoteList = new Set(tagNoteList)
|
||||||
|
tagNoteList.add(uniqueKey)
|
||||||
|
|
||||||
|
state.tagNoteMap.set(tag, tagNoteList)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.tagNoteMap = new Map(state.tagNoteMap)
|
||||||
|
note.tags.forEach((tag) => {
|
||||||
|
let tagNoteList = state.tagNoteMap.get(tag)
|
||||||
|
if (tagNoteList == null) {
|
||||||
|
tagNoteList = new Set(tagNoteList)
|
||||||
|
state.tagNoteMap.set(tag, tagNoteList)
|
||||||
|
}
|
||||||
|
tagNoteList.add(uniqueKey)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
}
|
}
|
||||||
case 'MOVE_NOTE':
|
case 'MOVE_NOTE':
|
||||||
{
|
{
|
||||||
let notes = state.slice()
|
let originNote = action.originNote
|
||||||
notes = notes.filter((note) => note.key !== action.note.key || note.folder !== action.note.folder || note.storage !== action.note.storage)
|
let originKey = originNote.storage + '-' + originNote.key
|
||||||
notes.push(action.newNote)
|
let note = action.note
|
||||||
return notes
|
let uniqueKey = note.storage + '-' + note.key
|
||||||
|
let folderKey = note.storage + '-' + note.folder
|
||||||
|
let oldNote = state.noteMap.get(uniqueKey)
|
||||||
|
|
||||||
|
state = Object.assign({}, state)
|
||||||
|
state.noteMap = new Map(state.noteMap)
|
||||||
|
state.noteMap.delete(originKey)
|
||||||
|
state.noteMap.set(uniqueKey, note)
|
||||||
|
|
||||||
|
// If storage chanced, origin key must be discarded
|
||||||
|
if (originKey !== uniqueKey) {
|
||||||
|
console.log('diffrent storage')
|
||||||
|
// From isStarred
|
||||||
|
if (originNote.isStarred) {
|
||||||
|
state.starredSet = new Set(state.starredSet)
|
||||||
|
state.starredSet.delete(originKey)
|
||||||
}
|
}
|
||||||
case 'REMOVE_NOTE':
|
|
||||||
|
// From storageNoteMap
|
||||||
|
state.storeageNoteMap = new Map(state.storeageNoteMap)
|
||||||
|
let noteSet = state.storeageNoteMap.get(originNote.storage)
|
||||||
|
noteSet = new Set(noteSet)
|
||||||
|
noteSet.delete(originKey)
|
||||||
|
state.storeageNoteMap.set(originNote.storage, noteSet)
|
||||||
|
|
||||||
|
// From folderNoteMap
|
||||||
|
state.folderNoteMap = new Map(state.folderNoteMap)
|
||||||
|
let originFolderKey = originNote.storage + '-' + originNote.folder
|
||||||
|
let originFolderList = state.folderNoteMap.get(originFolderKey)
|
||||||
|
originFolderList = new Set(originFolderList)
|
||||||
|
originFolderList.delete(originKey)
|
||||||
|
state.folderNoteMap.set(originFolderKey, originFolderList)
|
||||||
|
|
||||||
|
// From tagMap
|
||||||
|
if (originNote.tags.length > 0) {
|
||||||
|
state.tagNoteMap = new Map(state.tagNoteMap)
|
||||||
|
originNote.tags.forEach((tag) => {
|
||||||
|
let noteSet = state.tagNoteMap.get(tag)
|
||||||
|
noteSet = new Set(noteSet)
|
||||||
|
noteSet.delete(originKey)
|
||||||
|
state.tagNoteMap.set(tag, noteSet)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldNote == null || oldNote.isStarred !== note.isStarred) {
|
||||||
|
state.starredSet = new Set(state.starredSet)
|
||||||
|
if (note.isStarred) {
|
||||||
|
state.starredSet.add(uniqueKey)
|
||||||
|
} else {
|
||||||
|
state.starredSet.delete(uniqueKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update storageNoteMap if oldNote doesn't exist
|
||||||
|
if (oldNote == null) {
|
||||||
|
state.storeageNoteMap = new Map(state.storeageNoteMap)
|
||||||
|
let noteSet = state.storeageNoteMap.get(note.storage)
|
||||||
|
noteSet = new Set(noteSet)
|
||||||
|
noteSet.add(uniqueKey)
|
||||||
|
state.folderNoteMap.set(folderKey, noteSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update foldermap if folder changed or post created
|
||||||
|
if (oldNote == null || oldNote.folder !== note.folder) {
|
||||||
|
state.folderNoteMap = new Map(state.folderNoteMap)
|
||||||
|
let folderNoteList = state.folderNoteMap.get(folderKey)
|
||||||
|
folderNoteList = new Set(folderNoteList)
|
||||||
|
folderNoteList.add(uniqueKey)
|
||||||
|
state.folderNoteMap.set(folderKey, folderNoteList)
|
||||||
|
|
||||||
|
if (oldNote != null) {
|
||||||
|
let oldFolderKey = oldNote.storage + '-' + oldNote.folder
|
||||||
|
let oldFolderNoteList = state.folderNoteMap.get(oldFolderKey)
|
||||||
|
oldFolderNoteList = new Set(oldFolderNoteList)
|
||||||
|
oldFolderNoteList.delete(uniqueKey)
|
||||||
|
state.folderNoteMap.set(oldFolderKey, oldFolderNoteList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from old folder map
|
||||||
|
if (oldNote != null) {
|
||||||
|
let discardedTags = _.difference(oldNote.tags, note.tags)
|
||||||
|
let addedTags = _.difference(note.tags, oldNote.tags)
|
||||||
|
if (discardedTags.length + addedTags.length > 0) {
|
||||||
|
state.tagNoteMap = new Map(state.tagNoteMap)
|
||||||
|
|
||||||
|
discardedTags.forEach((tag) => {
|
||||||
|
let tagNoteList = state.tagNoteMap.get(tag)
|
||||||
|
if (tagNoteList != null) {
|
||||||
|
tagNoteList = new Set(tagNoteList)
|
||||||
|
tagNoteList.delete(uniqueKey)
|
||||||
|
state.tagNoteMap.set(tag, tagNoteList)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
addedTags.forEach((tag) => {
|
||||||
|
let tagNoteList = state.tagNoteMap.get(tag)
|
||||||
|
tagNoteList = new Set(tagNoteList)
|
||||||
|
tagNoteList.add(uniqueKey)
|
||||||
|
|
||||||
|
state.tagNoteMap.set(tag, tagNoteList)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.tagNoteMap = new Map(state.tagNoteMap)
|
||||||
|
note.tags.forEach((tag) => {
|
||||||
|
let tagNoteList = state.tagNoteMap.get(tag)
|
||||||
|
if (tagNoteList == null) {
|
||||||
|
tagNoteList = new Set(tagNoteList)
|
||||||
|
state.tagNoteMap.set(tag, tagNoteList)
|
||||||
|
}
|
||||||
|
tagNoteList.add(uniqueKey)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
case 'DELETE_NOTE':
|
||||||
{
|
{
|
||||||
let notes = state.slice()
|
|
||||||
notes = notes.filter((note) => note.key !== action.note.key || note.folder !== action.note.folder || note.storage !== action.note.storage)
|
return state
|
||||||
return notes
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
@@ -116,8 +292,7 @@ function config (state = defaultConfig, action) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let reducer = combineReducers({
|
let reducer = combineReducers({
|
||||||
storages,
|
data,
|
||||||
notes,
|
|
||||||
config,
|
config,
|
||||||
routing: routerReducer
|
routing: routerReducer
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user