From d9c85a7275953c14562aab3e0e8cc7f0546c8bfe Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Tue, 22 Aug 2017 19:57:35 +0200 Subject: [PATCH] Various changes --- CliClient/app/app.js | 2 +- CliClient/app/autocompletion.js | 34 ++++++++++++---- CliClient/app/autocompletion_template.txt | 3 +- CliClient/app/cli-utils.js | 16 ++++++++ CliClient/app/command-config.js | 9 +++-- CliClient/app/command-edit.js | 1 + CliClient/install.sh | 10 +---- CliClient/locales/en_GB.po | 24 ++++++++++-- CliClient/locales/fr_FR.po | 32 ++++++++++++--- CliClient/locales/joplin.pot | 24 ++++++++++-- CliClient/package.json | 5 ++- CliClient/package.json.md5 | 2 +- ReactNativeClient/android/app/build.gradle | 4 +- .../lib/components/note-body-viewer.js | 3 +- .../lib/components/side-menu-content.js | 6 ++- ReactNativeClient/lib/models/setting.js | 39 +++++++++++-------- ReactNativeClient/lib/registry.js | 2 +- 17 files changed, 157 insertions(+), 59 deletions(-) diff --git a/CliClient/app/app.js b/CliClient/app/app.js index 8ad7de95c..943cba2cb 100644 --- a/CliClient/app/app.js +++ b/CliClient/app/app.js @@ -402,7 +402,7 @@ class Application { if (this.autocompletion_.active) { if (this.autocompletion_.install) { try { - installAutocompletionFile(Setting.value('appName'), Setting.value('profileDir')); + await installAutocompletionFile(Setting.value('appName'), Setting.value('profileDir')); } catch (error) { if (error.code == 'shellNotSupported') { console.info(error.message); diff --git a/CliClient/app/autocompletion.js b/CliClient/app/autocompletion.js index b33d93d8e..7ef2bff08 100644 --- a/CliClient/app/autocompletion.js +++ b/CliClient/app/autocompletion.js @@ -8,21 +8,31 @@ import fs from 'fs-extra'; import os from 'os'; import yargParser from 'yargs-parser'; -function autocompletionFileContent(appName) { +function autocompletionFileContent(appName, alias) { let content = fs.readFileSync(__dirname + '/autocompletion_template.txt', 'utf8'); content = content.replace(/\|__APPNAME__\|/g, appName); + + if (!alias) alias = 'joplin_alias_support_is_disabled'; + content = content.replace(/\|__APPALIAS__\|/g, alias); + return content; } -function installAutocompletionFile(appName, profileDir) { +function autocompletionScriptPath(profileDir) { + return profileDir + '/autocompletion.sh'; +} + +async function installAutocompletionFile(appName, profileDir) { if (process.env.SHELL.indexOf('bash') < 0) { let error = new Error(_('Only Bash is currently supported for autocompletion.')); error.code = 'shellNotSupported'; throw error; } - const content = autocompletionFileContent(appName); - const filePath = profileDir + '/autocompletion.sh'; + const alias = await cliUtils.promptInput(_('Autocompletion can be made to work with an alias too (such as a one-letter command like "j").\nIf you would like to enable this, please type the alias now (leave it empty for no alias):')); + + const content = autocompletionFileContent(appName, alias); + const filePath = autocompletionScriptPath(profileDir); fs.writeFileSync(filePath, content); console.info(_('Created autocompletion script "%s".', filePath)); @@ -41,10 +51,18 @@ function installAutocompletionFile(appName, profileDir) { console.info(_('Added autocompletion to "%s".', bashProfilePath)); } - console.info(_('Sourcing "%s"...', filePath)); + if (alias) { + if (bashrcContent.indexOf('alias ' + alias + '=') >= 0) { + console.info(_('Alias is already set in "%s".', bashProfilePath)); + } else { + const l = 'alias ' + alias + '=' + appName; + bashrcContent += "\n" + l + "\n"; + fs.writeFileSync(bashProfilePath, bashrcContent); + console.info(_('Added alias to "%s".', bashProfilePath)); + } + } - const spawnSync = require('child_process').spawnSync; - spawnSync('source', [filePath]); + console.info(_("IMPORTANT: run the following command to initialise autocompletion in the current shell:\nsource '%s'", filePath)); } async function handleAutocompletion(autocompletion) { @@ -154,4 +172,4 @@ function filterList(list, currentWord) { return output; } -export { handleAutocompletion, installAutocompletionFile }; \ No newline at end of file +export { handleAutocompletion, installAutocompletionFile, autocompletionScriptPath }; \ No newline at end of file diff --git a/CliClient/app/autocompletion_template.txt b/CliClient/app/autocompletion_template.txt index 00f61e485..6ba3a59d4 100644 --- a/CliClient/app/autocompletion_template.txt +++ b/CliClient/app/autocompletion_template.txt @@ -40,4 +40,5 @@ _|__APPNAME__|_completion() { fi } -complete -o default -F _|__APPNAME__|_completion |__APPNAME__| \ No newline at end of file +complete -o default -F _|__APPNAME__|_completion |__APPNAME__| +complete -o default -F _|__APPNAME__|_completion |__APPALIAS__| \ No newline at end of file diff --git a/CliClient/app/cli-utils.js b/CliClient/app/cli-utils.js index 783c515b5..bf7dc6230 100644 --- a/CliClient/app/cli-utils.js +++ b/CliClient/app/cli-utils.js @@ -147,6 +147,22 @@ cliUtils.promptConfirm = function(message, answers = null) { }); } +cliUtils.promptInput = function(message) { + const readline = require('readline'); + + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }); + + return new Promise((resolve, reject) => { + rl.question(message + ' ', (answer) => { + rl.close(); + resolve(answer); + }); + }); +} + let redrawStarted_ = false; let redrawLastLog_ = null; let redrawLastUpdateTime_ = 0; diff --git a/CliClient/app/command-config.js b/CliClient/app/command-config.js index 0cfe7ba1f..1c9e0775c 100644 --- a/CliClient/app/command-config.js +++ b/CliClient/app/command-config.js @@ -15,24 +15,27 @@ class Command extends BaseCommand { options() { return [ - ['-v, --verbose', _('Also displays hidden config variables.')], + ['-v, --verbose', _('Also displays unset and hidden config variables.')], ]; } async action(args) { + const verbose = args.options.verbose; const renderKeyValue = (name) => { const value = Setting.value(name); if (Setting.isEnum(name)) { - return _('%s = %s (%s)', name, value, Setting.enumOptionLabel(name, value)); + return _('%s = %s (%s)', name, value, Setting.enumOptionsDoc(name)); } else { return _('%s = %s', name, value); } } if (!args.name && !args.value) { - let keys = args.options.verbose ? Setting.keys() : Setting.publicKeys(); + let keys = Setting.keys(!verbose, 'cli'); for (let i = 0; i < keys.length; i++) { + const value = Setting.value(keys[i]); + if (!verbose && !value) continue; this.log(renderKeyValue(keys[i])); } return; diff --git a/CliClient/app/command-edit.js b/CliClient/app/command-edit.js index d70e77541..c25d17d1d 100644 --- a/CliClient/app/command-edit.js +++ b/CliClient/app/command-edit.js @@ -76,6 +76,7 @@ class Command extends BaseCommand { updatedNote = await Note.unserializeForEdit(updatedNote); updatedNote.id = note.id; await Note.save(updatedNote); + process.stdout.write('.'); watchTimeout = null; }, 200); }); diff --git a/CliClient/install.sh b/CliClient/install.sh index 2952f52d8..e730ae2f1 100755 --- a/CliClient/install.sh +++ b/CliClient/install.sh @@ -3,11 +3,5 @@ set -e CLIENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" npm version patch -bash $CLIENT_DIR/build.sh -cp "$CLIENT_DIR/package.json" build/ -cp "$CLIENT_DIR/../ReactNativeClient/lib/package.json" build/lib -#cp "$CLIENT_DIR/app/main.sh" build/ -cd "$CLIENT_DIR/build" -sudo npm install -g --save -#sudo yarn global add -cd - \ No newline at end of file +$CLIENT_DIR/build.sh +sudo rsync -aP "$CLIENT_DIR/build/" "/usr/lib/node_modules/joplin/" \ No newline at end of file diff --git a/CliClient/locales/en_GB.po b/CliClient/locales/en_GB.po index 6c8f7e7c4..fbe27ed99 100644 --- a/CliClient/locales/en_GB.po +++ b/CliClient/locales/en_GB.po @@ -44,6 +44,13 @@ msgstr "" msgid "Only Bash is currently supported for autocompletion." msgstr "" +msgid "" +"Autocompletion can be made to work with an alias too (such as a one-letter " +"command like \"j\").\n" +"If you would like to enable this, please type the alias now (leave it empty " +"for no alias):" +msgstr "" + #, javascript-format msgid "Created autocompletion script \"%s\"." msgstr "" @@ -57,7 +64,18 @@ msgid "Added autocompletion to \"%s\"." msgstr "" #, javascript-format -msgid "Sourcing \"%s\"..." +msgid "Alias is already set in \"%s\"." +msgstr "" + +#, javascript-format +msgid "Added alias to \"%s\"." +msgstr "" + +#, javascript-format +msgid "" +"IMPORTANT: run the following command to initialise autocompletion in the " +"current shell:\n" +"source '%s'" msgstr "" #, javascript-format @@ -86,7 +104,7 @@ msgid "" "current configuration." msgstr "" -msgid "Also displays hidden config variables." +msgid "Also displays unset and hidden config variables." msgstr "" #, javascript-format @@ -418,7 +436,7 @@ msgid "Invalid option value: \"%s\". Possible values are: %s." msgstr "" #, javascript-format -msgid "%s (%s)" +msgid "%s: %s" msgstr "" msgid "Synchronisation target" diff --git a/CliClient/locales/fr_FR.po b/CliClient/locales/fr_FR.po index f5fb256bb..9515b39e0 100644 --- a/CliClient/locales/fr_FR.po +++ b/CliClient/locales/fr_FR.po @@ -46,6 +46,13 @@ msgstr "Quitter le logiciel." msgid "Only Bash is currently supported for autocompletion." msgstr "" +msgid "" +"Autocompletion can be made to work with an alias too (such as a one-letter " +"command like \"j\").\n" +"If you would like to enable this, please type the alias now (leave it empty " +"for no alias):" +msgstr "" + #, javascript-format msgid "Created autocompletion script \"%s\"." msgstr "" @@ -59,7 +66,18 @@ msgid "Added autocompletion to \"%s\"." msgstr "" #, javascript-format -msgid "Sourcing \"%s\"..." +msgid "Alias is already set in \"%s\"." +msgstr "" + +#, javascript-format +msgid "Added alias to \"%s\"." +msgstr "" + +#, javascript-format +msgid "" +"IMPORTANT: run the following command to initialise autocompletion in the " +"current shell:\n" +"source '%s'" msgstr "" #, javascript-format @@ -91,7 +109,8 @@ msgstr "" "fournie, la valeur de [nom] est affichée. Si ni le [nom] ni la [valeur] ne " "sont fournis, la configuration complète est affichée." -msgid "Also displays hidden config variables." +#, fuzzy +msgid "Also displays unset and hidden config variables." msgstr "Afficher également les variables cachées." #, javascript-format @@ -464,9 +483,9 @@ msgstr "Impossible de déplacer la note vers le carnet \"%s\"" msgid "Invalid option value: \"%s\". Possible values are: %s." msgstr "Option invalide: \"%s\". Les valeurs possibles sont : %s." -#, javascript-format -msgid "%s (%s)" -msgstr "%s (%s)" +#, fuzzy, javascript-format +msgid "%s: %s" +msgstr "%s: %d/%d" msgid "Synchronisation target" msgstr "Cible de la synchronisation" @@ -644,6 +663,9 @@ msgstr "" msgid "Welcome" msgstr "Bienvenue" +#~ msgid "%s (%s)" +#~ msgstr "%s (%s)" + #~ msgid "Last error: %s (stacktrace in log)." #~ msgstr "Dernière erreur : %s (Plus d'information dans le journal d'erreurs)" diff --git a/CliClient/locales/joplin.pot b/CliClient/locales/joplin.pot index 6c8f7e7c4..fbe27ed99 100644 --- a/CliClient/locales/joplin.pot +++ b/CliClient/locales/joplin.pot @@ -44,6 +44,13 @@ msgstr "" msgid "Only Bash is currently supported for autocompletion." msgstr "" +msgid "" +"Autocompletion can be made to work with an alias too (such as a one-letter " +"command like \"j\").\n" +"If you would like to enable this, please type the alias now (leave it empty " +"for no alias):" +msgstr "" + #, javascript-format msgid "Created autocompletion script \"%s\"." msgstr "" @@ -57,7 +64,18 @@ msgid "Added autocompletion to \"%s\"." msgstr "" #, javascript-format -msgid "Sourcing \"%s\"..." +msgid "Alias is already set in \"%s\"." +msgstr "" + +#, javascript-format +msgid "Added alias to \"%s\"." +msgstr "" + +#, javascript-format +msgid "" +"IMPORTANT: run the following command to initialise autocompletion in the " +"current shell:\n" +"source '%s'" msgstr "" #, javascript-format @@ -86,7 +104,7 @@ msgid "" "current configuration." msgstr "" -msgid "Also displays hidden config variables." +msgid "Also displays unset and hidden config variables." msgstr "" #, javascript-format @@ -418,7 +436,7 @@ msgid "Invalid option value: \"%s\". Possible values are: %s." msgstr "" #, javascript-format -msgid "%s (%s)" +msgid "%s: %s" msgstr "" msgid "Synchronisation target" diff --git a/CliClient/package.json b/CliClient/package.json index 356437d2a..1b5cb4101 100644 --- a/CliClient/package.json +++ b/CliClient/package.json @@ -7,7 +7,7 @@ "url": "https://github.com/laurent22/joplin" }, "url": "git://github.com/laurent22/joplin.git", - "version": "0.9.11", + "version": "0.9.16", "bin": { "joplin": "./main.js" }, @@ -57,6 +57,7 @@ "babelbuild": "babel app -d build", "build": "babel-changed app -d build --source-maps && babel-changed app/lib/models -d build/lib/models --source-maps && babel-changed app/lib/services -d build/lib/services --source-maps", "clean": "babel-changed --reset", - "test": "babel-changed tests -d tests-build --source-maps && jasmine" + "test": "babel-changed tests -d tests-build --source-maps && jasmine", + "postinstall": "joplin --autocompletion --ac-install" } } diff --git a/CliClient/package.json.md5 b/CliClient/package.json.md5 index 7a5b3ede8..d3387bab0 100644 --- a/CliClient/package.json.md5 +++ b/CliClient/package.json.md5 @@ -1 +1 @@ -7863f7005a6fd4ec83c3b2a8df8a5f60 \ No newline at end of file +320eb753be882e5509e873e2b5f624e3 \ No newline at end of file diff --git a/ReactNativeClient/android/app/build.gradle b/ReactNativeClient/android/app/build.gradle index 6ee8f16ad..99ae58d88 100644 --- a/ReactNativeClient/android/app/build.gradle +++ b/ReactNativeClient/android/app/build.gradle @@ -90,8 +90,8 @@ android { applicationId "net.cozic.joplin" minSdkVersion 16 targetSdkVersion 22 - versionCode 45 - versionName "0.9.32" + versionCode 46 + versionName "0.9.33" ndk { abiFilters "armeabi-v7a", "x86" } diff --git a/ReactNativeClient/lib/components/note-body-viewer.js b/ReactNativeClient/lib/components/note-body-viewer.js index 20dbf1a90..f45b17f13 100644 --- a/ReactNativeClient/lib/components/note-body-viewer.js +++ b/ReactNativeClient/lib/components/note-body-viewer.js @@ -180,9 +180,8 @@ class NoteBodyViewer extends Component { // the content is displayed. setTimeout(() => { if (!this.isMounted_) return; - this.setState({ webViewLoaded: true }); - }, 100); + }, 200); } render() { diff --git a/ReactNativeClient/lib/components/side-menu-content.js b/ReactNativeClient/lib/components/side-menu-content.js index f2d896c02..7e09a1fd9 100644 --- a/ReactNativeClient/lib/components/side-menu-content.js +++ b/ReactNativeClient/lib/components/side-menu-content.js @@ -195,9 +195,11 @@ class SideMenuContentComponent extends Component { } if (this.props.tags.length) { + let tags = this.props.tags.slice(); + tags.sort((a, b) => { return a.title < b.title ? -1 : +1; }); let tagItems = []; - for (let i = 0; i < this.props.tags.length; i++) { - const tag = this.props.tags[i]; + for (let i = 0; i < tags.length; i++) { + const tag = tags[i]; tagItems.push(this.tagItem(tag, this.props.selectedTagId == tag.id && this.props.notesParentType == 'Tag')); } diff --git a/ReactNativeClient/lib/models/setting.js b/ReactNativeClient/lib/models/setting.js index 58708c5c2..f60ea2068 100644 --- a/ReactNativeClient/lib/models/setting.js +++ b/ReactNativeClient/lib/models/setting.js @@ -20,27 +20,32 @@ class Setting extends BaseModel { return output; } - static keys() { - if (this.keys_) return this.keys_; - this.keys_ = []; - for (let n in this.metadata_) { - if (!this.metadata_.hasOwnProperty(n)) continue; - this.keys_.push(n); + static keys(publicOnly = false, appType = null) { + if (!this.keys_) { + this.keys_ = []; + for (let n in this.metadata_) { + if (!this.metadata_.hasOwnProperty(n)) continue; + this.keys_.push(n); + } + this.keys_.sort(); } - return this.keys_; - } - static publicKeys() { - let output = []; - for (let n in this.metadata_) { - if (!this.metadata_.hasOwnProperty(n)) continue; - if (this.metadata_[n].public) output.push(n); + if (appType || publicOnly) { + let output = []; + for (let i = 0; i < this.keys_.length; i++) { + const md = this.settingMetadata(this.keys_[i]); + if (publicOnly && !md.public) continue; + if (appType && md.appTypes && md.appTypes.indexOf(appType) < 0) continue; + output.push(md.key); + } + return output; + } else { + return this.keys_; } - return output; } static isPublic(key) { - return this.publicKeys().indexOf(key) >= 0; + return this.keys(true).indexOf(key) >= 0; } static load() { @@ -205,7 +210,7 @@ class Setting extends BaseModel { let output = []; for (let n in options) { if (!options.hasOwnProperty(n)) continue; - output.push(_('%s (%s)', n, options[n])); + output.push(_('%s: %s', n, options[n])); } return output.join(', '); } @@ -330,7 +335,7 @@ Setting.metadata_ = { })}, 'uncompletedTodosOnTop': { value: true, type: Setting.TYPE_BOOL, public: true, label: () => _('Show uncompleted todos on top of the lists') }, 'trackLocation': { value: true, type: Setting.TYPE_BOOL, public: true, label: () => _('Save location with notes') }, - 'sync.interval': { value: 300, type: Setting.TYPE_INT, isEnum: true, public: true, label: () => _('Synchronisation interval'), options: () => { + 'sync.interval': { value: 300, type: Setting.TYPE_INT, isEnum: true, public: true, appTypes: ['mobile'], label: () => _('Synchronisation interval'), options: () => { return { 0: _('Disabled'), 300: _('%d minutes', 5), diff --git a/ReactNativeClient/lib/registry.js b/ReactNativeClient/lib/registry.js index 3cdc3f252..1c019760f 100644 --- a/ReactNativeClient/lib/registry.js +++ b/ReactNativeClient/lib/registry.js @@ -18,7 +18,7 @@ reg.initSynchronizerStates_ = {}; reg.logger = () => { if (!reg.logger_) { - console.warn('Calling logger before it is initialized'); + //console.warn('Calling logger before it is initialized'); return new Logger(); }