1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-11 08:46:20 +00:00

export folder as md or text

This commit is contained in:
Maurits Lourens
2017-11-20 17:33:17 +01:00
parent d29d5105f1
commit 959b75bddd
6 changed files with 206 additions and 26 deletions

4
.gitignore vendored
View File

@@ -8,5 +8,5 @@ node_modules/*
/compiled
/secret
*.log
.vscode
.idea
.idea
.vscode

View File

@@ -10,6 +10,7 @@ import dataApi from 'browser/main/lib/dataApi'
import StorageItemChild from 'browser/components/StorageItem'
import eventEmitter from 'browser/main/lib/eventEmitter'
import _ from 'lodash'
const path = require('path')
const { remote } = require('electron')
const { Menu, MenuItem, dialog } = remote
@@ -24,18 +25,20 @@ class StorageItem extends React.Component {
}
handleHeaderContextMenu (e) {
const menu = new Menu()
menu.append(new MenuItem({
label: 'Add Folder',
click: (e) => this.handleAddFolderButtonClick(e)
}))
menu.append(new MenuItem({
type: 'separator'
}))
menu.append(new MenuItem({
label: 'Unlink Storage',
click: (e) => this.handleUnlinkStorageClick(e)
}))
let menu = Menu.buildFromTemplate([
{
label: 'Add Folder',
click: (e) => this.handleAddFolderButtonClick(e)
},
{
type: 'separator'
},
{
label: 'Unlink Storage',
click: (e) => this.handleUnlinkStorageClick(e)
}
])
menu.popup()
}
@@ -89,18 +92,36 @@ class StorageItem extends React.Component {
}
handleFolderButtonContextMenu (e, folder) {
const menu = new Menu()
menu.append(new MenuItem({
label: 'Rename Folder',
click: (e) => this.handleRenameFolderClick(e, folder)
}))
menu.append(new MenuItem({
type: 'separator'
}))
menu.append(new MenuItem({
label: 'Delete Folder',
click: (e) => this.handleFolderDeleteClick(e, folder)
}))
const menu = Menu.buildFromTemplate([
{
label: 'Rename Folder',
click: (e) => this.handleRenameFolderClick(e, folder)
},
{
type: 'separator'
},
{
label: 'Export Folder',
submenu: [
{
label: 'Export as txt',
click: (e) => this.handleExportFolderClick(e, folder, 'txt')
},
{
label: 'Export as md',
click: (e) => this.handleExportFolderClick(e, folder, 'md')
}
]
},
{
type: 'separator'
},
{
label: 'Delete Folder',
click: (e) => this.handleFolderDeleteClick(e, folder)
}
])
menu.popup()
}
@@ -112,6 +133,31 @@ class StorageItem extends React.Component {
})
}
handleExportFolderClick (e, folder, fileType) {
const options = {
properties: ['openDirectory', 'createDirectory'],
buttonLabel: 'Select directory',
title: 'Select a folder to export the files to',
multiSelections: false
}
dialog.showOpenDialog(remote.getCurrentWindow(), options,
(paths) => {
if (paths && paths.length === 1) {
const { storage, dispatch } = this.props
dataApi
.exportFolder(storage.key, folder.key, fileType, paths[0])
.then((data) => {
dispatch({
type: 'EXPORT_FOLDER',
storage: data.storage,
folderKey: data.folderKey,
fileType: data.fileType
})
})
}
})
}
handleFolderDeleteClick (e, folder) {
const index = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',

View File

@@ -0,0 +1,64 @@
const { findStorage } = require('browser/lib/findStorage')
const resolveStorageData = require('./resolveStorageData')
const resolveStorageNotes = require('./resolveStorageNotes')
const path = require('path')
const fs = require('fs')
/**
* @param {String} storageKey
* @param {String} folderKey
* @param {String} fileType
* @param {String} exportDir
*
* @return {Object}
* ```
* {
* storage: Object,
* folderKey: String,
* fileType: String,
* exportDir: String
* }
* ```
*/
function exportFolder (storageKey, folderKey, fileType, exportDir) {
let targetStorage
try {
targetStorage = findStorage(storageKey)
} catch (e) {
return Promise.reject(e)
}
return resolveStorageData(targetStorage)
.then(function assignNotes (storage) {
return resolveStorageNotes(storage)
.then((notes) => {
return {
storage,
notes
}
})
})
.then(function exportNotes (data) {
const { storage, notes } = data
notes
.filter(note => note.folder === folderKey && note.isTrashed === false && note.type === 'MARKDOWN_NOTE')
.forEach(snippet => {
const notePath = path.join(exportDir, `${snippet.title}.${fileType}`)
console.log(notePath)
fs.writeFile(notePath, snippet.content, (err) => {
if (err) throw err
})
})
return {
storage,
folderKey,
fileType,
exportDir
}
})
}
module.exports = exportFolder

View File

@@ -7,6 +7,7 @@ const dataApi = {
updateFolder: require('./updateFolder'),
deleteFolder: require('./deleteFolder'),
reorderFolder: require('./reorderFolder'),
exportFolder: require('./exportFolder'),
createNote: require('./createNote'),
updateNote: require('./updateNote'),
deleteNote: require('./deleteNote'),

View File

@@ -349,6 +349,13 @@ function data (state = defaultDataMap(), action) {
state.storageMap = new Map(state.storageMap)
state.storageMap.set(action.storage.key, action.storage)
return state
case 'EXPORT_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)

View File

@@ -0,0 +1,62 @@
const test = require('ava')
const exportFolder = require('browser/main/lib/dataApi/exportFolder')
const createNote = require('browser/main/lib/dataApi/createNote')
global.document = require('jsdom').jsdom('<body></body>')
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 TestDummy = require('../fixtures/TestDummy')
const os = require('os')
const faker = require('faker')
const fs = require('fs')
const storagePath = path.join(os.tmpdir(), 'test/export-note')
test.beforeEach((t) => {
t.context.storage = TestDummy.dummyStorage(storagePath)
localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
})
test.serial('Export a folder', (t) => {
const storageKey = t.context.storage.cache.key
const folderKey = t.context.storage.json.folders[0].key
const input1 = {
type: 'MARKDOWN_NOTE',
description: '*Some* markdown text',
tags: faker.lorem.words().split(' '),
folder: folderKey
}
input1.title = 'input1'
const input2 = {
type: 'SNIPPET_NOTE',
description: 'Some normal text',
snippets: [{
name: faker.system.fileName(),
mode: 'text',
content: faker.lorem.lines()
}],
tags: faker.lorem.words().split(' '),
folder: folderKey
}
input2.title = 'input2'
return createNote(storageKey, input1)
.then(function () {
return createNote(storageKey, input2)
})
.then(function () {
return exportFolder(storageKey, folderKey, 'md', storagePath)
})
.then(function assert () {
let filePath = path.join(storagePath, 'input1.md')
t.true(fs.existsSync(filePath))
filePath = path.join(storagePath, 'input2.md')
t.false(fs.existsSync(filePath))
})
})