You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-24 20:19:10 +02:00
Compare commits
9 Commits
cli-v1.0.1
...
android-v1
Author | SHA1 | Date | |
---|---|---|---|
|
7a985c2c8a | ||
|
b11ad30a31 | ||
|
5914fc97df | ||
|
e41ae1832d | ||
|
89b50909ed | ||
|
edccd7412f | ||
|
c76beae057 | ||
|
23c5934a7d | ||
|
a078947d6d |
@@ -53,9 +53,8 @@ function renderCommandHelp(cmd, width = null) {
|
||||
desc.push(label);
|
||||
}
|
||||
|
||||
if (md.description) {
|
||||
desc.push(md.description());
|
||||
}
|
||||
const description = Setting.keyDescription(md.key, 'cli');
|
||||
if (description) desc.push(description);
|
||||
|
||||
desc.push(_('Type: %s.', md.isEnum ? _('Enum') : Setting.typeToString(md.type)));
|
||||
if (md.isEnum) desc.push(_('Possible values: %s.', Setting.enumOptionsDoc(md.key, '%s (%s)')));
|
||||
|
@@ -1126,9 +1126,18 @@ msgstr "Erstellt eine neue Notiz."
|
||||
msgid "Show tray icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set application zoom percentage"
|
||||
#, fuzzy
|
||||
msgid "Global zoom percentage"
|
||||
msgstr "Einstellen des Anwendungszooms"
|
||||
|
||||
msgid "Editor font family"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The font name will not be checked. If incorrect or empty, it will default to "
|
||||
"a generic monospace font."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
msgstr "Die Applikation automatisch aktualisieren"
|
||||
|
||||
|
@@ -993,7 +993,15 @@ msgstr ""
|
||||
msgid "Show tray icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set application zoom percentage"
|
||||
msgid "Global zoom percentage"
|
||||
msgstr ""
|
||||
|
||||
msgid "Editor font family"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The font name will not be checked. If incorrect or empty, it will default to "
|
||||
"a generic monospace font."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
|
@@ -1098,9 +1098,18 @@ msgstr "Cuando se crear una nota nueva:"
|
||||
msgid "Show tray icon"
|
||||
msgstr "Mostrar icono en la bandeja"
|
||||
|
||||
msgid "Set application zoom percentage"
|
||||
#, fuzzy
|
||||
msgid "Global zoom percentage"
|
||||
msgstr "Establecer el porcentaje de aumento de la aplicación"
|
||||
|
||||
msgid "Editor font family"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The font name will not be checked. If incorrect or empty, it will default to "
|
||||
"a generic monospace font."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
msgstr "Actualizar la aplicación automáticamente"
|
||||
|
||||
|
@@ -1101,9 +1101,18 @@ msgstr "Ohar berria sortzen du."
|
||||
msgid "Show tray icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set application zoom percentage"
|
||||
#, fuzzy
|
||||
msgid "Global zoom percentage"
|
||||
msgstr "Ezarri aplikazioaren zoomaren ehunekoa"
|
||||
|
||||
msgid "Editor font family"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The font name will not be checked. If incorrect or empty, it will default to "
|
||||
"a generic monospace font."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
msgstr "Automatikoki eguneratu aplikazioa"
|
||||
|
||||
|
@@ -1101,9 +1101,19 @@ msgstr "Lors de la création d'une note :"
|
||||
msgid "Show tray icon"
|
||||
msgstr "Afficher icône dans la zone de notifications"
|
||||
|
||||
msgid "Set application zoom percentage"
|
||||
msgid "Global zoom percentage"
|
||||
msgstr "Niveau de zoom"
|
||||
|
||||
msgid "Editor font family"
|
||||
msgstr "Police de l'éditeur"
|
||||
|
||||
msgid ""
|
||||
"The font name will not be checked. If incorrect or empty, it will default to "
|
||||
"a generic monospace font."
|
||||
msgstr ""
|
||||
"Le nom de la police ne sera pas vérifié. Si incorrect ou vide une police "
|
||||
"monospace sera utilisée par défaut."
|
||||
|
||||
msgid "Automatically update the application"
|
||||
msgstr "Mettre à jour le logiciel automatiquement"
|
||||
|
||||
|
@@ -1089,7 +1089,15 @@ msgstr "Stvara novu bilješku."
|
||||
msgid "Show tray icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set application zoom percentage"
|
||||
msgid "Global zoom percentage"
|
||||
msgstr ""
|
||||
|
||||
msgid "Editor font family"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The font name will not be checked. If incorrect or empty, it will default to "
|
||||
"a generic monospace font."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
|
@@ -1075,7 +1075,15 @@ msgstr "Crea una nuova nota."
|
||||
msgid "Show tray icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set application zoom percentage"
|
||||
msgid "Global zoom percentage"
|
||||
msgstr ""
|
||||
|
||||
msgid "Editor font family"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The font name will not be checked. If incorrect or empty, it will default to "
|
||||
"a generic monospace font."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
|
@@ -1079,7 +1079,15 @@ msgstr "あたらしいノートを作成します。"
|
||||
msgid "Show tray icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set application zoom percentage"
|
||||
msgid "Global zoom percentage"
|
||||
msgstr ""
|
||||
|
||||
msgid "Editor font family"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The font name will not be checked. If incorrect or empty, it will default to "
|
||||
"a generic monospace font."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
|
@@ -993,7 +993,15 @@ msgstr ""
|
||||
msgid "Show tray icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set application zoom percentage"
|
||||
msgid "Global zoom percentage"
|
||||
msgstr ""
|
||||
|
||||
msgid "Editor font family"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The font name will not be checked. If incorrect or empty, it will default to "
|
||||
"a generic monospace font."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
|
@@ -1105,7 +1105,15 @@ msgstr "Maakt een nieuwe notitie aan."
|
||||
msgid "Show tray icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set application zoom percentage"
|
||||
msgid "Global zoom percentage"
|
||||
msgstr ""
|
||||
|
||||
msgid "Editor font family"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The font name will not be checked. If incorrect or empty, it will default to "
|
||||
"a generic monospace font."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
|
@@ -1076,7 +1076,15 @@ msgstr "Cria uma nova nota."
|
||||
msgid "Show tray icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set application zoom percentage"
|
||||
msgid "Global zoom percentage"
|
||||
msgstr ""
|
||||
|
||||
msgid "Editor font family"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The font name will not be checked. If incorrect or empty, it will default to "
|
||||
"a generic monospace font."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
|
@@ -1101,9 +1101,18 @@ msgstr "При создании новой заметки:"
|
||||
msgid "Show tray icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set application zoom percentage"
|
||||
#, fuzzy
|
||||
msgid "Global zoom percentage"
|
||||
msgstr "Масштаб приложения в процентах"
|
||||
|
||||
msgid "Editor font family"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The font name will not be checked. If incorrect or empty, it will default to "
|
||||
"a generic monospace font."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
msgstr "Автоматически обновлять приложение"
|
||||
|
||||
|
@@ -1041,7 +1041,15 @@ msgstr "创建新笔记。"
|
||||
msgid "Show tray icon"
|
||||
msgstr ""
|
||||
|
||||
msgid "Set application zoom percentage"
|
||||
msgid "Global zoom percentage"
|
||||
msgstr ""
|
||||
|
||||
msgid "Editor font family"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"The font name will not be checked. If incorrect or empty, it will default to "
|
||||
"a generic monospace font."
|
||||
msgstr ""
|
||||
|
||||
msgid "Automatically update the application"
|
||||
|
@@ -209,4 +209,44 @@ describe('services_InteropService', function() {
|
||||
expect(fileContentEqual(resourcePath1, resourcePath2)).toBe(true);
|
||||
}));
|
||||
|
||||
it('should export and import single notes', asyncTest(async () => {
|
||||
const service = new InteropService();
|
||||
const filePath = exportDir() + '/test.jex';
|
||||
let folder1 = await Folder.save({ title: "folder1" });
|
||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||
|
||||
await service.export({ path: filePath, sourceNoteIds: [note1.id] });
|
||||
|
||||
await Note.delete(note1.id);
|
||||
await Folder.delete(folder1.id);
|
||||
|
||||
await service.import({ path: filePath });
|
||||
|
||||
expect(await Note.count()).toBe(1);
|
||||
expect(await Folder.count()).toBe(1);
|
||||
|
||||
let folder2 = (await Folder.all())[0];
|
||||
expect(folder2.title).toBe('test');
|
||||
}));
|
||||
|
||||
it('should export and import single folders', asyncTest(async () => {
|
||||
const service = new InteropService();
|
||||
const filePath = exportDir() + '/test.jex';
|
||||
let folder1 = await Folder.save({ title: "folder1" });
|
||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||
|
||||
await service.export({ path: filePath, sourceFolderIds: [folder1.id] });
|
||||
|
||||
await Note.delete(note1.id);
|
||||
await Folder.delete(folder1.id);
|
||||
|
||||
await service.import({ path: filePath });
|
||||
|
||||
expect(await Note.count()).toBe(1);
|
||||
expect(await Folder.count()).toBe(1);
|
||||
|
||||
let folder2 = (await Folder.all())[0];
|
||||
expect(folder2.title).toBe('folder1');
|
||||
}));
|
||||
|
||||
});
|
@@ -172,6 +172,8 @@ class ElectronAppWrapper {
|
||||
}
|
||||
|
||||
ensureSingleInstance() {
|
||||
if (this.env_ === 'dev') return false;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const alreadyRunning = this.electronApp_.makeSingleInstance((commandLine, workingDirectory) => {
|
||||
const win = this.window();
|
||||
|
51
ElectronClient/app/InteropServiceHelper.js
Normal file
51
ElectronClient/app/InteropServiceHelper.js
Normal file
@@ -0,0 +1,51 @@
|
||||
const { _ } = require('lib/locale');
|
||||
const { bridge } = require('electron').remote.require('./bridge');
|
||||
const InteropService = require('lib/services/InteropService');
|
||||
|
||||
class InteropServiceHelper {
|
||||
|
||||
static async export(dispatch, module, options = null) {
|
||||
if (!options) options = {};
|
||||
|
||||
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];
|
||||
|
||||
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;
|
||||
if (options.sourceFolderIds) exportOptions.sourceFolderIds = options.sourceFolderIds;
|
||||
if (options.sourceNoteIds) exportOptions.sourceNoteIds = options.sourceNoteIds;
|
||||
|
||||
const service = new InteropService();
|
||||
const result = await service.export(exportOptions);
|
||||
|
||||
console.info('Export result: ', result);
|
||||
|
||||
dispatch({
|
||||
type: 'WINDOW_COMMAND',
|
||||
name: 'hideModalMessage',
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = InteropServiceHelper;
|
@@ -21,6 +21,7 @@ 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 InteropServiceHelper = require('./InteropServiceHelper.js');
|
||||
|
||||
const { bridge } = require('electron').remote.require('./bridge');
|
||||
const Menu = bridge().Menu;
|
||||
@@ -145,6 +146,10 @@ class Application extends BaseApplication {
|
||||
this.updateTray();
|
||||
}
|
||||
|
||||
if (action.type == 'SETTING_UPDATE_ONE' && action.key == 'style.editor.fontFamily' || action.type == 'SETTING_UPDATE_ALL') {
|
||||
this.updateEditorFont();
|
||||
}
|
||||
|
||||
if (['NOTE_UPDATE_ONE', 'NOTE_DELETE', 'FOLDER_UPDATE_ONE', 'FOLDER_DELETE'].indexOf(action.type) >= 0) {
|
||||
if (!await reg.syncTarget().syncStarted()) reg.scheduleSync();
|
||||
}
|
||||
@@ -203,41 +208,7 @@ class Application extends BaseApplication {
|
||||
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',
|
||||
});
|
||||
await InteropServiceHelper.export(this.dispatch.bind(this), module);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -492,8 +463,8 @@ class Application extends BaseApplication {
|
||||
'Copyright © 2016-2018 Laurent Cozic',
|
||||
_('%s %s (%s, %s)', p.name, p.version, Setting.value('env'), process.platform),
|
||||
];
|
||||
bridge().showMessageBox({
|
||||
message: message.join('\n'),
|
||||
bridge().showInfoMessageBox(message.join('\n'), {
|
||||
icon: bridge().electronApp().buildDir() + '/icons/32x32.png',
|
||||
});
|
||||
}
|
||||
}]
|
||||
@@ -553,6 +524,21 @@ class Application extends BaseApplication {
|
||||
}
|
||||
}
|
||||
|
||||
updateEditorFont() {
|
||||
const fontFamilies = [];
|
||||
if (Setting.value('style.editor.fontFamily')) fontFamilies.push('"' + Setting.value('style.editor.fontFamily') + '"');
|
||||
fontFamilies.push('monospace');
|
||||
|
||||
// The '*' and '!important' parts are necessary to make sure Russian text is displayed properly
|
||||
// https://github.com/laurent22/joplin/issues/155
|
||||
|
||||
const css = '.ace_editor * { font-family: ' + fontFamilies.join(', ') + ' !important; }';
|
||||
const styleTag = document.createElement('style');
|
||||
styleTag.type = 'text/css';
|
||||
styleTag.appendChild(document.createTextNode(css));
|
||||
document.head.appendChild(styleTag);
|
||||
}
|
||||
|
||||
async start(argv) {
|
||||
argv = await super.start(argv);
|
||||
|
||||
|
@@ -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 };
|
||||
@@ -62,20 +62,23 @@ class Bridge {
|
||||
return filePaths;
|
||||
}
|
||||
|
||||
showMessageBox(window, options) {
|
||||
// Don't use this directly - call one of the showXxxxxxxMessageBox() instead
|
||||
showMessageBox_(window, options) {
|
||||
const {dialog} = require('electron');
|
||||
const nativeImage = require('electron').nativeImage
|
||||
if (!window) window = this.window();
|
||||
return dialog.showMessageBox(window, options);
|
||||
}
|
||||
|
||||
showErrorMessageBox(message) {
|
||||
return this.showMessageBox(this.window(), {
|
||||
return this.showMessageBox_(this.window(), {
|
||||
type: 'error',
|
||||
message: message,
|
||||
});
|
||||
}
|
||||
|
||||
showConfirmMessageBox(message) {
|
||||
const result = this.showMessageBox(this.window(), {
|
||||
const result = this.showMessageBox_(this.window(), {
|
||||
type: 'question',
|
||||
message: message,
|
||||
buttons: [_('OK'), _('Cancel')],
|
||||
@@ -83,12 +86,12 @@ class Bridge {
|
||||
return result === 0;
|
||||
}
|
||||
|
||||
showInfoMessageBox(message) {
|
||||
const result = this.showMessageBox(this.window(), {
|
||||
showInfoMessageBox(message, options = {}) {
|
||||
const result = this.showMessageBox_(this.window(), Object.assign({}, {
|
||||
type: 'info',
|
||||
message: message,
|
||||
buttons: [_('OK')],
|
||||
});
|
||||
}, options));
|
||||
return result === 0;
|
||||
}
|
||||
|
||||
|
BIN
ElectronClient/app/build/icons/16x16@2x.png
Normal file
BIN
ElectronClient/app/build/icons/16x16@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
ElectronClient/app/build/icons/16x16@3x.png
Normal file
BIN
ElectronClient/app/build/icons/16x16@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
ElectronClient/app/build/icons/32x32@3.png
Normal file
BIN
ElectronClient/app/build/icons/32x32@3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
@@ -59,6 +59,12 @@ class ConfigScreenComponent extends React.Component {
|
||||
display: 'inline-block',
|
||||
};
|
||||
|
||||
const descriptionStyle = Object.assign({}, theme.textStyle, {
|
||||
color: theme.colorFaded,
|
||||
marginTop: 5,
|
||||
fontStyle: 'italic',
|
||||
});
|
||||
|
||||
const updateSettingValue = (key, value) => {
|
||||
return shared.updateSettingValue(this, key, value);
|
||||
}
|
||||
@@ -67,6 +73,13 @@ class ConfigScreenComponent extends React.Component {
|
||||
|
||||
const md = Setting.settingMetadata(key);
|
||||
|
||||
const descriptionText = Setting.keyDescription(key, 'desktop');
|
||||
const descriptionComp = descriptionText ? (
|
||||
<div style={descriptionStyle}>
|
||||
{descriptionText}
|
||||
</div>
|
||||
) : null;
|
||||
|
||||
if (md.isEnum) {
|
||||
let items = [];
|
||||
const settingOptions = md.options();
|
||||
@@ -82,6 +95,7 @@ class ConfigScreenComponent extends React.Component {
|
||||
<select value={value} style={controlStyle} onChange={(event) => { updateSettingValue(key, event.target.value) }}>
|
||||
{items}
|
||||
</select>
|
||||
{ descriptionComp }
|
||||
</div>
|
||||
);
|
||||
} else if (md.type === Setting.TYPE_BOOL) {
|
||||
@@ -96,6 +110,7 @@ class ConfigScreenComponent extends React.Component {
|
||||
<div key={key+value.toString()} style={rowStyle}>
|
||||
<div style={controlStyle}>
|
||||
<input id={'setting_checkbox_' + key} type="checkbox" checked={!!value} onChange={(event) => { onCheckboxClick(event) }}/><label onClick={(event) => { onCheckboxClick(event) }} style={labelStyle} htmlFor={'setting_checkbox_' + key}>{md.label()}</label>
|
||||
{ descriptionComp }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -111,6 +126,7 @@ class ConfigScreenComponent extends React.Component {
|
||||
<div key={key} style={rowStyle}>
|
||||
<div style={labelStyle}><label>{md.label()}</label></div>
|
||||
<input type={inputType} style={inputStyle} value={this.state.settings[key]} onChange={(event) => {onTextChange(event)}} />
|
||||
{ descriptionComp }
|
||||
</div>
|
||||
);
|
||||
} else if (md.type === Setting.TYPE_INT) {
|
||||
@@ -122,6 +138,7 @@ class ConfigScreenComponent extends React.Component {
|
||||
<div key={key} style={rowStyle}>
|
||||
<div style={labelStyle}><label>{md.label()}</label></div>
|
||||
<input type="number" style={controlStyle} value={this.state.settings[key]} onChange={(event) => {onNumChange(event)}} min={md.minimum} max={md.maximum} step={md.step}/>
|
||||
{ descriptionComp }
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
|
@@ -9,6 +9,8 @@ const { bridge } = require('electron').remote.require('./bridge');
|
||||
const Menu = bridge().Menu;
|
||||
const MenuItem = bridge().MenuItem;
|
||||
const eventManager = require('../eventManager');
|
||||
const InteropService = require('lib/services/InteropService');
|
||||
const InteropServiceHelper = require('../InteropServiceHelper.js');
|
||||
|
||||
class NoteListComponent extends React.Component {
|
||||
|
||||
@@ -91,6 +93,12 @@ class NoteListComponent extends React.Component {
|
||||
eventManager.emit('noteTypeToggle', { noteId: note.id });
|
||||
}
|
||||
}}));
|
||||
|
||||
menu.append(new MenuItem({label: _('Export'), click: async () => {
|
||||
const ioService = new InteropService();
|
||||
const module = ioService.moduleByFormat_('exporter', 'jex');
|
||||
await InteropServiceHelper.export(this.props.dispatch.bind(this), module, { sourceNoteIds: noteIds });
|
||||
}}));
|
||||
}
|
||||
|
||||
menu.append(new MenuItem({label: _('Delete'), click: async () => {
|
||||
|
@@ -320,10 +320,7 @@ class NoteTextComponent extends React.Component {
|
||||
bridge().openItem(filePath);
|
||||
});
|
||||
} else {
|
||||
bridge().showMessageBox({
|
||||
type: 'error',
|
||||
message: _('Unsupported link or message: %s', msg),
|
||||
});
|
||||
bridge().showErrorMessageBox(_('Unsupported link or message: %s', msg));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -54,10 +54,7 @@ class OneDriveLoginScreenComponent extends React.Component {
|
||||
this.props.dispatch({ type: 'NAV_BACK' });
|
||||
reg.scheduleSync(0);
|
||||
} catch (error) {
|
||||
bridge().showMessageBox({
|
||||
type: 'error',
|
||||
message: 'Could not login to OneDrive. Please try again.\n\n' + error.message + "\n\n" + url.match(/.{1,64}/g).join('\n'),
|
||||
});
|
||||
bridge().showErrorMessageBox('Could not login to OneDrive. Please try again.\n\n' + error.message + "\n\n" + url.match(/.{1,64}/g).join('\n'));
|
||||
}
|
||||
|
||||
this.authCode_ = null;
|
||||
|
@@ -11,6 +11,7 @@ const { themeStyle } = require('../theme.js');
|
||||
const { bridge } = require('electron').remote.require('./bridge');
|
||||
const Menu = bridge().Menu;
|
||||
const MenuItem = bridge().MenuItem;
|
||||
const InteropServiceHelper = require('../InteropServiceHelper.js');
|
||||
|
||||
class SideBarComponent extends React.Component {
|
||||
|
||||
@@ -136,7 +137,17 @@ class SideBarComponent extends React.Component {
|
||||
name: 'renameFolder',
|
||||
id: itemId,
|
||||
});
|
||||
}}))
|
||||
}}));
|
||||
|
||||
menu.append(new MenuItem({ type: 'separator' }));
|
||||
|
||||
const InteropService = require('lib/services/InteropService.js');
|
||||
|
||||
menu.append(new MenuItem({label: _('Export'), click: async () => {
|
||||
const ioService = new InteropService();
|
||||
const module = ioService.moduleByFormat_('exporter', 'jex');
|
||||
await InteropServiceHelper.export(this.props.dispatch.bind(this), module, { sourceFolderIds: [itemId] });
|
||||
}}));
|
||||
}
|
||||
|
||||
menu.popup(bridge().window());
|
||||
|
@@ -17,11 +17,6 @@
|
||||
.smalltalk .page {
|
||||
max-width: 30em;
|
||||
}
|
||||
.ace_editor * {
|
||||
/* Necessary to make sure Russian text is displayed properly */
|
||||
/* https://github.com/laurent22/joplin/issues/155 */
|
||||
font-family: monospace !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
16
README.md
16
README.md
@@ -26,7 +26,7 @@ Linux | <a href='https://github.com/laurent22/joplin/releases/download/
|
||||
|
||||
Operating System | Download | Alt. Download
|
||||
-----------------|----------|----------------
|
||||
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeAndroid.png'/></a> | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.102/joplin-v1.0.102.apk)
|
||||
Android | <a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeAndroid.png'/></a> | or [Download APK File](https://github.com/laurent22/joplin-android/releases/download/android-v1.0.103/joplin-v1.0.103.apk)
|
||||
iOS | <a href='https://itunes.apple.com/us/app/joplin/id1315599797'><img alt='Get it on the App Store' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeIOS.png'/></a> | -
|
||||
|
||||
## Terminal application
|
||||
@@ -194,9 +194,9 @@ Here is an example with the Markdown and rendered result side by side:
|
||||
|
||||
Checkboxes can be added like so:
|
||||
|
||||
-[ ] Milk
|
||||
-[ ] Rice
|
||||
-[ ] Eggs
|
||||
- [ ] Milk
|
||||
- [ ] Rice
|
||||
- [ ] Eggs
|
||||
|
||||
The checkboxes can then be ticked in the mobile and desktop applications.
|
||||
|
||||
@@ -222,16 +222,16 @@ Current translations:
|
||||
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
||||
| Language | Po File | Last translator | Percent done
|
||||
---|---|---|---|---
|
||||
 | Basque | [eu](https://github.com/laurent22/joplin/blob/master/CliClient/locales/eu.po) | juan.abasolo@ehu.eus | 82%
|
||||
 | Basque | [eu](https://github.com/laurent22/joplin/blob/master/CliClient/locales/eu.po) | juan.abasolo@ehu.eus | 81%
|
||||
 | Croatian | [hr_HR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/hr_HR.po) | Hrvoje Mandić <trbuhom@net.hr> | 66%
|
||||
 | Deutsch | [de_DE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/de_DE.po) | Tobias Strobel <git@strobeltobias.de> | 84%
|
||||
 | Deutsch | [de_DE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/de_DE.po) | Tobias Strobel <git@strobeltobias.de> | 83%
|
||||
 | English | [en_GB](https://github.com/laurent22/joplin/blob/master/CliClient/locales/en_GB.po) | | 100%
|
||||
 | Español | [es_ES](https://github.com/laurent22/joplin/blob/master/CliClient/locales/es_ES.po) | Fernando Martín <f@mrtn.es> | 94%
|
||||
 | Español | [es_ES](https://github.com/laurent22/joplin/blob/master/CliClient/locales/es_ES.po) | Fernando Martín <f@mrtn.es> | 93%
|
||||
 | Français | [fr_FR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/fr_FR.po) | Laurent Cozic | 100%
|
||||
 | Italiano | [it_IT](https://github.com/laurent22/joplin/blob/master/CliClient/locales/it_IT.po) | | 68%
|
||||
 | Nederlands | [nl_BE](https://github.com/laurent22/joplin/blob/master/CliClient/locales/nl_BE.po) | | 82%
|
||||
 | Português (Brasil) | [pt_BR](https://github.com/laurent22/joplin/blob/master/CliClient/locales/pt_BR.po) | | 66%
|
||||
 | Русский | [ru_RU](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ru_RU.po) | Artyom Karlov <artyom.karlov@gmail.com> | 86%
|
||||
 | Русский | [ru_RU](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ru_RU.po) | Artyom Karlov <artyom.karlov@gmail.com> | 85%
|
||||
 | 中文 (简体) | [zh_CN](https://github.com/laurent22/joplin/blob/master/CliClient/locales/zh_CN.po) | RCJacH <RCJacH@outlook.com> | 68%
|
||||
 | 日本語 | [ja_JP](https://github.com/laurent22/joplin/blob/master/CliClient/locales/ja_JP.po) | | 66%
|
||||
<!-- LOCALE-TABLE-AUTO-GENERATED -->
|
||||
|
@@ -90,8 +90,8 @@ android {
|
||||
applicationId "net.cozic.joplin"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 22
|
||||
versionCode 2097280
|
||||
versionName "1.0.102"
|
||||
versionCode 2097281
|
||||
versionName "1.0.103"
|
||||
ndk {
|
||||
abiFilters "armeabi-v7a", "x86"
|
||||
}
|
||||
|
@@ -83,7 +83,8 @@ class Setting extends BaseModel {
|
||||
'encryption.enabled': { value: false, type: Setting.TYPE_BOOL, public: false },
|
||||
'encryption.activeMasterKeyId': { value: '', type: Setting.TYPE_STRING, public: false },
|
||||
'encryption.passwordCache': { value: {}, type: Setting.TYPE_OBJECT, public: false },
|
||||
'style.zoom': {value: "100", type: Setting.TYPE_INT, public: true, appTypes: ['desktop'], label: () => _('Set application zoom percentage'), minimum: "50", maximum: "500", step: "10"},
|
||||
'style.zoom': {value: "100", type: Setting.TYPE_INT, public: true, appTypes: ['desktop'], label: () => _('Global zoom percentage'), minimum: "50", maximum: "500", step: "10"},
|
||||
'style.editor.fontFamily': {value: "", type: Setting.TYPE_STRING, public: true, appTypes: ['desktop'], label: () => _('Editor font family'), description: () => _('The font name will not be checked. If incorrect or empty, it will default to a generic monospace font.')},
|
||||
'autoUpdateEnabled': { value: true, type: Setting.TYPE_BOOL, public: true, appTypes: ['desktop'], label: () => _('Automatically update the application') },
|
||||
'sync.interval': { value: 300, type: Setting.TYPE_INT, isEnum: true, public: true, label: () => _('Synchronisation interval'), options: () => {
|
||||
return {
|
||||
@@ -98,7 +99,7 @@ class Setting extends BaseModel {
|
||||
}},
|
||||
'noteVisiblePanes': { value: ['editor', 'viewer'], type: Setting.TYPE_ARRAY, public: false, appTypes: ['desktop'] },
|
||||
'showAdvancedOptions': { value: false, type: Setting.TYPE_BOOL, public: true, appTypes: ['mobile' ], label: () => _('Show advanced options') },
|
||||
'sync.target': { value: SyncTargetRegistry.nameToId('onedrive'), type: Setting.TYPE_INT, isEnum: true, public: true, label: () => _('Synchronisation target'), description: () => _('The target to synchonise to. Each sync target may have additional parameters which are named as `sync.NUM.NAME` (all documented below).'), options: () => {
|
||||
'sync.target': { value: SyncTargetRegistry.nameToId('onedrive'), type: Setting.TYPE_INT, isEnum: true, public: true, label: () => _('Synchronisation target'), description: (appType) => { return appType !== 'cli' ? null : _('The target to synchonise to. Each sync target may have additional parameters which are named as `sync.NUM.NAME` (all documented below).') }, options: () => {
|
||||
return SyncTargetRegistry.idAndLabelPlainObject();
|
||||
}},
|
||||
|
||||
@@ -108,7 +109,7 @@ class Setting extends BaseModel {
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}, public: true, label: () => _('Directory to synchronise with (absolute path)'), description: () => _('The path to synchronise with when file system synchronisation is enabled. See `sync.target`.') },
|
||||
}, public: true, label: () => _('Directory to synchronise with (absolute path)'), description: (appType) => { return appType !== 'cli' ? null : _('The path to synchronise with when file system synchronisation is enabled. See `sync.target`.'); } },
|
||||
|
||||
'sync.5.path': { value: '', type: Setting.TYPE_STRING, show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('nextcloud') }, public: true, label: () => _('Nextcloud WebDAV URL') },
|
||||
'sync.5.username': { value: '', type: Setting.TYPE_STRING, show: (settings) => { return settings['sync.target'] == SyncTargetRegistry.nameToId('nextcloud') }, public: true, label: () => _('Nextcloud username') },
|
||||
@@ -143,6 +144,12 @@ class Setting extends BaseModel {
|
||||
return key in this.metadata();
|
||||
}
|
||||
|
||||
static keyDescription(key, appType = null) {
|
||||
const md = this.settingMetadata(key);
|
||||
if (!md.description) return null;
|
||||
return md.description(appType);
|
||||
}
|
||||
|
||||
static keys(publicOnly = false, appType = null) {
|
||||
if (!this.keys_) {
|
||||
const metadata = this.metadata();
|
||||
|
@@ -36,6 +36,8 @@ class InteropService_Importer_Jex extends InteropService_Importer_Base {
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (!('defaultFolderTitle' in this.options_)) this.options_.defaultFolderTitle = filename(this.sourcePath_);
|
||||
|
||||
const importer = new InteropService_Importer_Raw();
|
||||
await importer.init(tempDir, this.options_);
|
||||
result = await importer.exec(result);
|
||||
|
@@ -14,7 +14,6 @@ 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_Raw extends InteropService_Importer_Base {
|
||||
|
||||
@@ -41,6 +40,25 @@ class InteropService_Importer_Raw extends InteropService_Importer_Base {
|
||||
}
|
||||
|
||||
const stats = await shim.fsDriver().readDirStats(this.sourcePath_);
|
||||
|
||||
const folderExists = function(stats, folderId) {
|
||||
folderId = folderId.toLowerCase();
|
||||
for (let i = 0; i < stats.length; i++) {
|
||||
const stat = stats[i];
|
||||
const statId = BaseItem.pathToId(stat.path);
|
||||
if (statId.toLowerCase() === folderId) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
let defaultFolder_ = null;
|
||||
const defaultFolder = async () => {
|
||||
if (defaultFolder_) return defaultFolder_;
|
||||
const folderTitle = await Folder.findUniqueFolderTitle(this.options_.defaultFolderTitle ? this.options_.defaultFolderTitle : 'Imported');
|
||||
defaultFolder_ = await Folder.save({ title: folderTitle });
|
||||
return defaultFolder_;
|
||||
}
|
||||
|
||||
for (let i = 0; i < stats.length; i++) {
|
||||
const stat = stats[i];
|
||||
if (stat.isDirectory()) continue;
|
||||
@@ -54,7 +72,22 @@ class InteropService_Importer_Raw extends InteropService_Importer_Base {
|
||||
delete item.type_;
|
||||
|
||||
if (itemType === BaseModel.TYPE_NOTE) {
|
||||
if (!folderIdMap[item.parent_id]) folderIdMap[item.parent_id] = destinationFolderId ? destinationFolderId : uuid.create();
|
||||
|
||||
// Logic is a bit complex here:
|
||||
// - If a destination folder was specified, move the note to it.
|
||||
// - Otherwise, if the associated folder exists, use this.
|
||||
// - If it doesn't exist, use the default folder. This is the case for example when importing JEX archives that contain only one or more notes, but no folder.
|
||||
if (!folderIdMap[item.parent_id]) {
|
||||
if (destinationFolderId) {
|
||||
folderIdMap[item.parent_id] = destinationFolderId;
|
||||
} else if (!folderExists(stats, item.parent_id)) {
|
||||
const parentFolder = await defaultFolder();
|
||||
folderIdMap[item.parent_id] = parentFolder.id;
|
||||
} else {
|
||||
folderIdMap[item.parent_id] = uuid.create();
|
||||
}
|
||||
}
|
||||
|
||||
const noteId = uuid.create();
|
||||
noteIdMap[item.id] = noteId;
|
||||
item.id = noteId;
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -247,7 +247,7 @@
|
||||
<tr>
|
||||
<td>Android</td>
|
||||
<td><a href='https://play.google.com/store/apps/details?id=net.cozic.joplin&utm_source=GitHub&utm_campaign=README&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="40px" src='https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/BadgeAndroid.png'/></a></td>
|
||||
<td>or <a href="https://github.com/laurent22/joplin-android/releases/download/android-v1.0.102/joplin-v1.0.102.apk">Download APK File</a></td>
|
||||
<td>or <a href="https://github.com/laurent22/joplin-android/releases/download/android-v1.0.103/joplin-v1.0.103.apk">Download APK File</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>iOS</td>
|
||||
@@ -366,9 +366,9 @@ $$
|
||||
<p><img src="https://raw.githubusercontent.com/laurent22/joplin/master/docs/images/Katex.png" style="max-width: 100%; max-height: 35em;"></p>
|
||||
<h2 id="checkboxes">Checkboxes</h2>
|
||||
<p>Checkboxes can be added like so:</p>
|
||||
<pre><code>-[ ] Milk
|
||||
-[ ] Rice
|
||||
-[ ] Eggs
|
||||
<pre><code>- [ ] Milk
|
||||
- [ ] Rice
|
||||
- [ ] Eggs
|
||||
</code></pre><p>The checkboxes can then be ticked in the mobile and desktop applications.</p>
|
||||
<h1 id="contributing">Contributing</h1>
|
||||
<p>Please see the guide for information on how to contribute to the development of Joplin: <a href="https://github.com/laurent22/joplin/blob/master/CONTRIBUTING.md">https://github.com/laurent22/joplin/blob/master/CONTRIBUTING.md</a></p>
|
||||
@@ -400,21 +400,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>82%</td>
|
||||
<td>81%</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="mailto:trbuhom@net.hr">trbuhom@net.hr</a></td>
|
||||
<td>Hrvoje Mandić <a href="mailto:trbuhom@net.hr">trbuhom@net.hr</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="mailto:git@strobeltobias.de">git@strobeltobias.de</a></td>
|
||||
<td>84%</td>
|
||||
<td>Tobias Strobel <a href="mailto:git@strobeltobias.de">git@strobeltobias.de</a></td>
|
||||
<td>83%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/gb.png" alt=""></td>
|
||||
@@ -427,8 +427,8 @@ $$
|
||||
<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="mailto:f@mrtn.es">f@mrtn.es</a></td>
|
||||
<td>94%</td>
|
||||
<td>Fernando Martín <a href="mailto:f@mrtn.es">f@mrtn.es</a></td>
|
||||
<td>93%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://raw.githubusercontent.com/stevenrskelton/flag-icon/master/png/16/country-4x3/fr.png" alt=""></td>
|
||||
@@ -462,14 +462,14 @@ $$
|
||||
<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="mailto:artyom.karlov@gmail.com">artyom.karlov@gmail.com</a></td>
|
||||
<td>86%</td>
|
||||
<td>Artyom Karlov <a href="mailto:artyom.karlov@gmail.com">artyom.karlov@gmail.com</a></td>
|
||||
<td>85%</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="mailto:RCJacH@outlook.com">RCJacH@outlook.com</a></td>
|
||||
<td>RCJacH <a href="mailto:RCJacH@outlook.com">RCJacH@outlook.com</a></td>
|
||||
<td>68%</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
Reference in New Issue
Block a user