diff --git a/browser/main/global.styl b/browser/main/global.styl
index ef70fcb3..9da7a596 100644
--- a/browser/main/global.styl
+++ b/browser/main/global.styl
@@ -102,3 +102,10 @@ body[data-theme="dark"]
background #B1D7FE
::selection
background #B1D7FE
+
+.sortableItemHelper
+ z-index modalZIndex + 5
+
+body[data-theme="dark"]
+ .sortableItemHelper
+ color: $ui-dark-text-color
diff --git a/browser/main/lib/dataApi/index.js b/browser/main/lib/dataApi/index.js
index bad6f527..768dfe32 100644
--- a/browser/main/lib/dataApi/index.js
+++ b/browser/main/lib/dataApi/index.js
@@ -6,6 +6,7 @@ const dataApi = {
createFolder: require('./createFolder'),
updateFolder: require('./updateFolder'),
deleteFolder: require('./deleteFolder'),
+ reorderFolder: require('./reorderFolder'),
createNote: require('./createNote'),
updateNote: require('./updateNote'),
deleteNote: require('./deleteNote'),
diff --git a/browser/main/lib/dataApi/reorderFolder.js b/browser/main/lib/dataApi/reorderFolder.js
new file mode 100644
index 00000000..3ee9229e
--- /dev/null
+++ b/browser/main/lib/dataApi/reorderFolder.js
@@ -0,0 +1,43 @@
+const _ = require('lodash')
+_.move = require('lodash-move').default
+const path = require('path')
+const resolveStorageData = require('./resolveStorageData')
+const CSON = require('@rokt33r/season')
+const { findStorage } = require('browser/lib/findStorage')
+
+/**
+ * @param {String} storageKey
+ * @param {number} oldIndex
+ * @param {number} newIndex
+ *
+ * @return {Object}
+ * ```
+ * {
+ * storage: Object
+ * }
+ * ```
+ */
+function reorderFolder (storageKey, oldIndex, newIndex) {
+ let rawStorages
+ let targetStorage
+ try {
+ if (!_.isNumber(oldIndex)) throw new Error('oldIndex must be a number.')
+ if (!_.isNumber(newIndex)) throw new Error('newIndex must be a number.')
+
+ targetStorage = findStorage(storageKey)
+ } catch (e) {
+ return Promise.reject(e)
+ }
+
+ return resolveStorageData(targetStorage)
+ .then(function reorderFolder (storage) {
+ storage.folders = _.move(storage.folders, oldIndex, newIndex)
+ CSON.writeFileSync(path.join(storage.path, 'boostnote.json'), _.pick(storage, ['folders', 'version']))
+
+ return {
+ storage
+ }
+ })
+}
+
+module.exports = reorderFolder
diff --git a/browser/main/lib/dataApi/updateFolder.js b/browser/main/lib/dataApi/updateFolder.js
index e128a2d3..6c6e587b 100644
--- a/browser/main/lib/dataApi/updateFolder.js
+++ b/browser/main/lib/dataApi/updateFolder.js
@@ -2,6 +2,7 @@ const _ = require('lodash')
const path = require('path')
const resolveStorageData = require('./resolveStorageData')
const CSON = require('@rokt33r/season')
+const { findStorage } = require('browser/lib/findStorage')
/**
* @param {String} storageKey
@@ -29,11 +30,7 @@ function updateFolder (storageKey, folderKey, input) {
if (!_.isString(input.name)) throw new Error('Name must be a string.')
if (!_.isString(input.color)) throw new Error('Color must be a string.')
- rawStorages = JSON.parse(localStorage.getItem('storages'))
- if (!_.isArray(rawStorages)) throw new Error('Target storage doesn\'t exist.')
-
- targetStorage = _.find(rawStorages, {key: storageKey})
- if (targetStorage == null) throw new Error('Target storage doesn\'t exist.')
+ targetStorage = findStorage(storageKey)
} catch (e) {
return Promise.reject(e)
}
diff --git a/browser/main/modals/PreferencesModal/FolderItem.js b/browser/main/modals/PreferencesModal/FolderItem.js
new file mode 100644
index 00000000..5bd9d9f1
--- /dev/null
+++ b/browser/main/modals/PreferencesModal/FolderItem.js
@@ -0,0 +1,303 @@
+import React, { PropTypes } from 'react'
+import CSSModules from 'browser/lib/CSSModules'
+import ReactDOM from 'react-dom'
+import styles from './FolderItem.styl'
+import dataApi from 'browser/main/lib/dataApi'
+import store from 'browser/main/store'
+import { SketchPicker } from 'react-color'
+import { SortableElement, SortableHandle } from 'react-sortable-hoc'
+
+class FolderItem extends React.Component {
+ constructor (props) {
+ super(props)
+
+ this.state = {
+ status: 'IDLE',
+ folder: {
+ showColumnPicker: false,
+ colorPickerPos: { left: 0, top: 0 },
+ color: props.color,
+ name: props.name
+ }
+ }
+ }
+
+ handleEditChange (e) {
+ let { folder } = this.state
+
+ folder.name = this.refs.nameInput.value
+ this.setState({
+ folder
+ })
+ }
+
+ handleConfirmButtonClick (e) {
+ this.confirm()
+ }
+
+ confirm () {
+ let { storage, folder } = this.props
+ dataApi
+ .updateFolder(storage.key, folder.key, {
+ color: this.state.folder.color,
+ name: this.state.folder.name
+ })
+ .then((data) => {
+ store.dispatch({
+ type: 'UPDATE_FOLDER',
+ storage: data.storage
+ })
+ this.setState({
+ status: 'IDLE'
+ })
+ })
+ }
+
+ handleColorButtonClick (e) {
+ const folder = Object.assign({}, this.state.folder, { showColumnPicker: true, colorPickerPos: { left: 0, top: 0 } })
+ this.setState({ folder }, function () {
+ // After the color picker has been painted, re-calculate its position
+ // by comparing its dimensions to the host dimensions.
+ const { hostBoundingBox } = this.props
+ const colorPickerNode = ReactDOM.findDOMNode(this.refs.colorPicker)
+ const colorPickerBox = colorPickerNode.getBoundingClientRect()
+ const offsetTop = hostBoundingBox.bottom - colorPickerBox.bottom
+ const folder = Object.assign({}, this.state.folder, {
+ colorPickerPos: {
+ left: 25,
+ top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics
+ }
+ })
+ this.setState({ folder })
+ })
+ }
+
+ handleColorChange (color) {
+ const folder = Object.assign({}, this.state.folder, { color: color.hex })
+ this.setState({ folder })
+ }
+
+ handleColorPickerClose (event) {
+ const folder = Object.assign({}, this.state.folder, { showColumnPicker: false })
+ this.setState({ folder })
+ }
+
+ handleCancelButtonClick (e) {
+ this.setState({
+ status: 'IDLE'
+ })
+ }
+
+ handleFolderItemBlur (e) {
+ let el = e.relatedTarget
+ while (el != null) {
+ if (el === this.refs.root) {
+ return false
+ }
+ el = el.parentNode
+ }
+ this.confirm()
+ }
+
+ renderEdit (e) {
+ const popover = { position: 'absolute', zIndex: 2 }
+ const cover = {
+ position: 'fixed',
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0
+ }
+ const pickerStyle = Object.assign({}, {
+ position: 'absolute'
+ }, this.state.folder.colorPickerPos)
+ return (
+
this.handleFolderItemBlur(e)}
+ tabIndex='-1'
+ ref='root'
+ >
+
+
+ )
+ }
+
+ handleDeleteConfirmButtonClick (e) {
+ let { storage, folder } = this.props
+ dataApi
+ .deleteFolder(storage.key, folder.key)
+ .then((data) => {
+ store.dispatch({
+ type: 'DELETE_FOLDER',
+ storage: data.storage,
+ folderKey: data.folderKey
+ })
+ })
+ }
+
+ renderDelete () {
+ return (
+
+
+ Are you sure to delete this folder?
+
+
+ this.handleDeleteConfirmButtonClick(e)}
+ >
+ Confirm
+
+ this.handleCancelButtonClick(e)}
+ >
+ Cancel
+
+
+
+ )
+ }
+
+ handleEditButtonClick (e) {
+ let { folder: propsFolder } = this.props
+ let { folder: stateFolder } = this.state
+ const folder = Object.assign({}, stateFolder, propsFolder)
+ this.setState({
+ status: 'EDIT',
+ folder
+ }, () => {
+ this.refs.nameInput.select()
+ })
+ }
+
+ handleDeleteButtonClick (e) {
+ this.setState({
+ status: 'DELETE'
+ })
+ }
+
+ renderIdle () {
+ let { folder } = this.props
+ return (
+
this.handleEditButtonClick(e)}
+ >
+
+ {folder.name}
+ ({folder.key})
+
+
+ this.handleEditButtonClick(e)}
+ >
+ Edit
+
+ this.handleDeleteButtonClick(e)}
+ >
+ Delete
+
+
+
+ )
+ }
+
+ render () {
+ switch (this.state.status) {
+ case 'DELETE':
+ return this.renderDelete()
+ case 'EDIT':
+ return this.renderEdit()
+ case 'IDLE':
+ default:
+ return this.renderIdle()
+ }
+ }
+}
+
+FolderItem.propTypes = {
+ hostBoundingBox: PropTypes.shape({
+ bottom: PropTypes.number,
+ height: PropTypes.number,
+ left: PropTypes.number,
+ right: PropTypes.number,
+ top: PropTypes.number,
+ width: PropTypes.number
+ }),
+ storage: PropTypes.shape({
+ key: PropTypes.string
+ }),
+ folder: PropTypes.shape({
+ key: PropTypes.string,
+ color: PropTypes.string,
+ name: PropTypes.string
+ })
+}
+
+class Handle extends React.Component {
+ render () {
+ return (
+
+
+
+ )
+ }
+}
+
+class SortableFolderItemComponent extends React.Component {
+ render () {
+ const StyledHandle = CSSModules(Handle, this.props.styles)
+ const DragHandle = SortableHandle(StyledHandle)
+
+ const StyledFolderItem = CSSModules(FolderItem, this.props.styles)
+
+ return (
+
+
+
+
+ )
+ }
+}
+
+export default CSSModules(SortableElement(SortableFolderItemComponent), styles)
diff --git a/browser/main/modals/PreferencesModal/FolderItem.styl b/browser/main/modals/PreferencesModal/FolderItem.styl
new file mode 100644
index 00000000..e3b09582
--- /dev/null
+++ b/browser/main/modals/PreferencesModal/FolderItem.styl
@@ -0,0 +1,103 @@
+.folderItem
+ height 35px
+ box-sizing border-box
+ padding 2.5px 15px
+ &:hover
+ background-color darken(white, 3%)
+
+.folderItem-drag-handle
+ height 35px
+ border none
+ padding 0 10px
+ line-height 35px
+ float left
+ cursor row-resize
+
+.folderItem-left
+ height 30px
+ border-left solid 2px transparent
+ padding 0 10px
+ line-height 30px
+ float left
+.folderItem-left-danger
+ color $danger-color
+ font-weight bold
+
+.folderItem-left-key
+ color $ui-inactive-text-color
+ font-size 10px
+ margin 0 5px
+ border none
+
+.folderItem-left-colorButton
+ colorDefaultButton()
+ height 25px
+ width 25px
+ line-height 23px
+ padding 0
+ box-sizing border-box
+ vertical-align middle
+ border $ui-border
+ border-radius 2px
+ margin-right 5px
+ margin-left -15px
+
+.folderItem-left-nameInput
+ height 25px
+ box-sizing border-box
+ vertical-align middle
+ border $ui-border
+ border-radius 2px
+ padding 0 5px
+ outline none
+
+.folderItem-right
+ float right
+
+.folderItem-right-button
+ vertical-align middle
+ height 25px
+ margin-top 2.5px
+ colorDefaultButton()
+ border-radius 2px
+ border $ui-border
+ margin-right 5px
+ padding 0 5px
+ &:last-child
+ margin-right 0
+
+.folderItem-right-confirmButton
+ @extend .folderItem-right-button
+ border none
+ colorPrimaryButton()
+
+.folderItem-right-dangerButton
+ @extend .folderItem-right-button
+ border none
+ colorDangerButton()
+
+body[data-theme="dark"]
+ .folderItem
+ &:hover
+ background-color lighten($ui-dark-button--hover-backgroundColor, 5%)
+
+ .folderItem-left-danger
+ color $danger-color
+ font-weight bold
+
+ .folderItem-left-key
+ color $ui-dark-inactive-text-color
+
+ .folderItem-left-colorButton
+ colorDarkDefaultButton()
+ border-color $ui-dark-borderColor
+
+ .folderItem-right-button
+ colorDarkDefaultButton()
+ border-color $ui-dark-borderColor
+
+ .folderItem-right-confirmButton
+ colorDarkPrimaryButton()
+
+ .folderItem-right-dangerButton
+ colorDarkDangerButton()
diff --git a/browser/main/modals/PreferencesModal/FolderList.js b/browser/main/modals/PreferencesModal/FolderList.js
new file mode 100644
index 00000000..0172dc10
--- /dev/null
+++ b/browser/main/modals/PreferencesModal/FolderList.js
@@ -0,0 +1,84 @@
+import React, { PropTypes } from 'react'
+import CSSModules from 'browser/lib/CSSModules'
+import dataApi from 'browser/main/lib/dataApi'
+import styles from './FolderList.styl'
+import store from 'browser/main/store'
+import FolderItem from './FolderItem'
+import { SortableContainer, arrayMove } from 'react-sortable-hoc'
+
+class FolderList extends React.Component {
+ render () {
+ let { storage, hostBoundingBox } = this.props
+
+ let folderList = storage.folders.map((folder, index) => {
+ return
+ })
+
+ return (
+
+ {folderList.length > 0
+ ? folderList
+ :
No Folders
+ }
+
+ )
+ }
+}
+
+FolderList.propTypes = {
+ hostBoundingBox: PropTypes.shape({
+ bottom: PropTypes.number,
+ height: PropTypes.number,
+ left: PropTypes.number,
+ right: PropTypes.number,
+ top: PropTypes.number,
+ width: PropTypes.number
+ }),
+ storage: PropTypes.shape({
+ key: PropTypes.string
+ }),
+ folder: PropTypes.shape({
+ key: PropTypes.number,
+ color: PropTypes.string,
+ name: PropTypes.string
+ })
+}
+
+class SortableFolderListComponent extends React.Component {
+ constructor (props) {
+ super(props)
+ this.onSortEnd = ({oldIndex, newIndex}) => {
+ let { storage } = this.props
+ dataApi
+ .reorderFolder(storage.key, oldIndex, newIndex)
+ .then((data) => {
+ store.dispatch({
+ type: 'REORDER_FOLDER',
+ storage: data.storage
+ })
+ this.setState()
+ })
+ }
+ }
+
+ render () {
+ const StyledFolderList = CSSModules(FolderList, this.props.styles)
+ const SortableFolderList = SortableContainer(StyledFolderList)
+
+ return (
+
+ )
+ }
+}
+
+export default CSSModules(SortableFolderListComponent, styles)
diff --git a/browser/main/modals/PreferencesModal/FolderList.styl b/browser/main/modals/PreferencesModal/FolderList.styl
new file mode 100644
index 00000000..e69de29b
diff --git a/browser/main/modals/PreferencesModal/StorageItem.js b/browser/main/modals/PreferencesModal/StorageItem.js
index d3586f35..478e4c44 100644
--- a/browser/main/modals/PreferencesModal/StorageItem.js
+++ b/browser/main/modals/PreferencesModal/StorageItem.js
@@ -1,265 +1,13 @@
import React, { PropTypes } from 'react'
-import ReactDOM from 'react-dom'
import CSSModules from 'browser/lib/CSSModules'
import styles from './StorageItem.styl'
import consts from 'browser/lib/consts'
import dataApi from 'browser/main/lib/dataApi'
import store from 'browser/main/store'
+import FolderList from './FolderList'
const { shell, remote } = require('electron')
const { dialog } = remote
-import { SketchPicker } from 'react-color'
-
-class UnstyledFolderItem extends React.Component {
- constructor (props) {
- super(props)
-
- this.state = {
- status: 'IDLE',
- folder: {
- showColumnPicker: false,
- colorPickerPos: { left: 0, top: 0 },
- color: props.color,
- name: props.name
- }
- }
- }
-
- handleEditChange (e) {
- let { folder } = this.state
-
- folder.name = this.refs.nameInput.value
- this.setState({
- folder
- })
- }
-
- handleConfirmButtonClick (e) {
- this.confirm()
- }
-
- confirm () {
- let { storage, folder } = this.props
- dataApi
- .updateFolder(storage.key, folder.key, {
- color: this.state.folder.color,
- name: this.state.folder.name
- })
- .then((data) => {
- store.dispatch({
- type: 'UPDATE_FOLDER',
- storage: data.storage
- })
- this.setState({
- status: 'IDLE'
- })
- })
- }
-
- handleColorButtonClick (e) {
- const folder = Object.assign({}, this.state.folder, { showColumnPicker: true, colorPickerPos: { left: 0, top: 0 } })
- this.setState({ folder }, function () {
- // After the color picker has been painted, re-calculate its position
- // by comparing its dimensions to the host dimensions.
- const { hostBoundingBox } = this.props
- const colorPickerNode = ReactDOM.findDOMNode(this.refs.colorPicker)
- const colorPickerBox = colorPickerNode.getBoundingClientRect()
- const offsetTop = hostBoundingBox.bottom - colorPickerBox.bottom
- const folder = Object.assign({}, this.state.folder, {
- colorPickerPos: {
- left: 25,
- top: offsetTop < 0 ? offsetTop - 5 : 0 // subtract 5px for aestetics
- }
- })
- this.setState({ folder })
- })
- }
-
- handleColorChange (color) {
- const folder = Object.assign({}, this.state.folder, { color: color.hex })
- this.setState({ folder })
- }
-
- handleColorPickerClose (event) {
- const folder = Object.assign({}, this.state.folder, { showColumnPicker: false })
- this.setState({ folder })
- }
-
- handleCancelButtonClick (e) {
- this.setState({
- status: 'IDLE'
- })
- }
-
- handleFolderItemBlur (e) {
- let el = e.relatedTarget
- while (el != null) {
- if (el === this.refs.root) {
- return false
- }
- el = el.parentNode
- }
- this.confirm()
- }
-
- renderEdit (e) {
- const popover = { position: 'absolute', zIndex: 2 }
- const cover = {
- position: 'fixed',
- top: 0,
- right: 0,
- bottom: 0,
- left: 0
- }
- const pickerStyle = Object.assign({}, {
- position: 'absolute'
- }, this.state.folder.colorPickerPos)
- return (
-
this.handleFolderItemBlur(e)}
- tabIndex='-1'
- ref='root'
- >
-
-
!this.state.folder.showColumnPicker && this.handleColorButtonClick(e)}
- >
- {this.state.folder.showColumnPicker
- ?
-
this.handleColorPickerClose()}
- />
-
- this.handleColorChange(color)}
- onChangeComplete={(color) => this.handleColorChange(color)}
- />
-
-
- : null
- }
-
-
-
this.handleEditChange(e)}
- />
-
-
- this.handleConfirmButtonClick(e)}
- >
- Confirm
-
- this.handleCancelButtonClick(e)}
- >
- Cancel
-
-
-
- )
- }
-
- handleDeleteConfirmButtonClick (e) {
- let { storage, folder } = this.props
- dataApi
- .deleteFolder(storage.key, folder.key)
- .then((data) => {
- store.dispatch({
- type: 'DELETE_FOLDER',
- storage: data.storage,
- folderKey: data.folderKey
- })
- })
- }
-
- renderDelete () {
- return (
-
-
- Are you sure to delete this folder?
-
-
- this.handleDeleteConfirmButtonClick(e)}
- >
- Confirm
-
- this.handleCancelButtonClick(e)}
- >
- Cancel
-
-
-
- )
- }
-
- handleEditButtonClick (e) {
- let { folder: propsFolder } = this.props
- let { folder: stateFolder } = this.state
- const folder = Object.assign({}, stateFolder, propsFolder)
- this.setState({
- status: 'EDIT',
- folder
- }, () => {
- this.refs.nameInput.select()
- })
- }
-
- handleDeleteButtonClick (e) {
- this.setState({
- status: 'DELETE'
- })
- }
-
- renderIdle () {
- let { folder } = this.props
- return (
-
this.handleEditButtonClick(e)}
- >
-
- {folder.name}
- ({folder.key})
-
-
- this.handleEditButtonClick(e)}
- >
- Edit
-
- this.handleDeleteButtonClick(e)}
- >
- Delete
-
-
-
-
- )
- }
-
- render () {
- switch (this.state.status) {
- case 'DELETE':
- return this.renderDelete()
- case 'EDIT':
- return this.renderEdit()
- case 'IDLE':
- default:
- return this.renderIdle()
- }
- }
-}
-
-const FolderItem = CSSModules(UnstyledFolderItem, styles)
class StorageItem extends React.Component {
constructor (props) {
@@ -349,13 +97,7 @@ class StorageItem extends React.Component {
render () {
let { storage, hostBoundingBox } = this.props
- let folderList = storage.folders.map((folder) => {
- return
- })
+
return (
@@ -404,12 +146,9 @@ class StorageItem extends React.Component {
-
- {folderList.length > 0
- ? folderList
- :
No Folders
- }
-
+
)
}
@@ -426,11 +165,6 @@ StorageItem.propTypes = {
}),
storage: PropTypes.shape({
key: PropTypes.string
- }),
- folder: PropTypes.shape({
- key: PropTypes.string,
- color: PropTypes.string,
- name: PropTypes.string
})
}
diff --git a/browser/main/modals/PreferencesModal/StorageItem.styl b/browser/main/modals/PreferencesModal/StorageItem.styl
index 538edfb8..13759007 100644
--- a/browser/main/modals/PreferencesModal/StorageItem.styl
+++ b/browser/main/modals/PreferencesModal/StorageItem.styl
@@ -63,75 +63,6 @@
z-index 10
white-space nowrap
-.folderList-item
- height 35px
- box-sizing border-box
- padding 2.5px 15px
- &:hover
- background-color darken(white, 3%)
-.folderList-item-left
- height 30px
- border-left solid 2px transparent
- padding 0 10px
- line-height 30px
- float left
-.folderList-item-left-danger
- color $danger-color
- font-weight bold
-
-.folderList-item-left-key
- color $ui-inactive-text-color
- font-size 10px
- margin 0 5px
- border none
-
-.folderList-item-left-colorButton
- colorDefaultButton()
- height 25px
- width 25px
- line-height 23px
- padding 0
- box-sizing border-box
- vertical-align middle
- border $ui-border
- border-radius 2px
- margin-right 5px
- margin-left -15px
-
-.folderList-item-left-nameInput
- height 25px
- box-sizing border-box
- vertical-align middle
- border $ui-border
- border-radius 2px
- padding 0 5px
- outline none
-
-.folderList-item-right
- float right
-
-.folderList-item-right-button
- vertical-align middle
- height 25px
- margin-top 2.5px
- colorDefaultButton()
- border-radius 2px
- border $ui-border
- margin-right 5px
- padding 0 5px
- &:last-child
- margin-right 0
-
-.folderList-item-right-confirmButton
- @extend .folderList-item-right-button
- border none
- colorPrimaryButton()
-
-.folderList-item-right-dangerButton
- @extend .folderList-item-right-button
- border none
- colorDangerButton()
-
body[data-theme="dark"]
.header
border-color $ui-dark-borderColor
@@ -153,28 +84,3 @@ body[data-theme="dark"]
top 25px
z-index 10
white-space nowrap
-
- .folderList-item
- &:hover
- background-color lighten($ui-dark-button--hover-backgroundColor, 5%)
-
- .folderList-item-left-danger
- color $danger-color
- font-weight bold
-
- .folderList-item-left-key
- color $ui-dark-inactive-text-color
-
- .folderList-item-left-colorButton
- colorDarkDefaultButton()
- border-color $ui-dark-borderColor
-
- .folderList-item-right-button
- colorDarkDefaultButton()
- border-color $ui-dark-borderColor
-
- .folderList-item-right-confirmButton
- colorDarkPrimaryButton()
-
- .folderList-item-right-dangerButton
- colorDarkDangerButton()
diff --git a/browser/main/store.js b/browser/main/store.js
index 68c46876..ac41b1d0 100644
--- a/browser/main/store.js
+++ b/browser/main/store.js
@@ -346,6 +346,13 @@ function data (state = defaultDataMap(), action) {
state.storageMap.set(action.storage.key, action.storage)
}
return state
+ case 'REORDER_FOLDER':
+ {
+ state = Object.assign({}, state)
+ state.storageMap = new Map(state.storageMap)
+ state.storageMap.set(action.storage.key, action.storage)
+ }
+ return state
case 'DELETE_FOLDER':
{
state = Object.assign({}, state)
diff --git a/package.json b/package.json
index 2370049b..33e42fde 100644
--- a/package.json
+++ b/package.json
@@ -61,6 +61,7 @@
"js-sequence-diagrams": "^1000000.0.6",
"katex": "^0.7.1",
"lodash": "^4.11.1",
+ "lodash-move": "^1.1.1",
"markdown-it": "^6.0.1",
"markdown-it-checkbox": "^1.1.0",
"markdown-it-emoji": "^1.1.1",
@@ -77,6 +78,7 @@
"react-codemirror": "^0.3.0",
"react-dom": "^15.0.2",
"react-redux": "^4.4.5",
+ "react-sortable-hoc": "^0.6.7",
"redux": "^3.5.2",
"sander": "^0.5.1",
"striptags": "^2.2.1",
diff --git a/tests/dataApi/reorderFolder-test.js b/tests/dataApi/reorderFolder-test.js
new file mode 100644
index 00000000..bb7f6b0c
--- /dev/null
+++ b/tests/dataApi/reorderFolder-test.js
@@ -0,0 +1,48 @@
+const test = require('ava')
+const reorderFolder = require('browser/main/lib/dataApi/reorderFolder')
+
+global.document = require('jsdom').jsdom('')
+global.window = document.defaultView
+global.navigator = window.navigator
+
+const Storage = require('dom-storage')
+const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
+const path = require('path')
+const _ = require('lodash')
+const TestDummy = require('../fixtures/TestDummy')
+const sander = require('sander')
+const os = require('os')
+const CSON = require('@rokt33r/season')
+
+const storagePath = path.join(os.tmpdir(), 'test/reorder-folder')
+
+test.beforeEach((t) => {
+ t.context.storage = TestDummy.dummyStorage(storagePath)
+ localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
+})
+
+test.serial('Reorder a folder', (t) => {
+ const storageKey = t.context.storage.cache.key
+ const firstFolderKey = t.context.storage.json.folders[0].key
+ const secondFolderKey = t.context.storage.json.folders[1].key
+
+ return Promise.resolve()
+ .then(function doTest () {
+ return reorderFolder(storageKey, 0, 1)
+ })
+ .then(function assert (data) {
+ t.true(_.nth(data.storage.folders, 0).key === secondFolderKey)
+ t.true(_.nth(data.storage.folders, 1).key === firstFolderKey)
+
+ let jsonData = CSON.readFileSync(path.join(data.storage.path, 'boostnote.json'))
+ console.log(path.join(data.storage.path, 'boostnote.json'))
+
+ t.true(_.nth(jsonData.folders, 0).key === secondFolderKey)
+ t.true(_.nth(jsonData.folders, 1).key === firstFolderKey)
+ })
+})
+
+test.after(function after () {
+ localStorage.clear()
+ sander.rimrafSync(storagePath)
+})
diff --git a/yarn.lock b/yarn.lock
index 157e2977..ad4becaa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1057,6 +1057,13 @@ babel-register@^6.11.6, babel-register@^6.24.1:
mkdirp "^0.5.1"
source-map-support "^0.4.2"
+babel-runtime@^6.11.6:
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
+ dependencies:
+ core-js "^2.4.0"
+ regenerator-runtime "^0.11.0"
+
babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.3.19:
version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
@@ -3900,6 +3907,12 @@ lodash-es@^4.2.1:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7"
+lodash-move@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/lodash-move/-/lodash-move-1.1.1.tgz#59f76e0f1ac57e6d8683f531bec07c5b6ea4e348"
+ dependencies:
+ lodash "^4.6.1"
+
lodash._reinterpolate@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
@@ -3949,7 +3962,7 @@ lodash@^3.5.0:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
-lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.17.2, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1:
+lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.12.0, lodash@^4.17.2, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
@@ -5337,6 +5350,15 @@ react-router@^2.4.0:
loose-envify "^1.2.0"
warning "^3.0.0"
+react-sortable-hoc@^0.6.7:
+ version "0.6.7"
+ resolved "https://registry.yarnpkg.com/react-sortable-hoc/-/react-sortable-hoc-0.6.7.tgz#e30d247bc36dd5a605430c331ac9cb50a5fa72a6"
+ dependencies:
+ babel-runtime "^6.11.6"
+ invariant "^2.2.1"
+ lodash "^4.12.0"
+ prop-types "^15.5.7"
+
react-transform-catch-errors@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/react-transform-catch-errors/-/react-transform-catch-errors-1.0.2.tgz#1b4d4a76e97271896fc16fe3086c793ec88a9eeb"
@@ -5497,6 +5519,10 @@ regenerator-runtime@^0.10.0:
version "0.10.5"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
+regenerator-runtime@^0.11.0:
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1"
+
regenerator-transform@0.9.11:
version "0.9.11"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.11.tgz#3a7d067520cb7b7176769eb5ff868691befe1283"