Electron: Handle import export

pull/265/head
Laurent Cozic 2018-02-27 20:04:38 +00:00
parent 45845f645d
commit 4046a51472
24 changed files with 562 additions and 338 deletions

View File

@ -283,7 +283,7 @@ class Application extends BaseApplication {
exit: () => {},
showModalOverlay: (text) => {},
hideModalOverlay: () => {},
stdoutMaxWidth: () => { return 78; },
stdoutMaxWidth: () => { return 100; },
forceRender: () => {},
termSaveState: () => {},
termRestoreState: (state) => {},

View File

@ -18,8 +18,13 @@ class Command extends BaseCommand {
}
options() {
const service = new InteropService();
const formats = service.modules()
.filter(m => m.type === 'exporter')
.map(m => m.format + (m.description ? ' (' + m.description + ')' : ''));
return [
//['--format <format>', 'jex (default), raw'],
['--format <format>', _('Destination format: %s', formats.join(', '))],
['--note <note>', _('Exports only the given note.')],
['--notebook <notebook>', _('Exports only the given notebook.')],
];

View File

@ -21,9 +21,12 @@ class Command extends BaseCommand {
}
options() {
const service = new InteropService();
const formats = service.modules().filter(m => m.type === 'importer').map(m => m.format);
return [
['--format <format>', _('Source format: %s', (['auto'].concat(formats)).join(', '))],
['-f, --force', _('Do not ask for confirmation.')],
['--format <format>', 'auto, jex, enex, md'],
];
}

View File

@ -71,37 +71,10 @@ process.stdout.on('error', function( err ) {
// async function main() {
// const WebDavApi = require('lib/WebDavApi');
// const api = new WebDavApi('http://nextcloud.local/remote.php/dav/files/admin/Joplin', { username: 'admin', password: '1234567' });
// const { FileApiDriverWebDav } = new require('lib/file-api-driver-webdav');
// const driver = new FileApiDriverWebDav(api);
// const stat = await driver.stat('');
// console.info(stat);
// // const stat = await driver.stat('testing.txt');
// // console.info(stat);
// // const content = await driver.get('testing.txta');
// // console.info(content);
// // const content = await driver.get('testing.txta', { target: 'file', path: '/var/www/joplin/CliClient/testing-file.txt' });
// // console.info(content);
// // const content = await driver.mkdir('newdir5');
// // console.info(content);
// //await driver.put('myfile4.md', 'this is my content');
// // await driver.put('testimg.jpg', null, { source: 'file', path: '/mnt/d/test.jpg' });
// // await driver.delete('myfile4.md');
// // const deltaResult = await driver.delta('', {
// // allItemIdsHandler: () => { return []; }
// // });
// // console.info(deltaResult);
// const InteropService = require('lib/services/InteropService');
// const service = new InteropService();
// console.info(service.moduleByFormat('importer', 'enex'));
// //await service.modules();
// }
// main().catch((error) => { console.error(error); });

View File

@ -41,13 +41,14 @@ class ElectronAppWrapper {
const windowState = windowStateKeeper({
defaultWidth: 800,
defaultHeight: 600,
file: 'window-state-' + this.env_ + '.json',
});
const windowOptions = {
'x': windowState.x,
'y': windowState.y,
'width': windowState.width,
'height': windowState.height,
x: windowState.x,
y: windowState.y,
width: windowState.width,
height: windowState.height,
};
// Linux icon workaround for bug https://github.com/electron-userland/electron-builder/issues/2098

View File

@ -20,6 +20,7 @@ const packageInfo = require('./packageInfo.js');
const AlarmService = require('lib/services/AlarmService.js');
const AlarmServiceDriverNode = require('lib/services/AlarmServiceDriverNode');
const DecryptionWorker = require('lib/services/DecryptionWorker');
const InteropService = require('lib/services/InteropService');
const { bridge } = require('electron').remote.require('./bridge');
const Menu = bridge().Menu;
@ -191,6 +192,112 @@ class Application extends BaseApplication {
});
}
const importItems = [];
const exportItems = [];
const ioService = new InteropService();
const ioModules = ioService.modules();
for (let i = 0; i < ioModules.length; i++) {
const module = ioModules[i];
if (module.type === 'exporter') {
exportItems.push({
label: module.format + ' - ' + module.description,
screens: ['Main'],
click: async () => {
let path = null;
if (module.target === 'file') {
path = bridge().showSaveDialog({
filters: [{ name: module.description, extensions: [module.fileExtension]}]
});
} else {
path = bridge().showOpenDialog({
properties: ['openDirectory', 'createDirectory'],
});
}
if (!path || (Array.isArray(path) && !path.length)) return;
if (Array.isArray(path)) path = path[0];
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'showModalMessage',
message: _('Exporting to "%s" as "%s" format. Please wait...', path, module.format),
});
const exportOptions = {};
exportOptions.path = path;
exportOptions.format = module.format;
const service = new InteropService();
const result = await service.export(exportOptions);
console.info('Export result: ', result);
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'hideModalMessage',
});
}
});
} else {
for (let j = 0; j < module.sources.length; j++) {
const moduleSource = module.sources[j];
let label = [module.format + ' - ' + module.description];
if (module.sources.length > 1) {
label.push('(' + (moduleSource === 'file' ? _('File') : _('Directory')) + ')');
}
importItems.push({
label: label.join(' '),
screens: ['Main'],
click: async () => {
let path = null;
const selectedFolderId = this.store().getState().selectedFolderId;
if (moduleSource === 'file') {
path = bridge().showOpenDialog({
filters: [{ name: module.description, extensions: [module.fileExtension]}]
});
} else {
path = bridge().showOpenDialog({
properties: ['openDirectory', 'createDirectory'],
});
}
if (!path || (Array.isArray(path) && !path.length)) return;
if (Array.isArray(path)) path = path[0];
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'showModalMessage',
message: _('Importing from "%s" as "%s" format. Please wait...', path, module.format),
});
const importOptions = {};
importOptions.path = path;
importOptions.format = module.format;
importOptions.destinationFolderId = !module.isNoteArchive && moduleSource === 'file' ? selectedFolderId : null;
const service = new InteropService();
try {
const result = await service.import(importOptions);
console.info('Import result: ', result);
} catch (error) {
bridge().showErrorMessageBox(error.message);
}
this.dispatch({
type: 'WINDOW_COMMAND',
name: 'hideModalMessage',
});
}
});
}
}
}
const template = [
{
label: _('File'),
@ -226,25 +333,31 @@ class Application extends BaseApplication {
}
}, {
type: 'separator',
}, {
label: _('Import Evernote notes'),
click: () => {
const filePaths = bridge().showOpenDialog({
properties: ['openFile', 'createDirectory'],
filters: [
{ name: _('Evernote Export Files'), extensions: ['enex'] },
]
});
if (!filePaths || !filePaths.length) return;
// }, {
// label: _('Import Evernote notes'),
// click: () => {
// const filePaths = bridge().showOpenDialog({
// properties: ['openFile', 'createDirectory'],
// filters: [
// { name: _('Evernote Export Files'), extensions: ['enex'] },
// ]
// });
// if (!filePaths || !filePaths.length) return;
this.dispatch({
type: 'NAV_GO',
routeName: 'Import',
props: {
filePath: filePaths[0],
},
});
}
// this.dispatch({
// type: 'NAV_GO',
// routeName: 'Import',
// props: {
// filePath: filePaths[0],
// },
// });
// }
}, {
label: _('Import'),
submenu: importItems,
}, {
label: _('Export'),
submenu: exportItems,
}, {
type: 'separator',
platforms: ['darwin'],

View File

@ -26,7 +26,7 @@ class Bridge {
if (!this.window()) return { width: 0, height: 0 };
const s = this.window().getContentSize();
return { width: s[0], height: s[1] };
}
}
windowSize() {
if (!this.window()) return { width: 0, height: 0 };
@ -108,23 +108,6 @@ class Bridge {
return require('electron').shell.openItem(fullPath)
}
// async checkForUpdatesAndNotify(logFilePath) {
// if (!this.autoUpdater_) {
// this.autoUpdateLogger_ = new Logger();
// this.autoUpdateLogger_.addTarget('file', { path: logFilePath });
// this.autoUpdateLogger_.setLevel(Logger.LEVEL_DEBUG);
// this.autoUpdateLogger_.info('checkForUpdatesAndNotify: Initializing...');
// this.autoUpdater_ = require("electron-updater").autoUpdater;
// this.autoUpdater_.logger = this.autoUpdateLogger_;
// }
// try {
// await this.autoUpdater_.checkForUpdatesAndNotify();
// } catch (error) {
// this.autoUpdateLogger_.error(error);
// }
// }
checkForUpdates(inBackground, window, logFilePath) {
const { checkForUpdates } = require('./checkForUpdates.js');
checkForUpdates(inBackground, window, logFilePath);

View File

@ -22,6 +22,10 @@ class MainScreenComponent extends React.Component {
componentWillMount() {
this.setState({
promptOptions: null,
modalLayer: {
visible: false,
message: '',
},
});
}
@ -165,6 +169,10 @@ class MainScreenComponent extends React.Component {
});
} else if (command.name === 'toggleVisiblePanes') {
this.toggleVisiblePanes();
} else if (command.name === 'showModalMessage') {
this.setState({ modalLayer: { visible: true, message: command.message } });
} else if (command.name === 'hideModalMessage') {
this.setState({ modalLayer: { visible: false, message: '' } });
} else if (command.name === 'editAlarm') {
const note = await Note.load(command.noteId);
@ -265,6 +273,17 @@ class MainScreenComponent extends React.Component {
height: height,
};
this.styles_.modalLayer = Object.assign({}, theme.textStyle, {
zIndex: 10000,
position: 'absolute',
top: 0,
left: 0,
backgroundColor: theme.backgroundColorTransparent,
width: width - 20,
height: height - 20,
padding: 10,
});
return this.styles_;
}
@ -353,8 +372,12 @@ class MainScreenComponent extends React.Component {
);
}
const modalLayerStyle = Object.assign({}, styles.modalLayer, { display: this.state.modalLayer.visible ? 'block' : 'none' });
return (
<div style={style}>
<div style={modalLayerStyle}>{this.state.modalLayer.message}</div>
<PromptDialog
autocomplete={promptOptions && ('autocomplete' in promptOptions) ? promptOptions.autocomplete : null}
defaultValue={promptOptions && promptOptions.value ? promptOptions.value : ''}

View File

@ -42,11 +42,6 @@
"integrity": "sha512-jjpyQsKGsOF/wUElNjfPULk+d8PKvJOIXk3IUeBYYmNCy5dMWfrI+JiixYNw8ppKOlcRwWTXFl0B+i5oGrf95Q==",
"dev": true
},
"adm-zip": {
"version": "0.4.7",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz",
"integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E="
},
"ajv": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz",
@ -952,8 +947,7 @@
"chownr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz",
"integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=",
"dev": true
"integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE="
},
"chromium-pickle-js": {
"version": "0.2.0",
@ -2015,6 +2009,14 @@
}
}
},
"fs-minipass": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
"requires": {
"minipass": "2.2.1"
}
},
"fs-readdir-recursive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz",
@ -3009,6 +3011,22 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"minipass": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.1.tgz",
"integrity": "sha512-u1aUllxPJUI07cOqzR7reGmQxmCqlH88uIIsf6XZFEWgw7gXKpJdR+5R9Y3KEDmWYkdIz9wXZs3C0jOPxejk/Q==",
"requires": {
"yallist": "3.0.2"
}
},
"minizlib": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz",
"integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==",
"requires": {
"minipass": "2.2.1"
}
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
@ -3964,6 +3982,18 @@
"nan": "2.7.0",
"semver": "5.4.1",
"tar": "2.2.1"
},
"dependencies": {
"tar": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
"integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
"requires": {
"block-stream": "0.0.9",
"fstream": "1.0.11",
"inherits": "2.0.3"
}
}
}
},
"shebang-command": {
@ -4936,13 +4966,16 @@
"integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0="
},
"tar": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
"integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.0.tgz",
"integrity": "sha512-gJlTiiErwo96K904FnoYWl+5+FBgS+FimU6GMh66XLdLa55al8+d4jeDfPoGwSNHdtWI5FJP6xurmVqhBuGJpQ==",
"requires": {
"block-stream": "0.0.9",
"fstream": "1.0.11",
"inherits": "2.0.3"
"chownr": "1.0.1",
"fs-minipass": "1.2.5",
"minipass": "2.2.1",
"minizlib": "1.1.0",
"mkdirp": "0.5.1",
"yallist": "3.0.2"
}
},
"tar-fs": {
@ -5397,6 +5430,11 @@
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
"dev": true
},
"yallist": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k="
},
"yargs": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-10.0.3.tgz",

View File

@ -91,6 +91,7 @@
"sqlite3": "^3.1.13",
"string-padding": "^1.0.2",
"string-to-stream": "^1.1.0",
"tar": "^4.4.0",
"tcp-port-used": "^0.1.2",
"url-parse": "^1.2.0",
"uuid": "^3.1.0",

View File

@ -7,6 +7,7 @@ const globalStyle = {
itemMarginTop: 10,
itemMarginBottom: 10,
backgroundColor: "#ffffff",
backgroundColorTransparent: 'rgba(255,255,255,0.9)',
oddBackgroundColor: "#dddddd",
color: "#222222", // For regular text
colorError: "red",

View File

@ -207,18 +207,18 @@ Current translations:
<!-- LOCALE-TABLE-AUTO-GENERATED -->
&nbsp; | Language | Po File | Last translator | Percent done
---|---|---|---|---
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/es/basque_country.png) | Basque | [eu](https://github.com/laurent22/joplin/blob/master/CliClient/locales/eu.po) | juan.abasolo@ehu.eus | 87%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/hr.png) | Croatian | [hr_HR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/hr_HR.po) | Hrvoje Mandić <trbuhom@net.hr> | 71%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/de.png) | Deutsch | [de_DE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/de_DE.po) | Tobias Strobel <git@strobeltobias.de> | 89%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/es/basque_country.png) | Basque | [eu](https://github.com/laurent22/joplin/blob/master/CliClient/locales/eu.po) | juan.abasolo@ehu.eus | 82%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/hr.png) | Croatian | [hr_HR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/hr_HR.po) | Hrvoje Mandić <trbuhom@net.hr> | 66%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/de.png) | Deutsch | [de_DE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/de_DE.po) | Tobias Strobel <git@strobeltobias.de> | 84%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/gb.png) | English | [en_GB](https://github.com/laurent22/joplin/blob/master/CliClient/locales/en_GB.po) | | 100%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/es.png) | Español | [es_ES](https://github.com/laurent22/joplin/blob/master/CliClient/locales/es_ES.po) | Fernando Martín <f@mrtn.es> | 100%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/fr.png) | Français | [fr_FR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/fr_FR.po) | Laurent Cozic | 100%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/it.png) | Italiano | [it_IT](https://github.com/laurent22/joplin/blob/master/CliClient/locales/it_IT.po) | | 73%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/be.png) | Nederlands | [nl_BE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/nl_BE.po) | | 87%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/br.png) | Português (Brasil) | [pt_BR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/pt_BR.po) | | 71%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/ru.png) | Русский | [ru_RU](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ru_RU.po) | Artyom Karlov <artyom.karlov@gmail.com> | 91%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/cn.png) | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/master/CliClient/locales/zh_CN.po) | RCJacH <RCJacH@outlook.com> | 73%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/jp.png) | 日本語 | [ja_JP](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ja_JP.po) | | 71%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/es.png) | Español | [es_ES](https://github.com/laurent22/joplin/blob/master/CliClient/locales/es_ES.po) | Fernando Martín <f@mrtn.es> | 94%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/fr.png) | Français | [fr_FR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/fr_FR.po) | Laurent Cozic | 94%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/it.png) | Italiano | [it_IT](https://github.com/laurent22/joplin/blob/master/CliClient/locales/it_IT.po) | | 68%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/be.png) | Nederlands | [nl_BE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/nl_BE.po) | | 82%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/br.png) | Português (Brasil) | [pt_BR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/pt_BR.po) | | 67%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/ru.png) | Русский | [ru_RU](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ru_RU.po) | Artyom Karlov <artyom.karlov@gmail.com> | 86%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/cn.png) | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/master/CliClient/locales/zh_CN.po) | RCJacH <RCJacH@outlook.com> | 68%
![](https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/jp.png) | 日本語 | [ja_JP](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ja_JP.po) | | 66%
<!-- LOCALE-TABLE-AUTO-GENERATED -->
# Known bugs

View File

@ -274,81 +274,91 @@ The following commands are available in [command-line mode](#command-line-mode):
Possible keys/values:
editor Text editor.
The editor that will be used to open a note. If
none is provided it will try to auto-detect the
default editor.
Type: string.
editor Text editor.
The editor that will be used to open a note. If
none is provided it will try to auto-detect the
default editor.
Type: string.
locale Language.
Type: Enum.
Possible values: en_GB (English), de_DE (Deutsch),
es_CR (Español (Costa Rica)), es_ES (Español), eu
(Basque), fr_FR (Français), hr_HR (Croatian), it_IT
(Italiano), ja_JP (日本語), nl_BE (Nederlands), pt_BR
(Português (Brasil)), ru_RU (Русский), zh_CN (中文
(简体)).
Default: "en_GB"
locale Language.
Type: Enum.
Possible values: eu (Basque), hr_HR (Croatian),
de_DE (Deutsch), en_GB (English), es_ES
(Español), fr_FR (Français), it_IT (Italiano),
nl_BE (Nederlands), pt_BR (Português (Brasil)),
ru_RU (Русский), zh_CN (中文 (简体)), ja_JP (日本語).
Default: "en_GB"
dateFormat Date format.
Type: Enum.
Possible values: DD/MM/YYYY (30/01/2017), DD/MM/YY
(30/01/17), MM/DD/YYYY (01/30/2017), MM/DD/YY
(01/30/17), YYYY-MM-DD (2017-01-30).
Default: "DD/MM/YYYY"
dateFormat Date format.
Type: Enum.
Possible values: DD/MM/YYYY (30/01/2017),
DD/MM/YY (30/01/17), MM/DD/YYYY (01/30/2017),
MM/DD/YY (01/30/17), YYYY-MM-DD (2017-01-30).
Default: "DD/MM/YYYY"
timeFormat Time format.
Type: Enum.
Possible values: HH:mm (20:30), h:mm A (8:30 PM).
Default: "HH:mm"
timeFormat Time format.
Type: Enum.
Possible values: HH:mm (20:30), h:mm A (8:30 PM).
Default: "HH:mm"
uncompletedTodosOnTop Show uncompleted to-dos on top of the lists.
Type: bool.
Default: true
uncompletedTodosOnTop Uncompleted to-dos on top.
Type: bool.
Default: true
trackLocation Save geo-location with notes.
Type: bool.
Default: true
notes.sortOrder.field Sort notes by.
Type: Enum.
Possible values: user_updated_time (Updated
date), user_created_time (Created date), title
(Title).
Default: "user_updated_time"
sync.interval Synchronisation interval.
Type: Enum.
Possible values: 0 (Disabled), 300 (5 minutes), 600
(10 minutes), 1800 (30 minutes), 3600 (1 hour),
43200 (12 hours), 86400 (24 hours).
Default: 300
notes.sortOrder.reverse Reverse sort order.
Type: bool.
Default: true
sync.target Synchronisation target.
The target to synchonise to. Each sync target may
have additional parameters which are named as
`sync.NUM.NAME` (all documented below).
Type: Enum.
Possible values: 2 (File system), 3 (OneDrive), 4
(OneDrive Dev (For testing only)), 5 (Nextcloud), 6
(WebDAV).
Default: 3
trackLocation Save geo-location with notes.
Type: bool.
Default: true
sync.2.path Directory to synchronise with (absolute path).
The path to synchronise with when file system
synchronisation is enabled. See `sync.target`.
Type: string.
sync.interval Synchronisation interval.
Type: Enum.
Possible values: 0 (Disabled), 300 (5 minutes),
600 (10 minutes), 1800 (30 minutes), 3600 (1
hour), 43200 (12 hours), 86400 (24 hours).
Default: 300
sync.5.path Nextcloud WebDAV URL.
Type: string.
sync.target Synchronisation target.
The target to synchonise to. Each sync target may
have additional parameters which are named as
`sync.NUM.NAME` (all documented below).
Type: Enum.
Possible values: 2 (File system), 3 (OneDrive), 4
(OneDrive Dev (For testing only)), 5 (Nextcloud),
6 (WebDAV).
Default: 3
sync.5.username Nextcloud username.
Type: string.
sync.2.path Directory to synchronise with (absolute path).
The path to synchronise with when file system
synchronisation is enabled. See `sync.target`.
Type: string.
sync.5.password Nextcloud password.
Type: string.
sync.5.path Nextcloud WebDAV URL.
Type: string.
sync.6.path WebDAV URL.
Type: string.
sync.5.username Nextcloud username.
Type: string.
sync.6.username WebDAV username.
Type: string.
sync.5.password Nextcloud password.
Type: string.
sync.6.password WebDAV password.
Type: string.
sync.6.path WebDAV URL.
Type: string.
sync.6.username WebDAV username.
Type: string.
sync.6.password WebDAV password.
Type: string.
cp <note> [notebook]
@ -374,11 +384,13 @@ The following commands are available in [command-line mode](#command-line-mode):
Edit note.
export <directory>
export <path>
Exports Joplin data to the given directory. By default, it will export the
Exports Joplin data to the given path. By default, it will export the
complete database including notebooks, notes, tags and resources.
--format <format> Destination format: jex (Joplin Export File), raw
(Joplin Export Directory)
--note <note> Exports only the given note.
--notebook <notebook> Exports only the given notebook.
@ -390,11 +402,12 @@ The following commands are available in [command-line mode](#command-line-mode):
Displays usage information.
import-enex <file> [notebook]
import <path> [notebook]
Imports an Evernote notebook file (.enex file).
Imports data into Joplin.
-f, --force Do not ask for confirmation.
--format <format> Source format: auto, jex, md, raw, enex
-f, --force Do not ask for confirmation.
mkbook <new-notebook>

View File

@ -7,34 +7,111 @@ const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');
const { basename, filename } = require('lib/path-utils.js');
const fs = require('fs-extra');
const md5 = require('md5');
const ArrayUtils = require('lib/ArrayUtils');
const { sprintf } = require('sprintf-js');
const { shim } = require('lib/shim');
const { _ } = require('lib/locale');
const { fileExtension } = require('lib/path-utils');
const { uuid } = require('lib/uuid.js');
const { importEnex } = require('lib/import-enex');
const { toTitleCase } = require('lib/string-utils');
class InteropService {
newImportExportModule_(format, className) {
try {
const FormatClass = require('lib/services/' + className);
return new FormatClass();
} catch (error) {
error.message = _('Cannot load module for format "%s": %s', format, error.message);
throw error;
constructor() {
this.modules_ = null;
}
modules() {
if (this.modules_) return this.modules_;
let importModules = [
{
format: 'jex',
fileExtension: 'jex',
sources: ['file'],
description: _('Joplin Export File'),
}, {
format: 'md',
fileExtension: 'md',
sources: ['file', 'directory'],
isNoteArchive: false, // Tells whether the file can contain multiple notes (eg. Enex or Jex format)
description: _('Markdown'),
}, {
format: 'raw',
sources: ['directory'],
description: _('Joplin Export Directory'),
}, {
format: 'enex',
fileExtension: 'enex',
sources: ['file'],
description: _('Evernote Export File'),
},
];
let exportModules = [
{
format: 'jex',
fileExtension: 'jex',
target: 'file',
description: _('Joplin Export File'),
}, {
format: 'raw',
target: 'directory',
description: _('Joplin Export Directory'),
},
];
importModules = importModules.map((a) => {
const className = 'InteropService_Importer_' + toTitleCase(a.format);
const output = Object.assign({}, {
type: 'importer',
path: 'lib/services/' + className,
}, a);
if (!('isNoteArchive' in output)) output.isNoteArchive = true;
return output;
});
exportModules = exportModules.map((a) => {
const className = 'InteropService_Exporter_' + toTitleCase(a.format);
return Object.assign({}, {
type: 'exporter',
path: 'lib/services/' + className,
}, a);
});
this.modules_ = importModules.concat(exportModules);
return this.modules_;
}
moduleByFormat_(type, format) {
const modules = this.modules();
for (let i = 0; i < modules.length; i++) {
const m = modules[i];
if (m.format === format && m.type === type) return modules[i];
}
return null;
}
newExporter_(format) {
return this.newImportExportModule_(format, 'InteropService_Exporter_' + toTitleCase(format));
newModule_(type, format) {
const module = this.moduleByFormat_(type, format);
if (!module) throw new Error(_('Cannot load "%s" module for format "%s"', type, format));
const ModuleClass = require(module.path);
return new ModuleClass();
}
newImporter_(format) {
return this.newImportExportModule_(format, 'InteropService_Importer_' + toTitleCase(format));
moduleByFileExtension_(type, ext) {
ext = ext.toLowerCase();
const modules = this.modules();
for (let i = 0; i < modules.length; i++) {
const m = modules[i];
if (type !== m.type) continue;
if (m.fileExtension === ext) return m;
}
return null;
}
async import(options) {
@ -47,25 +124,20 @@ class InteropService {
}, options);
if (options.format === 'auto') {
const ext = fileExtension(options.path).toLowerCase();
if (ext === 'jex') {
options.format = 'jex';
} else if (ext === 'enex') {
options.format = 'enex';
} else {
throw new Error('Cannot automatically detect source format from path: ' + options.path);
}
const module = this.moduleByFileExtension_('importer', fileExtension(options.path));
if (!module) throw new Error(_('Please specify import format for %s', options.path));
options.format = module.format;
}
if (options.destinationFolderId) {
const folder = await Folder.load(options.destinationFolderId);
if (!folder) throw new Error('Notebook not found: ' + options.destinationFolderId);
if (!folder) throw new Error(_('Cannot find "%s".', options.destinationFolderId));
options.destinationFolder = folder;
}
let result = { warnings: [] }
const importer = this.newImporter_(options.format);
const importer = this.newModule_('importer', options.format);
await importer.init(options.path, options);
result = await importer.exec(result);
@ -132,7 +204,7 @@ class InteropService {
await queueExportItem(BaseModel.TYPE_TAG, exportedTagIds[i]);
}
const exporter = this.newExporter_(exportFormat);
const exporter = this.newModule_('exporter', exportFormat);
await exporter.init(exportPath);
for (let i = 0; i < itemsToExport.length; i++) {

View File

@ -54,11 +54,4 @@ class InteropService_Exporter_Jex extends InteropService_Exporter_Base {
}
InteropService_Exporter_Jex.metadata = function() {
return {
format: 'jex',
fileExtension: 'jex',
};
}
module.exports = InteropService_Exporter_Jex;

View File

@ -27,10 +27,4 @@ class InteropService_Exporter_Raw extends InteropService_Exporter_Base {
}
InteropService_Exporter_Raw.metadata = function() {
return {
format: 'raw',
};
}
module.exports = InteropService_Exporter_Raw;

View File

@ -14,11 +14,12 @@ const { shim } = require('lib/shim');
const { _ } = require('lib/locale');
const { fileExtension } = require('lib/path-utils');
const { uuid } = require('lib/uuid.js');
const { importEnex } = require('lib/import-enex');
class InteropService_Importer_Enex extends InteropService_Importer_Base {
async exec(result) {
const { importEnex } = require('lib/import-enex');
let folder = this.options_.destinationFolder;
if (!folder) {

View File

@ -47,11 +47,4 @@ class InteropService_Importer_Jex extends InteropService_Importer_Base {
}
InteropService_Importer_Jex.metadata = function() {
return {
format: 'jex',
fileExtension: 'jex',
};
}
module.exports = InteropService_Importer_Jex;

View File

@ -6,7 +6,7 @@ const Folder = require('lib/models/Folder.js');
const NoteTag = require('lib/models/NoteTag.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');
const { basename, filename } = require('lib/path-utils.js');
const { basename, filename, rtrimSlashes } = require('lib/path-utils.js');
const fs = require('fs-extra');
const md5 = require('md5');
const { sprintf } = require('sprintf-js');
@ -19,9 +19,7 @@ const { importEnex } = require('lib/import-enex');
class InteropService_Importer_Md extends InteropService_Importer_Base {
async exec(result) {
if (!this.options_.destinationFolder) throw new Error(_('Please specify the notebook where the notes should be imported to.'));
const parentFolderId = this.options_.destinationFolder.id;
let parentFolderId = null;
const filePaths = [];
if (await shim.fsDriver().isDirectory(this.sourcePath_)) {
@ -32,7 +30,17 @@ class InteropService_Importer_Md extends InteropService_Importer_Base {
filePaths.push(this.sourcePath_ + '/' + stat.path);
}
}
if (!this.options_.destinationFolder) {
const folderTitle = await Folder.findUniqueFolderTitle(basename(rtrimSlashes(this.sourcePath_)));
const folder = await Folder.save({ title: folderTitle });
parentFolderId = folder.id;
} else {
parentFolderId = this.options_.destinationFolder.id;
}
} else {
if (!this.options_.destinationFolder) throw new Error(_('Please specify the notebook where the notes should be imported to.'));
parentFolderId = this.options_.destinationFolder.id
filePaths.push(this.sourcePath_);
}
@ -59,11 +67,4 @@ class InteropService_Importer_Md extends InteropService_Importer_Base {
}
InteropService_Importer_Md.metadata = function() {
return {
format: 'md',
fileExtension: 'md',
};
}
module.exports = InteropService_Importer_Md;

View File

@ -110,30 +110,27 @@ class InteropService_Importer_Raw extends InteropService_Importer_Base {
await NoteTag.save(noteTag, { isNew: true });
}
const resourceStats = await shim.fsDriver().readDirStats(this.sourcePath_ + '/resources');
if (await shim.fsDriver().isDirectory(this.sourcePath_ + '/resources')) {
const resourceStats = await shim.fsDriver().readDirStats(this.sourcePath_ + '/resources');
for (let i = 0; i < resourceStats.length; i++) {
const resourceFilePath = this.sourcePath_ + '/resources/' + resourceStats[i].path;
const oldId = Resource.pathToId(resourceFilePath);
const newId = resourceIdMap[oldId];
if (!newId) {
result.warnings.push(sprintf('Resource file is not referenced in any note and so was not imported: %s', oldId));
continue;
for (let i = 0; i < resourceStats.length; i++) {
const resourceFilePath = this.sourcePath_ + '/resources/' + resourceStats[i].path;
const oldId = Resource.pathToId(resourceFilePath);
const newId = resourceIdMap[oldId];
if (!newId) {
result.warnings.push(sprintf('Resource file is not referenced in any note and so was not imported: %s', oldId));
continue;
}
const resource = createdResources[newId];
const destPath = Resource.fullPath(resource);
await shim.fsDriver().copy(resourceFilePath, destPath);
}
const resource = createdResources[newId];
const destPath = Resource.fullPath(resource);
await shim.fsDriver().copy(resourceFilePath, destPath);
}
return result;
}
}
InteropService_Importer_Raw.metadata = function() {
return {
format: 'raw',
};
}
module.exports = InteropService_Importer_Raw;

View File

@ -18,9 +18,9 @@
}
},
"fs-extra": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz",
"integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz",
"integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==",
"requires": {
"graceful-fs": "4.1.11",
"jsonfile": "4.0.0",
@ -88,6 +88,11 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"string-padding": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-padding/-/string-padding-1.0.2.tgz",
"integrity": "sha1-OqrYVbPpc1xeQS3+chmMz5nH9I4="
},
"universalify": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",

View File

@ -10,11 +10,12 @@
"license": "ISC",
"dependencies": {
"app-module-path": "^2.2.0",
"fs-extra": "^4.0.2",
"fs-extra": "^4.0.3",
"gettext-parser": "^1.3.0",
"marked": "^0.3.7",
"mustache": "^2.3.0",
"node-fetch": "^1.7.3",
"string-padding": "^1.0.2",
"uri-template": "^1.0.1"
}
}

View File

@ -392,21 +392,21 @@ $$
<td>Basque</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/eu.po">eu</a></td>
<td>juan.abasolo@ehu.eus</td>
<td>87%</td>
<td>82%</td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/hr.png" alt=""></td>
<td>Croatian</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/hr_HR.po">hr_HR</a></td>
<td>Hrvoje Mandić <a href="&#x6d;&#97;&#x69;&#x6c;&#x74;&#x6f;&#x3a;&#116;&#x72;&#x62;&#117;&#104;&#x6f;&#x6d;&#64;&#x6e;&#x65;&#x74;&#46;&#x68;&#x72;">&#116;&#x72;&#x62;&#117;&#104;&#x6f;&#x6d;&#64;&#x6e;&#x65;&#x74;&#46;&#x68;&#x72;</a></td>
<td>71%</td>
<td>Hrvoje Mandić <a href="&#109;&#x61;&#x69;&#x6c;&#x74;&#x6f;&#58;&#x74;&#x72;&#98;&#117;&#104;&#111;&#x6d;&#64;&#x6e;&#101;&#x74;&#x2e;&#104;&#x72;">&#x74;&#x72;&#98;&#117;&#104;&#111;&#x6d;&#64;&#x6e;&#101;&#x74;&#x2e;&#104;&#x72;</a></td>
<td>66%</td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/de.png" alt=""></td>
<td>Deutsch</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/de_DE.po">de_DE</a></td>
<td>Tobias Strobel <a href="&#x6d;&#97;&#105;&#x6c;&#x74;&#111;&#x3a;&#103;&#x69;&#116;&#x40;&#115;&#116;&#114;&#111;&#98;&#x65;&#108;&#116;&#x6f;&#98;&#105;&#97;&#x73;&#46;&#100;&#101;">&#103;&#x69;&#116;&#x40;&#115;&#116;&#114;&#111;&#98;&#x65;&#108;&#116;&#x6f;&#98;&#105;&#97;&#x73;&#46;&#100;&#101;</a></td>
<td>89%</td>
<td>Tobias Strobel <a href="&#x6d;&#97;&#x69;&#108;&#116;&#111;&#58;&#x67;&#x69;&#x74;&#64;&#115;&#x74;&#114;&#x6f;&#98;&#101;&#x6c;&#116;&#x6f;&#x62;&#x69;&#97;&#x73;&#46;&#x64;&#x65;">&#x67;&#x69;&#x74;&#64;&#115;&#x74;&#114;&#x6f;&#98;&#101;&#x6c;&#116;&#x6f;&#x62;&#x69;&#97;&#x73;&#46;&#x64;&#x65;</a></td>
<td>84%</td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/gb.png" alt=""></td>
@ -419,57 +419,57 @@ $$
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/es.png" alt=""></td>
<td>Español</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/es_ES.po">es_ES</a></td>
<td>Fernando Martín <a href="&#109;&#x61;&#x69;&#108;&#x74;&#x6f;&#58;&#x66;&#x40;&#x6d;&#114;&#116;&#x6e;&#x2e;&#101;&#115;">&#x66;&#x40;&#x6d;&#114;&#116;&#x6e;&#x2e;&#101;&#115;</a></td>
<td>100%</td>
<td>Fernando Martín <a href="&#x6d;&#97;&#x69;&#108;&#116;&#111;&#58;&#102;&#64;&#x6d;&#x72;&#x74;&#x6e;&#x2e;&#101;&#115;">&#102;&#64;&#x6d;&#x72;&#x74;&#x6e;&#x2e;&#101;&#115;</a></td>
<td>94%</td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/fr.png" alt=""></td>
<td>Français</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/fr_FR.po">fr_FR</a></td>
<td>Laurent Cozic</td>
<td>100%</td>
<td>94%</td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/it.png" alt=""></td>
<td>Italiano</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/it_IT.po">it_IT</a></td>
<td></td>
<td>73%</td>
<td>68%</td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/be.png" alt=""></td>
<td>Nederlands</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/nl_BE.po">nl_BE</a></td>
<td></td>
<td>87%</td>
<td>82%</td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/br.png" alt=""></td>
<td>Português (Brasil)</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/pt_BR.po">pt_BR</a></td>
<td></td>
<td>71%</td>
<td>67%</td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/ru.png" alt=""></td>
<td>Русский</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/ru_RU.po">ru_RU</a></td>
<td>Artyom Karlov <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#x3a;&#x61;&#x72;&#x74;&#x79;&#111;&#x6d;&#x2e;&#x6b;&#x61;&#x72;&#x6c;&#x6f;&#x76;&#x40;&#103;&#x6d;&#97;&#105;&#108;&#x2e;&#x63;&#x6f;&#109;">&#x61;&#x72;&#x74;&#x79;&#111;&#x6d;&#x2e;&#x6b;&#x61;&#x72;&#x6c;&#x6f;&#x76;&#x40;&#103;&#x6d;&#97;&#105;&#108;&#x2e;&#x63;&#x6f;&#109;</a></td>
<td>91%</td>
<td>Artyom Karlov <a href="&#109;&#x61;&#105;&#108;&#x74;&#x6f;&#58;&#x61;&#114;&#116;&#121;&#x6f;&#109;&#x2e;&#107;&#x61;&#x72;&#x6c;&#x6f;&#118;&#64;&#103;&#109;&#x61;&#105;&#x6c;&#46;&#x63;&#x6f;&#109;">&#x61;&#114;&#116;&#121;&#x6f;&#109;&#x2e;&#107;&#x61;&#x72;&#x6c;&#x6f;&#118;&#64;&#103;&#109;&#x61;&#105;&#x6c;&#46;&#x63;&#x6f;&#109;</a></td>
<td>86%</td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/cn.png" alt=""></td>
<td>中文 (简体)</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/zh_CN.po">zh_CN</a></td>
<td>RCJacH <a href="&#x6d;&#x61;&#x69;&#x6c;&#x74;&#x6f;&#58;&#x52;&#x43;&#74;&#97;&#99;&#72;&#64;&#x6f;&#x75;&#x74;&#x6c;&#111;&#111;&#107;&#46;&#99;&#x6f;&#x6d;">&#x52;&#x43;&#74;&#97;&#99;&#72;&#64;&#x6f;&#x75;&#x74;&#x6c;&#111;&#111;&#107;&#46;&#99;&#x6f;&#x6d;</a></td>
<td>73%</td>
<td>RCJacH <a href="&#x6d;&#x61;&#x69;&#108;&#116;&#111;&#x3a;&#82;&#x43;&#74;&#97;&#99;&#72;&#64;&#x6f;&#117;&#116;&#x6c;&#111;&#x6f;&#x6b;&#46;&#x63;&#x6f;&#x6d;">&#82;&#x43;&#74;&#97;&#99;&#72;&#64;&#x6f;&#117;&#116;&#x6c;&#111;&#x6f;&#x6b;&#46;&#x63;&#x6f;&#x6d;</a></td>
<td>68%</td>
</tr>
<tr>
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/jp.png" alt=""></td>
<td>日本語</td>
<td><a href="https://github.com/laurent22/joplin/blob/master/CliClient/locales/ja_JP.po">ja_JP</a></td>
<td></td>
<td>71%</td>
<td>66%</td>
</tr>
</tbody>
</table>

View File

@ -482,81 +482,91 @@ config [name] [value]
Possible keys/values:
editor Text editor.
The editor that will be used to open a note. If
none is provided it will try to auto-detect the
default editor.
Type: string.
editor Text editor.
The editor that will be used to open a note. If
none is provided it will try to auto-detect the
default editor.
Type: string.
locale Language.
Type: Enum.
Possible values: en_GB (English), de_DE (Deutsch),
es_CR (Español (Costa Rica)), es_ES (Español), eu
(Basque), fr_FR (Français), hr_HR (Croatian), it_IT
(Italiano), ja_JP (日本語), nl_BE (Nederlands), pt_BR
(Português (Brasil)), ru_RU (Русский), zh_CN (中文
(简体)).
Default: &quot;en_GB&quot;
locale Language.
Type: Enum.
Possible values: eu (Basque), hr_HR (Croatian),
de_DE (Deutsch), en_GB (English), es_ES
(Español), fr_FR (Français), it_IT (Italiano),
nl_BE (Nederlands), pt_BR (Português (Brasil)),
ru_RU (Русский), zh_CN (中文 (简体)), ja_JP (日本語).
Default: &quot;en_GB&quot;
dateFormat Date format.
Type: Enum.
Possible values: DD/MM/YYYY (30/01/2017), DD/MM/YY
(30/01/17), MM/DD/YYYY (01/30/2017), MM/DD/YY
(01/30/17), YYYY-MM-DD (2017-01-30).
Default: &quot;DD/MM/YYYY&quot;
dateFormat Date format.
Type: Enum.
Possible values: DD/MM/YYYY (30/01/2017),
DD/MM/YY (30/01/17), MM/DD/YYYY (01/30/2017),
MM/DD/YY (01/30/17), YYYY-MM-DD (2017-01-30).
Default: &quot;DD/MM/YYYY&quot;
timeFormat Time format.
Type: Enum.
Possible values: HH:mm (20:30), h:mm A (8:30 PM).
Default: &quot;HH:mm&quot;
timeFormat Time format.
Type: Enum.
Possible values: HH:mm (20:30), h:mm A (8:30 PM).
Default: &quot;HH:mm&quot;
uncompletedTodosOnTop Show uncompleted to-dos on top of the lists.
Type: bool.
Default: true
uncompletedTodosOnTop Uncompleted to-dos on top.
Type: bool.
Default: true
trackLocation Save geo-location with notes.
Type: bool.
Default: true
notes.sortOrder.field Sort notes by.
Type: Enum.
Possible values: user_updated_time (Updated
date), user_created_time (Created date), title
(Title).
Default: &quot;user_updated_time&quot;
sync.interval Synchronisation interval.
Type: Enum.
Possible values: 0 (Disabled), 300 (5 minutes), 600
(10 minutes), 1800 (30 minutes), 3600 (1 hour),
43200 (12 hours), 86400 (24 hours).
Default: 300
notes.sortOrder.reverse Reverse sort order.
Type: bool.
Default: true
sync.target Synchronisation target.
The target to synchonise to. Each sync target may
have additional parameters which are named as
`sync.NUM.NAME` (all documented below).
Type: Enum.
Possible values: 2 (File system), 3 (OneDrive), 4
(OneDrive Dev (For testing only)), 5 (Nextcloud), 6
(WebDAV).
Default: 3
trackLocation Save geo-location with notes.
Type: bool.
Default: true
sync.2.path Directory to synchronise with (absolute path).
The path to synchronise with when file system
synchronisation is enabled. See `sync.target`.
Type: string.
sync.interval Synchronisation interval.
Type: Enum.
Possible values: 0 (Disabled), 300 (5 minutes),
600 (10 minutes), 1800 (30 minutes), 3600 (1
hour), 43200 (12 hours), 86400 (24 hours).
Default: 300
sync.5.path Nextcloud WebDAV URL.
Type: string.
sync.target Synchronisation target.
The target to synchonise to. Each sync target may
have additional parameters which are named as
`sync.NUM.NAME` (all documented below).
Type: Enum.
Possible values: 2 (File system), 3 (OneDrive), 4
(OneDrive Dev (For testing only)), 5 (Nextcloud),
6 (WebDAV).
Default: 3
sync.5.username Nextcloud username.
Type: string.
sync.2.path Directory to synchronise with (absolute path).
The path to synchronise with when file system
synchronisation is enabled. See `sync.target`.
Type: string.
sync.5.password Nextcloud password.
Type: string.
sync.5.path Nextcloud WebDAV URL.
Type: string.
sync.6.path WebDAV URL.
Type: string.
sync.5.username Nextcloud username.
Type: string.
sync.6.username WebDAV username.
Type: string.
sync.5.password Nextcloud password.
Type: string.
sync.6.password WebDAV password.
Type: string.
sync.6.path WebDAV URL.
Type: string.
sync.6.username WebDAV username.
Type: string.
sync.6.password WebDAV password.
Type: string.
cp &lt;note&gt; [notebook]
@ -582,11 +592,13 @@ edit &lt;note&gt;
Edit note.
export &lt;directory&gt;
export &lt;path&gt;
Exports Joplin data to the given directory. By default, it will export the
Exports Joplin data to the given path. By default, it will export the
complete database including notebooks, notes, tags and resources.
--format &lt;format&gt; Destination format: jex (Joplin Export File), raw
(Joplin Export Directory)
--note &lt;note&gt; Exports only the given note.
--notebook &lt;notebook&gt; Exports only the given notebook.
@ -598,11 +610,12 @@ help [command]
Displays usage information.
import-enex &lt;file&gt; [notebook]
import &lt;path&gt; [notebook]
Imports an Evernote notebook file (.enex file).
Imports data into Joplin.
-f, --force Do not ask for confirmation.
--format &lt;format&gt; Source format: auto, jex, md, raw, enex
-f, --force Do not ask for confirmation.
mkbook &lt;new-notebook&gt;