You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-11-29 22:48:10 +02:00
Various improvements
This commit is contained in:
40
CliClient/app/command-done.js
Normal file
40
CliClient/app/command-done.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { BaseCommand } from './base-command.js';
|
||||||
|
import { app } from './app.js';
|
||||||
|
import { _ } from 'lib/locale.js';
|
||||||
|
import { BaseModel } from 'lib/base-model.js';
|
||||||
|
import { Folder } from 'lib/models/folder.js';
|
||||||
|
import { Note } from 'lib/models/note.js';
|
||||||
|
import { time } from 'lib/time-utils.js';
|
||||||
|
|
||||||
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
return 'done <note>';
|
||||||
|
}
|
||||||
|
|
||||||
|
description() {
|
||||||
|
return _('Marks a todo as done.');
|
||||||
|
}
|
||||||
|
|
||||||
|
static async handleAction(args, isCompleted) {
|
||||||
|
const note = await app().loadItem(BaseModel.TYPE_NOTE, args.note);
|
||||||
|
if (!note) throw new Error(_('Cannot find "%s".', args.note));
|
||||||
|
if (!note.is_todo) throw new Error(_('Note is not a todo: "%s"', args.note));
|
||||||
|
|
||||||
|
const todoCompleted = !!note.todo_completed;
|
||||||
|
|
||||||
|
if (isCompleted === todoCompleted) return;
|
||||||
|
|
||||||
|
await Note.save({
|
||||||
|
id: note.id,
|
||||||
|
todo_completed: isCompleted ? time.unixMs() : 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async action(args) {
|
||||||
|
Command.handleAction(args, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Command;
|
||||||
27
CliClient/app/command-undone.js
Normal file
27
CliClient/app/command-undone.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { BaseCommand } from './base-command.js';
|
||||||
|
import { app } from './app.js';
|
||||||
|
import { _ } from 'lib/locale.js';
|
||||||
|
import { BaseModel } from 'lib/base-model.js';
|
||||||
|
import { Folder } from 'lib/models/folder.js';
|
||||||
|
import { Note } from 'lib/models/note.js';
|
||||||
|
import { time } from 'lib/time-utils.js';
|
||||||
|
|
||||||
|
const CommandDone = require('./command-done.js');
|
||||||
|
|
||||||
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
return 'undone <note>';
|
||||||
|
}
|
||||||
|
|
||||||
|
description() {
|
||||||
|
return _('Marks a todo as non-completed.');
|
||||||
|
}
|
||||||
|
|
||||||
|
async action(args) {
|
||||||
|
CommandDone.handleAction(args, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Command;
|
||||||
@@ -102,6 +102,13 @@ msgid ""
|
|||||||
"specified the note is duplicated in the current notebook."
|
"specified the note is duplicated in the current notebook."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Marks a todo as done."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "Note is not a todo: \"%s\""
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Edit note."
|
msgid "Edit note."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,6 +298,9 @@ msgid ""
|
|||||||
"the todo back to a regular note."
|
"the todo back to a regular note."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Marks a todo as non-completed."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Switches to [notebook] - all further operations will happen within this "
|
"Switches to [notebook] - all further operations will happen within this "
|
||||||
"notebook."
|
"notebook."
|
||||||
@@ -367,10 +377,6 @@ msgstr ""
|
|||||||
msgid "State: \"%s\"."
|
msgid "State: \"%s\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
|
||||||
msgid "Last error: %s (stacktrace in log)."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -393,6 +399,9 @@ msgstr ""
|
|||||||
msgid "Notebooks cannot be named \"%s\", which is a reserved title."
|
msgid "Notebooks cannot be named \"%s\", which is a reserved title."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Untitled"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "This note does not have geolocation information."
|
msgid "This note does not have geolocation information."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -532,9 +541,6 @@ msgstr ""
|
|||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Untitled"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Delete note?"
|
msgid "Delete note?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -110,6 +110,13 @@ msgstr ""
|
|||||||
"Copie les notes correspondant à [nom] vers [carnet]. Si aucun carnet n'est "
|
"Copie les notes correspondant à [nom] vers [carnet]. Si aucun carnet n'est "
|
||||||
"spécifié, la note est dupliqué sur place."
|
"spécifié, la note est dupliqué sur place."
|
||||||
|
|
||||||
|
msgid "Marks a todo as done."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "Note is not a todo: \"%s\""
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Edit note."
|
msgid "Edit note."
|
||||||
msgstr "Editer la note."
|
msgstr "Editer la note."
|
||||||
|
|
||||||
@@ -333,6 +340,9 @@ msgstr ""
|
|||||||
"terminé (Si la cible est une note, elle sera convertie en tâche). Utilisez "
|
"terminé (Si la cible est une note, elle sera convertie en tâche). Utilisez "
|
||||||
"\"clear\" pour convertir la tâche en note."
|
"\"clear\" pour convertir la tâche en note."
|
||||||
|
|
||||||
|
msgid "Marks a todo as non-completed."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Switches to [notebook] - all further operations will happen within this "
|
"Switches to [notebook] - all further operations will happen within this "
|
||||||
"notebook."
|
"notebook."
|
||||||
@@ -414,10 +424,6 @@ msgstr "Objets distants supprimés : %d."
|
|||||||
msgid "State: \"%s\"."
|
msgid "State: \"%s\"."
|
||||||
msgstr "Etat : %s."
|
msgstr "Etat : %s."
|
||||||
|
|
||||||
#, javascript-format
|
|
||||||
msgid "Last error: %s (stacktrace in log)."
|
|
||||||
msgstr "Dernière erreur : %s (Plus d'information dans le journal d'erreurs)"
|
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
msgstr "Annulation..."
|
msgstr "Annulation..."
|
||||||
|
|
||||||
@@ -440,6 +446,9 @@ msgstr "Un carnet avec ce titre existe déjà : \"%s\""
|
|||||||
msgid "Notebooks cannot be named \"%s\", which is a reserved title."
|
msgid "Notebooks cannot be named \"%s\", which is a reserved title."
|
||||||
msgstr "Les carnets ne peuvent être nommés \"%s\" car c'est un nom réservé."
|
msgstr "Les carnets ne peuvent être nommés \"%s\" car c'est un nom réservé."
|
||||||
|
|
||||||
|
msgid "Untitled"
|
||||||
|
msgstr "Sans titre"
|
||||||
|
|
||||||
msgid "This note does not have geolocation information."
|
msgid "This note does not have geolocation information."
|
||||||
msgstr "Cette note n'a pas d'information d'emplacement."
|
msgstr "Cette note n'a pas d'information d'emplacement."
|
||||||
|
|
||||||
@@ -581,9 +590,6 @@ msgstr "Editer le carnet"
|
|||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr "Rafraîchir"
|
msgstr "Rafraîchir"
|
||||||
|
|
||||||
msgid "Untitled"
|
|
||||||
msgstr "Sans titre"
|
|
||||||
|
|
||||||
msgid "Delete note?"
|
msgid "Delete note?"
|
||||||
msgstr "Supprimer la note ?"
|
msgstr "Supprimer la note ?"
|
||||||
|
|
||||||
@@ -638,6 +644,9 @@ msgstr ""
|
|||||||
msgid "Welcome"
|
msgid "Welcome"
|
||||||
msgstr "Bienvenue"
|
msgstr "Bienvenue"
|
||||||
|
|
||||||
|
#~ msgid "Last error: %s (stacktrace in log)."
|
||||||
|
#~ msgstr "Dernière erreur : %s (Plus d'information dans le journal d'erreurs)"
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#~ msgid "Cancelling command..."
|
#~ msgid "Cancelling command..."
|
||||||
#~ msgstr "Annulation..."
|
#~ msgstr "Annulation..."
|
||||||
|
|||||||
@@ -102,6 +102,13 @@ msgid ""
|
|||||||
"specified the note is duplicated in the current notebook."
|
"specified the note is duplicated in the current notebook."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Marks a todo as done."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#, javascript-format
|
||||||
|
msgid "Note is not a todo: \"%s\""
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Edit note."
|
msgid "Edit note."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -291,6 +298,9 @@ msgid ""
|
|||||||
"the todo back to a regular note."
|
"the todo back to a regular note."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Marks a todo as non-completed."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Switches to [notebook] - all further operations will happen within this "
|
"Switches to [notebook] - all further operations will happen within this "
|
||||||
"notebook."
|
"notebook."
|
||||||
@@ -367,10 +377,6 @@ msgstr ""
|
|||||||
msgid "State: \"%s\"."
|
msgid "State: \"%s\"."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#, javascript-format
|
|
||||||
msgid "Last error: %s (stacktrace in log)."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Cancelling..."
|
msgid "Cancelling..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -393,6 +399,9 @@ msgstr ""
|
|||||||
msgid "Notebooks cannot be named \"%s\", which is a reserved title."
|
msgid "Notebooks cannot be named \"%s\", which is a reserved title."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Untitled"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "This note does not have geolocation information."
|
msgid "This note does not have geolocation information."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -532,9 +541,6 @@ msgstr ""
|
|||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Untitled"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid "Delete note?"
|
msgid "Delete note?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,10 @@ class NoteBodyViewer extends Component {
|
|||||||
super();
|
super();
|
||||||
this.state = {
|
this.state = {
|
||||||
resources: {},
|
resources: {},
|
||||||
|
webViewLoaded: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isMounted_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadResource(id) {
|
async loadResource(id) {
|
||||||
@@ -25,6 +28,14 @@ class NoteBodyViewer extends Component {
|
|||||||
this.setState({ resources: newResources });
|
this.setState({ resources: newResources });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
this.isMounted_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.isMounted_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
toggleTickAt(body, index) {
|
toggleTickAt(body, index) {
|
||||||
let counter = -1;
|
let counter = -1;
|
||||||
while (body.indexOf('- [ ]') >= 0 || body.indexOf('- [X]') >= 0) {
|
while (body.indexOf('- [ ]') >= 0 || body.indexOf('- [X]') >= 0) {
|
||||||
@@ -162,20 +173,36 @@ class NoteBodyViewer extends Component {
|
|||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onLoadEnd() {
|
||||||
|
if (this.state.webViewLoaded) return;
|
||||||
|
|
||||||
|
// Need to display after a delay to avoid a white flash before
|
||||||
|
// the content is displayed.
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this.isMounted_) return;
|
||||||
|
|
||||||
|
this.setState({ webViewLoaded: true });
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const note = this.props.note;
|
const note = this.props.note;
|
||||||
const style = this.props.style;
|
const style = this.props.style;
|
||||||
const onCheckboxChange = this.props.onCheckboxChange;
|
const onCheckboxChange = this.props.onCheckboxChange;
|
||||||
|
const html = this.markdownToHtml(note ? note.body : '', this.props.webViewStyle);
|
||||||
|
|
||||||
|
let webViewStyle = {}
|
||||||
|
if (!this.state.webViewLoaded) webViewStyle.display = 'none';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={style}>
|
<View style={style}>
|
||||||
<WebView
|
<WebView
|
||||||
source={{ html: this.markdownToHtml(note ? note.body : '', this.props.webViewStyle) }}
|
style={webViewStyle}
|
||||||
|
source={{ html: html }}
|
||||||
|
onLoadEnd={() => this.onLoadEnd()}
|
||||||
onMessage={(event) => {
|
onMessage={(event) => {
|
||||||
let msg = event.nativeEvent.data;
|
let msg = event.nativeEvent.data;
|
||||||
|
|
||||||
//reg.logger().info('postMessage received: ' + msg);
|
|
||||||
|
|
||||||
if (msg.indexOf('checkboxclick:') === 0) {
|
if (msg.indexOf('checkboxclick:') === 0) {
|
||||||
msg = msg.split(':');
|
msg = msg.split(':');
|
||||||
let index = Number(msg[msg.length - 1]);
|
let index = Number(msg[msg.length - 1]);
|
||||||
|
|||||||
@@ -196,7 +196,11 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let isNew = !note.id;
|
let isNew = !note.id;
|
||||||
if (!note.title) note.title = _('Untitled');
|
|
||||||
|
if (isNew && !note.title) {
|
||||||
|
note.title = Note.defaultTitle(note);
|
||||||
|
}
|
||||||
|
|
||||||
note = await Note.save(note);
|
note = await Note.save(note);
|
||||||
this.setState({
|
this.setState({
|
||||||
lastSavedNote: Object.assign({}, note),
|
lastSavedNote: Object.assign({}, note),
|
||||||
|
|||||||
@@ -41,6 +41,17 @@ class Note extends BaseItem {
|
|||||||
return super.serialize(note, 'note', fieldNames);
|
return super.serialize(note, 'note', fieldNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static defaultTitle(note) {
|
||||||
|
if (note.title && note.title.length) return note.title;
|
||||||
|
|
||||||
|
if (note.body && note.body.length) {
|
||||||
|
const lines = note.body.trim().split("\n");
|
||||||
|
return lines[0].trim().substr(0, 80).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _('Untitled');
|
||||||
|
}
|
||||||
|
|
||||||
static geolocationUrl(note) {
|
static geolocationUrl(note) {
|
||||||
if (!('latitude' in note) || !('longitude' in note)) throw new Error('Latitude or longitude is missing');
|
if (!('latitude' in note) || !('longitude' in note)) throw new Error('Latitude or longitude is missing');
|
||||||
if (!Number(note.latitude) && !Number(note.longitude)) throw new Error(_('This note does not have geolocation information.'));
|
if (!Number(note.latitude) && !Number(note.longitude)) throw new Error(_('This note does not have geolocation information.'));
|
||||||
|
|||||||
Reference in New Issue
Block a user