1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-09-16 08:56:40 +02:00

Added command attach and support for non-gui mode

This commit is contained in:
Laurent Cozic
2017-10-19 23:02:13 +01:00
parent 1845a0105c
commit ad1c0f3958
17 changed files with 517 additions and 99 deletions

View File

@@ -78,6 +78,10 @@ class AppGui {
await this.renderer_.renderRoot();
}
prompt(initialText = '', promptString = ':') {
return this.widget('statusBar').prompt(initialText, promptString);
}
buildUi() {
this.rootWidget_ = new ReduxRootWidget(this.store_);
this.rootWidget_.name = 'root';
@@ -343,6 +347,8 @@ class AppGui {
cmd = cmd.trim();
if (!cmd.length) return;
this.logger().info('Got command: ' + cmd);
let note = this.widget('noteList').currentItem;
let folder = this.widget('folderList').currentItem;
let args = cliUtils.splitCommandString(cmd);

View File

@@ -269,13 +269,21 @@ class Application {
return this.eventEmitter_.on(eventName, callback);
}
stdout(text) {
return this.gui().stdout(text);
}
setupCommand(cmd) {
cmd.setStdout((text) => {
this.gui().stdout(text);
return this.stdout(text);
});
cmd.setDispatcher((action) => {
return this.store().dispatch(action);
if (this.store()) {
return this.store().dispatch(action);
} else {
return (action) => {};
}
});
cmd.setPrompt(async (message, options) => {
@@ -283,7 +291,7 @@ class Application {
message += ' (' + options.answers.join('/') + ')';
}
const answer = await this.gui().widget('statusBar').prompt('', message + ' ');
const answer = await this.gui().prompt('', message + ' ');
if (options.type === 'boolean') {
if (answer === null) return false;
@@ -376,6 +384,16 @@ class Application {
return this.commands_[name];
}
dummyGui() {
return {
prompt: (initialText = '', promptString = '') => { return cliUtils.prompt(initialText, promptString); },
showConsole: () => {},
maximizeConsole: () => {},
stdout: (text) => { console.info(text); },
fullScreen: (b=true) => {},
};
}
async execCommand(argv) {
if (!argv.length) return this.execCommand(['help']);
reg.logger().info('execCommand()', argv);
@@ -499,9 +517,9 @@ class Application {
reg.setDb(this.database_);
BaseModel.db_ = this.database_;
this.store_ = createStore(reducer, applyMiddleware(this.generalMiddleware()));
BaseModel.dispatch = this.store().dispatch;
FoldersScreenUtils.dispatch = this.store().dispatch;
// this.store_ = createStore(reducer, applyMiddleware(this.generalMiddleware()));
// BaseModel.dispatch = this.store().dispatch;
// FoldersScreenUtils.dispatch = this.store().dispatch;
await Setting.load();
@@ -523,55 +541,37 @@ class Application {
if (!this.currentFolder_) this.currentFolder_ = await Folder.defaultFolder();
Setting.setValue('activeFolderId', this.currentFolder_ ? this.currentFolder_.id : '');
const AppGui = require('./app-gui.js');
this.gui_ = new AppGui(this, this.store());
this.gui_.setLogger(this.logger_);
await this.gui_.start();
// If we have some arguments left at this point, it's a command
// so execute it.
if (argv.length) {
this.gui_ = this.dummyGui();
await FoldersScreenUtils.refreshFolders();
try {
await this.execCommand(argv);
} catch (error) {
if (this.showStackTraces_) {
console.info(error);
} else {
console.info(error.message);
}
}
} else { // Otherwise open the GUI
this.store_ = createStore(reducer, applyMiddleware(this.generalMiddleware()));
BaseModel.dispatch = this.store().dispatch;
FoldersScreenUtils.dispatch = this.store().dispatch;
this.store().dispatch({
type: 'FOLDERS_SELECT',
folderId: Setting.value('activeFolderId'),
});
const AppGui = require('./app-gui.js');
this.gui_ = new AppGui(this, this.store());
this.gui_.setLogger(this.logger_);
await this.gui_.start();
// if (this.autocompletion_.active) {
// if (this.autocompletion_.install) {
// try {
// await installAutocompletionFile(Setting.value('appName'), Setting.value('profileDir'));
// } catch (error) {
// if (error.code == 'shellNotSupported') {
// console.info(error.message);
// return;
// }
// throw error;
// }
// } else {
// let items = await handleAutocompletion(this.autocompletion_);
// if (!items.length) return;
// for (let i = 0; i < items.length; i++) {
// items[i] = items[i].replace(/ /g, '\\ ');
// items[i] = items[i].replace(/'/g, "\\'");
// items[i] = items[i].replace(/:/g, "\\:");
// items[i] = items[i].replace(/\(/g, '\\(');
// items[i] = items[i].replace(/\)/g, '\\)');
// }
// console.info(items.join("\n"));
// }
// return;
// }
// try {
// await this.execCommand(argv);
// } catch (error) {
// if (this.showStackTraces_) {
// console.info(error);
// } else {
// console.info(error.message);
// }
// }
await FoldersScreenUtils.refreshFolders();
this.store().dispatch({
type: 'FOLDERS_SELECT',
folderId: Setting.value('activeFolderId'),
});
}
}
}

View File

@@ -209,6 +209,25 @@ cliUtils.promptInput = function(message) {
});
}
// Note: initialText is there to have the same signature as statusBar.prompt() so that
// it can be a drop-in replacement, however initialText is not used (and cannot be
// with readline.question?).
cliUtils.prompt = function(initialText = '', promptString = ':') {
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
return new Promise((resolve, reject) => {
rl.question(promptString, (answer) => {
rl.close();
resolve(answer);
});
});
}
let redrawStarted_ = false;
let redrawLastLog_ = null;
let redrawLastUpdateTime_ = 0;

View File

@@ -0,0 +1,72 @@
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 { Resource } from 'lib/models/resource.js';
import { uuid } from 'lib/uuid.js';
import { filename } from 'lib/path-utils.js';
const fs = require('fs-extra');
const mime = require('mime/lite');
const sharp = require('sharp');
class Command extends BaseCommand {
usage() {
return 'attach <note> <file>';
}
description() {
return _('Attaches the given file to the note.');
}
resizeImage_(filePath, targetPath) {
return new Promise((resolve, reject) => {
sharp(filePath)
.resize(Resource.IMAGE_MAX_DIMENSION, Resource.IMAGE_MAX_DIMENSION)
.max()
.withoutEnlargement()
.toFile(targetPath, (err, info) => {
if (err) {
reject(err);
} else {
resolve(info);
}
});
});
}
async action(args) {
let title = args['note'];
let note = await app().loadItem(BaseModel.TYPE_NOTE, title, { parent: app().currentFolder() });
if (!note) throw new Error(_('Cannot find "%s".', title));
const localFilePath = args['file'];
if (!(await fs.pathExists(localFilePath))) throw new Error(_('Cannot access %s', localFilePath));
let resource = Resource.new();
resource.id = uuid.create();
resource.mime = mime.getType(localFilePath);
resource.title = filename(localFilePath);
let targetPath = Resource.fullPath(resource);
if (resource.mime == 'image/jpeg' || resource.mime == 'image/jpg' || resource.mime == 'image/png') {
const result = await this.resizeImage_(localFilePath, targetPath);
this.logger().info(result);
} else {
await fs.copy(localFilePath, targetPath, { overwrite: true });
}
await Resource.save(resource, { isNew: true });
note.body += "\n" + Resource.markdownTag(resource);
await Note.save(note);
}
}
module.exports = Command;

View File

@@ -3,6 +3,7 @@ require('babel-plugin-transform-runtime');
import fs from 'fs-extra';
import { wrap } from 'lib/string-utils.js';
import { Setting } from 'lib/models/setting.js';
import { fileExtension, basename, dirname } from 'lib/path-utils.js';
import { _, setLocale, languageCode } from 'lib/locale.js';
@@ -10,14 +11,7 @@ const rootDir = dirname(dirname(__dirname));
const MAX_WIDTH = 78;
const INDENT = ' ';
// function wrap(text, indent, width) {
// return wrap_(text, {
// width: width - indent.length,
// indent: indent,
// });
// }
function renderOptions(options, baseIndent, width) {
function renderTwoColumnData(options, baseIndent, width) {
let output = [];
const optionColWidth = getOptionColWidth(options);
@@ -45,12 +39,57 @@ function renderCommandHelp(cmd, width = null) {
output.push('');
output.push(wrap(cmd.description(), baseIndent + INDENT, width));
const optionString = renderOptions(cmd.options(), baseIndent, width);
const optionString = renderTwoColumnData(cmd.options(), baseIndent, width);
if (optionString) {
output.push('');
output.push(optionString);
}
if (cmd.name() === 'config') {
const renderMetadata = (md) => {
let desc = [];
if (md.label) {
let label = md.label();
if (label.length && label[label.length - 1] !== '.') label += '.';
desc.push(label);
}
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)')));
let defaultString = null;
if ('value' in md) {
if (md.type === Setting.TYPE_STRING) {
defaultString = md.value ? '"' + md.value + '"' : null;
} else if (md.type === Setting.TYPE_INT) {
defaultString = (md.value ? md.value : 0).toString();
} else if (md.type === Setting.TYPE_BOOL) {
defaultString = (md.value === true ? 'true' : 'false');
}
}
if (defaultString !== null) desc.push(_('Default: %s', defaultString));
return [md.key, desc.join('\n')];
};
output.push('');
output.push(_('Possible keys/values:'));
output.push('');
let keysValues = [];
const keys = Setting.keys(true, 'cli');
for (let i = 0; i < keys.length; i++) {
const md = Setting.settingMetadata(keys[i]);
if (!md.label) continue;
keysValues.push(renderMetadata(md));
}
output.push(renderTwoColumnData(keysValues, baseIndent, width));
}
return output.join("\n");
}

View File

@@ -8,7 +8,7 @@ mkdir -p "$ROOT_DIR/build"
rm -f "$ROOT_DIR/app/lib"
ln -s "$ROOT_DIR/../ReactNativeClient/lib" "$ROOT_DIR/app"
npm run build
npm run build || exit 1
# Files under app/gui are in ES6 already but I cannot get Babel
# to ignore them, so copy them back to the build directory.

View File

@@ -139,16 +139,23 @@ msgstr ""
msgid "Invalid answer: %s"
msgstr ""
msgid "Displays the given note."
msgstr ""
msgid "Displays the complete information about note."
msgid "Attaches the given file to the note."
msgstr ""
#, javascript-format
msgid "Cannot find \"%s\"."
msgstr ""
#, javascript-format
msgid "Cannot access %s"
msgstr ""
msgid "Displays the given note."
msgstr ""
msgid "Displays the complete information about note."
msgstr ""
msgid ""
"Gets or sets a config value. If [value] is not provided, it will show the "
"value of [name]. If neither [name] nor [value] is provided, it will list the "
@@ -403,6 +410,24 @@ msgstr ""
msgid "%s %s (%s)"
msgstr ""
msgid "Enum"
msgstr ""
#, javascript-format
msgid "Type: %s."
msgstr ""
#, javascript-format
msgid "Possible values: %s."
msgstr ""
#, javascript-format
msgid "Default: %s"
msgstr ""
msgid "Possible keys/values:"
msgstr ""
msgid "Fatal error:"
msgstr ""
@@ -516,6 +541,11 @@ msgstr ""
msgid "OneDrive"
msgstr ""
msgid ""
"The editor that will be used to open a note. If none is provided it will try "
"to auto-detect the default editor."
msgstr ""
msgid "Language"
msgstr ""

View File

@@ -149,16 +149,24 @@ msgstr ""
msgid "Invalid answer: %s"
msgstr "Commande invalide : \"%s\""
#, fuzzy
msgid "Attaches the given file to the note."
msgstr "Chercher le motif <pattern> dans toutes les notes."
#, javascript-format
msgid "Cannot find \"%s\"."
msgstr "Impossible de trouver \"%s\"."
#, fuzzy, javascript-format
msgid "Cannot access %s"
msgstr "Impossible de trouver \"%s\"."
msgid "Displays the given note."
msgstr "Affiche la note."
msgid "Displays the complete information about note."
msgstr "Affiche tous les détails de la note."
#, javascript-format
msgid "Cannot find \"%s\"."
msgstr "Impossible de trouver \"%s\"."
msgid ""
"Gets or sets a config value. If [value] is not provided, it will show the "
"value of [name]. If neither [name] nor [value] is provided, it will list the "
@@ -457,6 +465,24 @@ msgstr "Affiche les informations de version"
msgid "%s %s (%s)"
msgstr "%s %s (%s)"
msgid "Enum"
msgstr ""
#, javascript-format
msgid "Type: %s."
msgstr ""
#, javascript-format
msgid "Possible values: %s."
msgstr ""
#, javascript-format
msgid "Default: %s"
msgstr ""
msgid "Possible keys/values:"
msgstr ""
msgid "Fatal error:"
msgstr "Erreur fatale :"
@@ -574,6 +600,11 @@ msgstr "Système de fichier"
msgid "OneDrive"
msgstr "OneDrive"
msgid ""
"The editor that will be used to open a note. If none is provided it will try "
"to auto-detect the default editor."
msgstr ""
msgid "Language"
msgstr "Langue"
@@ -755,6 +786,9 @@ msgstr ""
msgid "Welcome"
msgstr "Bienvenue"
#~ msgid "%s (%s)"
#~ msgstr "%s (%s)"
#, fuzzy
#~ msgid "Show/Hide the console"
#~ msgstr "Quitter le logiciel."
@@ -774,9 +808,6 @@ msgstr "Bienvenue"
#~ msgid "Confirm"
#~ msgstr "Conflits"
#~ 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)"

View File

@@ -139,16 +139,23 @@ msgstr ""
msgid "Invalid answer: %s"
msgstr ""
msgid "Displays the given note."
msgstr ""
msgid "Displays the complete information about note."
msgid "Attaches the given file to the note."
msgstr ""
#, javascript-format
msgid "Cannot find \"%s\"."
msgstr ""
#, javascript-format
msgid "Cannot access %s"
msgstr ""
msgid "Displays the given note."
msgstr ""
msgid "Displays the complete information about note."
msgstr ""
msgid ""
"Gets or sets a config value. If [value] is not provided, it will show the "
"value of [name]. If neither [name] nor [value] is provided, it will list the "
@@ -403,6 +410,24 @@ msgstr ""
msgid "%s %s (%s)"
msgstr ""
msgid "Enum"
msgstr ""
#, javascript-format
msgid "Type: %s."
msgstr ""
#, javascript-format
msgid "Possible values: %s."
msgstr ""
#, javascript-format
msgid "Default: %s"
msgstr ""
msgid "Possible keys/values:"
msgstr ""
msgid "Fatal error:"
msgstr ""
@@ -516,6 +541,11 @@ msgstr ""
msgid "OneDrive"
msgstr ""
msgid ""
"The editor that will be used to open a note. If none is provided it will try "
"to auto-detect the default editor."
msgstr ""
msgid "Language"
msgstr ""

View File

@@ -7,7 +7,7 @@
"url": "https://github.com/laurent22/joplin"
},
"url": "git://github.com/laurent22/joplin.git",
"version": "0.10.38",
"version": "0.10.42",
"bin": {
"joplin": "./main.js"
},
@@ -22,6 +22,7 @@
"levenshtein": "^1.0.5",
"lodash": "^4.17.4",
"md5": "^2.2.1",
"mime": "^2.0.3",
"moment": "^2.18.1",
"node-fetch": "^1.7.1",
"node-persist": "^2.1.0",
@@ -32,6 +33,7 @@
"redux": "^3.7.2",
"sax": "^1.2.2",
"server-destroy": "^1.0.1",
"sharp": "^0.18.4",
"source-map-support": "^0.4.15",
"sprintf-js": "^1.1.1",
"sqlite3": "^3.1.8",

View File

@@ -1 +1 @@
460c7642ca80c76758df33c7811fabec
d781c96c28a1da5497cd02dc4fc4691b

View File

@@ -2,6 +2,7 @@
set -e
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
yarn upgrade
npm version patch
$SCRIPT_DIR/update-package-md5.sh
touch "$SCRIPT_DIR/app/main.js"

View File

@@ -600,8 +600,8 @@ babel-polyfill@^6.1.4, babel-polyfill@^6.26.0:
regenerator-runtime "^0.10.5"
babel-preset-env@^1.5.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.0.tgz#2de1c782a780a0a5d605d199c957596da43c44e4"
version "1.6.1"
resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48"
dependencies:
babel-plugin-check-es2015-constants "^6.22.0"
babel-plugin-syntax-trailing-function-commas "^6.22.0"
@@ -812,6 +812,15 @@ caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
caw@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/caw/-/caw-2.0.1.tgz#6c3ca071fc194720883c2dc5da9b074bfc7e9e95"
dependencies:
get-proxy "^2.0.0"
isurl "^1.0.0-alpha5"
tunnel-agent "^0.6.0"
url-to-options "^1.0.1"
chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
@@ -849,6 +858,10 @@ chokidar@^1.6.1:
optionalDependencies:
fsevents "^1.0.0"
chownr@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181"
circular-json@^0.3.1:
version "0.3.3"
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
@@ -861,16 +874,30 @@ code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
color-convert@^1.9.0:
color-convert@^1.8.2, color-convert@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a"
dependencies:
color-name "^1.1.1"
color-name@^1.1.1:
color-name@^1.0.0, color-name@^1.1.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
color-string@^1.4.0:
version "1.5.2"
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.2.tgz#26e45814bc3c9a7cbd6751648a41434514a773a9"
dependencies:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/color/-/color-2.0.0.tgz#e0c9972d1e969857004b101eaa55ceab5961d67d"
dependencies:
color-convert "^1.8.2"
color-string "^1.4.0"
combined-stream@^1.0.5, combined-stream@~1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009"
@@ -885,6 +912,13 @@ concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
config-chain@^1.1.11:
version "1.1.11"
resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2"
dependencies:
ini "^1.3.4"
proto-list "~1.2.1"
console-control-strings@^1.0.0, console-control-strings@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
@@ -943,6 +977,12 @@ debug@^2.2.0, debug@^2.6.8, debug@^2.6.9:
dependencies:
ms "2.0.0"
decompress-response@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
dependencies:
mimic-response "^1.0.0"
deep-extend@~0.4.0:
version "0.4.2"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
@@ -977,6 +1017,10 @@ detect-indent@^4.0.0:
dependencies:
repeating "^2.0.0"
detect-libc@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-0.2.0.tgz#47fdf567348a17ec25fcbf0b9e446348a76f9fb5"
ecc-jsbn@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
@@ -1184,6 +1228,12 @@ get-pixels@^3.3.0:
request "^2.44.0"
through "^2.3.4"
get-proxy@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/get-proxy/-/get-proxy-2.1.0.tgz#349f2b4d91d44c4d4d4e9cba2ad90143fac5ef93"
dependencies:
npm-conf "^1.1.0"
getpass@^0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
@@ -1272,6 +1322,16 @@ has-flag@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
has-symbol-support-x@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.1.tgz#66ec2e377e0c7d7ccedb07a3a84d77510ff1bc4c"
has-to-string-tag-x@^1.2.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d"
dependencies:
has-symbol-support-x "^1.4.1"
has-unicode@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@@ -1344,7 +1404,7 @@ inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
ini@~1.3.0:
ini@^1.3.4, ini@~1.3.0:
version "1.3.4"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
@@ -1365,6 +1425,10 @@ is-absolute@^0.2.6:
is-relative "^0.2.1"
is-windows "^0.2.0"
is-arrayish@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.1.tgz#c2dfc386abaa0c3e33c48db3fe87059e69065efd"
is-binary-path@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
@@ -1427,6 +1491,10 @@ is-number@^3.0.0:
dependencies:
kind-of "^3.0.2"
is-object@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470"
is-path-cwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
@@ -1495,6 +1563,13 @@ isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
isurl@^1.0.0-alpha5:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67"
dependencies:
has-to-string-tag-x "^1.2.0"
is-object "^1.0.1"
jasmine-core@~2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-2.8.0.tgz#bcc979ae1f9fd05701e45e52e65d3a5d63f1a24e"
@@ -1658,6 +1733,14 @@ mime-types@^2.0.1, mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.7:
dependencies:
mime-db "~1.30.0"
mime@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.0.3.tgz#4353337854747c48ea498330dc034f9f4bbbcc0b"
mimic-response@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e"
minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@@ -1672,7 +1755,19 @@ minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
"mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.1:
minipass@^2.0.2, minipass@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.2.1.tgz#5ada97538b1027b4cf7213432428578cb564011f"
dependencies:
yallist "^3.0.0"
minizlib@^1.0.3:
version "1.0.4"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.0.4.tgz#8ebb51dd8bbe40b0126b5633dbb36b284a2f523c"
dependencies:
minipass "^2.2.1"
"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
dependencies:
@@ -1690,7 +1785,7 @@ nan@2.3.5:
version "2.3.5"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.3.5.tgz#822a0dc266290ce4cd3a12282ca3e7e364668a08"
nan@^2.3.0, nan@~2.7.0:
nan@^2.3.0, nan@^2.6.2, nan@~2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46"
@@ -1769,6 +1864,13 @@ normalize-path@^2.0.0, normalize-path@^2.0.1:
dependencies:
remove-trailing-separator "^1.0.1"
npm-conf@^1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.2.tgz#170a2c48a0c6ad0495f03f87aec2da11ef47a525"
dependencies:
config-chain "^1.1.11"
pify "^3.0.0"
npmlog@^4.0.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
@@ -1801,7 +1903,7 @@ omggif@^1.0.5:
version "1.0.8"
resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.8.tgz#178f37b2ab0b3d7b46ed3a0e46bd0790b58d3530"
once@^1.3.0, once@^1.3.3:
once@^1.3.0, once@^1.3.1, once@^1.3.3:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
dependencies:
@@ -1869,6 +1971,10 @@ pify@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
pify@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
pinkie-promise@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
@@ -1908,6 +2014,10 @@ proper-lockfile@^2.0.1:
graceful-fs "^4.1.2"
retry "^0.10.0"
proto-list@~1.2.1:
version "1.2.4"
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
pty.js@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/pty.js/-/pty.js-0.3.1.tgz#81f5bed332d6e5e7ab685688d1ba0373410d51b5"
@@ -2138,10 +2248,40 @@ set-immediate-shim@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61"
sharp@^0.18.4:
version "0.18.4"
resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.18.4.tgz#fe329c0f06896c28aa24376df1fff02ae57f2d34"
dependencies:
caw "^2.0.0"
color "^2.0.0"
detect-libc "^0.2.0"
nan "^2.6.2"
semver "^5.3.0"
simple-get "^2.7.0"
tar "^3.1.5"
signal-exit@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
simple-concat@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6"
simple-get@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.7.0.tgz#ad37f926d08129237ff08c4f2edfd6f10e0380b5"
dependencies:
decompress-response "^3.3.0"
once "^1.3.1"
simple-concat "^1.0.0"
simple-swizzle@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
dependencies:
is-arrayish "^0.3.1"
slash@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
@@ -2296,6 +2436,16 @@ tar@^2.2.1:
fstream "^1.0.2"
inherits "2"
tar@^3.1.5:
version "3.2.1"
resolved "https://registry.yarnpkg.com/tar/-/tar-3.2.1.tgz#9aa8e41c88f09e76c166075bc71f93d5166e61b1"
dependencies:
chownr "^1.0.1"
minipass "^2.0.2"
minizlib "^1.0.3"
mkdirp "^0.5.0"
yallist "^3.0.2"
tcp-port-used@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/tcp-port-used/-/tcp-port-used-0.1.2.tgz#9450e8768c83b416fd4d1a6a9449eeccbf496c29"
@@ -2320,8 +2470,8 @@ through@^2.3.4:
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
tkwidgets@^0.5.3:
version "0.5.9"
resolved "https://registry.yarnpkg.com/tkwidgets/-/tkwidgets-0.5.9.tgz#0770fb9db91d8e41f22fdbe77e436c40affaec01"
version "0.5.11"
resolved "https://registry.yarnpkg.com/tkwidgets/-/tkwidgets-0.5.11.tgz#5ecbb70d9326d19b1906d0298e8cbfea342d2c4f"
dependencies:
chalk "^2.1.0"
node-emoji "^1.8.1"
@@ -2374,6 +2524,10 @@ universalify@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
url-to-options@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"
user-home@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"
@@ -2431,6 +2585,10 @@ xregexp@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-3.2.0.tgz#cb3601987bfe2695b584000c18f1c4a8c322878e"
yallist@^3.0.0, yallist@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"
yargs-parser@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9"

View File

@@ -313,7 +313,7 @@ class NoteScreenComponent extends BaseScreenComponent {
let targetPath = Resource.fullPath(resource);
if (res.type == 'image/jpeg' || res.type == 'image/jpg' || res.type == 'image/png') {
const maxSize = 1920;
const maxSize = Resource.IMAGE_MAX_DIMENSION;
let dimensions = await this.imageDimensions(localFilePath);

View File

@@ -82,11 +82,27 @@ class Note extends BaseItem {
return output;
}
// Note: sort logic must be duplicated in previews();
static sortNotes(notes, orders, uncompletedTodosOnTop) {
const noteOnTop = (note) => {
return uncompletedTodosOnTop && note.is_todo && !note.todo_completed;
}
const noteFieldComp = (f1, f2) => {
if (f1 === f2) return 0;
return f1 < f2 ? -1 : +1;
}
// Makes the sort deterministic, so that if, for example, a and b have the
// same updated_time, they aren't swapped every time a list is refreshed.
const sortIdenticalNotes = (a, b) => {
let r = null;
r = noteFieldComp(a.user_updated_time, b.user_updated_time); if (r) return r;
r = noteFieldComp(a.user_created_time, b.user_created_time); if (r) return r;
r = noteFieldComp(a.title.toLowerCase(), b.title.toLowerCase()); if (r) return r;
return noteFieldComp(a.id, b.id);
}
return notes.sort((a, b) => {
if (noteOnTop(a) && !noteOnTop(b)) return -1;
if (!noteOnTop(a) && noteOnTop(b)) return +1;
@@ -98,12 +114,10 @@ class Note extends BaseItem {
if (a[order.by] < b[order.by]) r = +1;
if (a[order.by] > b[order.by]) r = -1;
if (order.dir == 'ASC') r = -r;
if (r !== 0) break;
if (r !== 0) return r;
}
// Makes the sort deterministic, so that if, for example, a and b have the
// same updated_time, they aren't swapped every time a list is refreshed.
return a.title.toLowerCase() + a.id < b.title.toLowerCase() + b.id ? -1 : +1;
return sortIdenticalNotes(a, b);
});
}
@@ -131,11 +145,16 @@ class Note extends BaseItem {
}
static async previews(parentId, options = null) {
// Note: ordering logic must be duplicated in sortNotes, which
// Note: ordering logic must be duplicated in sortNotes(), which
// is used to sort already loaded notes.
if (!options) options = {};
if (!options.order) options.order = [{ by: 'user_updated_time', dir: 'DESC' }];
if (!options.order) options.order = [
{ by: 'user_updated_time', dir: 'DESC' },
{ by: 'user_created_time', dir: 'DESC' },
{ by: 'title', dir: 'DESC' },
{ by: 'id', dir: 'DESC' },
];
if (!options.conditions) options.conditions = [];
if (!options.conditionsParams) options.conditionsParams = [];
if (!options.fields) options.fields = this.previewFields();

View File

@@ -78,4 +78,6 @@ class Resource extends BaseItem {
}
Resource.IMAGE_MAX_DIMENSION = 1920;
export { Resource };

View File

@@ -1,6 +1,7 @@
import { BaseModel } from 'lib/base-model.js';
import { Database } from 'lib/database.js';
import { Logger } from 'lib/logger.js';
import { sprintf } from 'sprintf-js';
import { _, supportedLocalesToLanguages, defaultLocale } from 'lib/locale.js';
class Setting extends BaseModel {
@@ -205,12 +206,14 @@ class Setting extends BaseModel {
return this.metadata_[key].options();
}
static enumOptionsDoc(key) {
static enumOptionsDoc(key, templateString = null) {
if (templateString === null) templateString = '%s: %s';
console.info(templateString);
const options = this.enumOptions(key);
let output = [];
for (let n in options) {
if (!options.hasOwnProperty(n)) continue;
output.push(_('%s: %s', n, options[n]));
output.push(sprintf(templateString, n, options[n]));
}
return output.join(', ');
}
@@ -289,6 +292,12 @@ class Setting extends BaseModel {
return output;
}
static typeToString(typeId) {
if (typeId === Setting.TYPE_INT) return 'int';
if (typeId === Setting.TYPE_STRING) return 'string';
if (typeId === Setting.TYPE_BOOL) return 'bool';
}
}
Setting.SYNC_TARGET_MEMORY = 1;
@@ -320,7 +329,7 @@ Setting.metadata_ = {
'sync.4.context': { value: '', type: Setting.TYPE_STRING, public: false },
'sync.5.context': { value: '', type: Setting.TYPE_STRING, public: false },
'sync.6.context': { value: '', type: Setting.TYPE_STRING, public: false },
'editor': { value: '', type: Setting.TYPE_STRING, public: true, appTypes: ['cli'] },
'editor': { value: '', type: Setting.TYPE_STRING, public: true, appTypes: ['cli'], label: () => _('The editor that will be used to open a note. If none is provided it will try to auto-detect the default editor.') },
'locale': { value: defaultLocale(), type: Setting.TYPE_STRING, isEnum: true, public: true, label: () => _('Language'), options: () => {
return supportedLocalesToLanguages();
}},
@@ -336,7 +345,7 @@ Setting.metadata_ = {
'uncompletedTodosOnTop': { value: true, type: Setting.TYPE_BOOL, public: true, label: () => _('Show uncompleted todos on top of the lists') },
'showAdvancedOptions': { value: false, type: Setting.TYPE_BOOL, public: true, appTypes: ['mobile'], label: () => _('Show advanced options') },
'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, appTypes: ['mobile'], label: () => _('Synchronisation interval'), options: () => {
'sync.interval': { value: 300, type: Setting.TYPE_INT, isEnum: true, public: true, label: () => _('Synchronisation interval'), options: () => {
return {
0: _('Disabled'),
300: _('%d minutes', 5),