mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Chore: Apply eslint rules
This commit is contained in:
parent
ab29d7e872
commit
e648392330
@ -28,7 +28,7 @@ class ResourceServer {
|
|||||||
|
|
||||||
baseUrl() {
|
baseUrl() {
|
||||||
if (!this.port_) return '';
|
if (!this.port_) return '';
|
||||||
return 'http://127.0.0.1:' + this.port_;
|
return `http://127.0.0.1:${this.port_}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
setLinkHandler(handler) {
|
setLinkHandler(handler) {
|
||||||
@ -53,7 +53,7 @@ class ResourceServer {
|
|||||||
const url = urlParser.parse(request.url, true);
|
const url = urlParser.parse(request.url, true);
|
||||||
let resourceId = url.pathname.split('/');
|
let resourceId = url.pathname.split('/');
|
||||||
if (resourceId.length < 2) {
|
if (resourceId.length < 2) {
|
||||||
writeResponse('Error: could not get resource ID from path name: ' + url.pathname);
|
writeResponse(`Error: could not get resource ID from path name: ${url.pathname}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
resourceId = resourceId[1];
|
resourceId = resourceId[1];
|
||||||
@ -62,7 +62,7 @@ class ResourceServer {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const done = await this.linkHandler_(resourceId, response);
|
const done = await this.linkHandler_(resourceId, response);
|
||||||
if (!done) throw new Error('Unhandled resource: ' + resourceId);
|
if (!done) throw new Error(`Unhandled resource: ${resourceId}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
response.setHeader('Content-Type', 'text/plain');
|
response.setHeader('Content-Type', 'text/plain');
|
||||||
// eslint-disable-next-line require-atomic-updates
|
// eslint-disable-next-line require-atomic-updates
|
||||||
|
@ -288,7 +288,7 @@ class AppGui {
|
|||||||
if (!cmd) return;
|
if (!cmd) return;
|
||||||
const isConfigPassword = cmd.indexOf('config ') >= 0 && cmd.indexOf('password') >= 0;
|
const isConfigPassword = cmd.indexOf('config ') >= 0 && cmd.indexOf('password') >= 0;
|
||||||
if (isConfigPassword) return;
|
if (isConfigPassword) return;
|
||||||
this.stdout(chalk.cyan.bold('> ' + cmd));
|
this.stdout(chalk.cyan.bold(`> ${cmd}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
setupKeymap(keymap) {
|
setupKeymap(keymap) {
|
||||||
@ -297,7 +297,7 @@ class AppGui {
|
|||||||
for (let i = 0; i < keymap.length; i++) {
|
for (let i = 0; i < keymap.length; i++) {
|
||||||
const item = Object.assign({}, keymap[i]);
|
const item = Object.assign({}, keymap[i]);
|
||||||
|
|
||||||
if (!item.command) throw new Error('Missing command for keymap item: ' + JSON.stringify(item));
|
if (!item.command) throw new Error(`Missing command for keymap item: ${JSON.stringify(item)}`);
|
||||||
|
|
||||||
if (!('type' in item)) item.type = 'exec';
|
if (!('type' in item)) item.type = 'exec';
|
||||||
|
|
||||||
@ -440,7 +440,7 @@ class AppGui {
|
|||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
if (item.type_ === BaseModel.TYPE_FOLDER) {
|
if (item.type_ === BaseModel.TYPE_FOLDER) {
|
||||||
await this.processPromptCommand('rmbook ' + item.id);
|
await this.processPromptCommand(`rmbook ${item.id}`);
|
||||||
} else if (item.type_ === BaseModel.TYPE_TAG) {
|
} else if (item.type_ === BaseModel.TYPE_TAG) {
|
||||||
this.stdout(_('To delete a tag, untag the associated notes.'));
|
this.stdout(_('To delete a tag, untag the associated notes.'));
|
||||||
} else if (item.type_ === BaseModel.TYPE_SEARCH) {
|
} else if (item.type_ === BaseModel.TYPE_SEARCH) {
|
||||||
@ -473,7 +473,7 @@ class AppGui {
|
|||||||
this.addCommandToConsole(cmd);
|
this.addCommandToConsole(cmd);
|
||||||
await this.processPromptCommand(cmd);
|
await this.processPromptCommand(cmd);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unknown command: ' + cmd);
|
throw new Error(`Unknown command: ${cmd}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,7 +593,7 @@ class AppGui {
|
|||||||
if (!s) return false;
|
if (!s) return false;
|
||||||
s = s.trim().toLowerCase();
|
s = s.trim().toLowerCase();
|
||||||
for (let i = 0; i < protocols.length; i++) {
|
for (let i = 0; i < protocols.length; i++) {
|
||||||
if (s.indexOf(protocols[i] + '://') === 0) return true;
|
if (s.indexOf(`${protocols[i]}://`) === 0) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@ -627,7 +627,7 @@ class AppGui {
|
|||||||
if (link.type === 'item') {
|
if (link.type === 'item') {
|
||||||
const itemId = link.id;
|
const itemId = link.id;
|
||||||
let item = await BaseItem.loadItemById(itemId);
|
let item = await BaseItem.loadItemById(itemId);
|
||||||
if (!item) throw new Error('No item with ID ' + itemId); // Should be nearly impossible
|
if (!item) throw new Error(`No item with ID ${itemId}`); // Should be nearly impossible
|
||||||
|
|
||||||
if (item.type_ === BaseModel.TYPE_RESOURCE) {
|
if (item.type_ === BaseModel.TYPE_RESOURCE) {
|
||||||
if (item.mime) response.setHeader('Content-Type', item.mime);
|
if (item.mime) response.setHeader('Content-Type', item.mime);
|
||||||
@ -640,11 +640,11 @@ class AppGui {
|
|||||||
<head><meta charset="UTF-8"/></head><body>
|
<head><meta charset="UTF-8"/></head><body>
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
html.push('<pre>' + htmlentities(item.title) + '\n\n' + htmlentities(item.body) + '</pre>');
|
html.push(`<pre>${htmlentities(item.title)}\n\n${htmlentities(item.body)}</pre>`);
|
||||||
html.push('</body></html>');
|
html.push('</body></html>');
|
||||||
response.write(html.join(''));
|
response.write(html.join(''));
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unsupported item type: ' + item.type_);
|
throw new Error(`Unsupported item type: ${item.type_}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -676,7 +676,7 @@ class AppGui {
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
return linkStyle(this.resourceServer_.baseUrl() + '/' + index);
|
return linkStyle(`${this.resourceServer_.baseUrl()}/${index}`);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -777,7 +777,7 @@ class AppGui {
|
|||||||
} else if (keymapItem.type === 'tkwidgets') {
|
} else if (keymapItem.type === 'tkwidgets') {
|
||||||
this.widget('root').handleKey(this.tkWidgetKeys_[keymapItem.command]);
|
this.widget('root').handleKey(this.tkWidgetKeys_[keymapItem.command]);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unknown command type: ' + JSON.stringify(keymapItem));
|
throw new Error(`Unknown command type: ${JSON.stringify(keymapItem)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,10 +136,10 @@ class Application extends BaseApplication {
|
|||||||
if (!options.answers) options.answers = options.booleanAnswerDefault === 'y' ? [_('Y'), _('n')] : [_('N'), _('y')];
|
if (!options.answers) options.answers = options.booleanAnswerDefault === 'y' ? [_('Y'), _('n')] : [_('N'), _('y')];
|
||||||
|
|
||||||
if (options.type == 'boolean') {
|
if (options.type == 'boolean') {
|
||||||
message += ' (' + options.answers.join('/') + ')';
|
message += ` (${options.answers.join('/')})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let answer = await this.gui().prompt('', message + ' ', options);
|
let answer = await this.gui().prompt('', `${message} `, options);
|
||||||
|
|
||||||
if (options.type === 'boolean') {
|
if (options.type === 'boolean') {
|
||||||
if (answer === null) return false; // Pressed ESCAPE
|
if (answer === null) return false; // Pressed ESCAPE
|
||||||
@ -181,7 +181,7 @@ class Application extends BaseApplication {
|
|||||||
const ext = fileExtension(path);
|
const ext = fileExtension(path);
|
||||||
if (ext != 'js') return;
|
if (ext != 'js') return;
|
||||||
|
|
||||||
let CommandClass = require('./' + path);
|
let CommandClass = require(`./${path}`);
|
||||||
let cmd = new CommandClass();
|
let cmd = new CommandClass();
|
||||||
if (!cmd.enabled()) return;
|
if (!cmd.enabled()) return;
|
||||||
cmd = this.setupCommand(cmd);
|
cmd = this.setupCommand(cmd);
|
||||||
@ -248,7 +248,7 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
let CommandClass = null;
|
let CommandClass = null;
|
||||||
try {
|
try {
|
||||||
CommandClass = require(__dirname + '/command-' + name + '.js');
|
CommandClass = require(`${__dirname}/command-${name}.js`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.message && error.message.indexOf('Cannot find module') >= 0) {
|
if (error.message && error.message.indexOf('Cannot find module') >= 0) {
|
||||||
let e = new Error(_('No such command: %s', name));
|
let e = new Error(_('No such command: %s', name));
|
||||||
@ -343,7 +343,7 @@ class Application extends BaseApplication {
|
|||||||
itemsByCommand[defaultKeyMap[i].command] = defaultKeyMap[i];
|
itemsByCommand[defaultKeyMap[i].command] = defaultKeyMap[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
const filePath = Setting.value('profileDir') + '/keymap.json';
|
const filePath = `${Setting.value('profileDir')}/keymap.json`;
|
||||||
if (await fs.pathExists(filePath)) {
|
if (await fs.pathExists(filePath)) {
|
||||||
try {
|
try {
|
||||||
let configString = await fs.readFile(filePath, 'utf-8');
|
let configString = await fs.readFile(filePath, 'utf-8');
|
||||||
@ -355,7 +355,7 @@ class Application extends BaseApplication {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let msg = error.message ? error.message : '';
|
let msg = error.message ? error.message : '';
|
||||||
msg = 'Could not load keymap ' + filePath + '\n' + msg;
|
msg = `Could not load keymap ${filePath}\n${msg}`;
|
||||||
error.message = msg;
|
error.message = msg;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,9 @@ async function handleAutocompletionPromise(line) {
|
|||||||
if (names.indexOf(words[0]) === -1) {
|
if (names.indexOf(words[0]) === -1) {
|
||||||
let x = names.filter(n => n.indexOf(words[0]) === 0);
|
let x = names.filter(n => n.indexOf(words[0]) === 0);
|
||||||
if (x.length === 1) {
|
if (x.length === 1) {
|
||||||
return x[0] + ' ';
|
return `${x[0]} `;
|
||||||
}
|
}
|
||||||
return x.length > 0 ? x.map(a => a + ' ') : line;
|
return x.length > 0 ? x.map(a => `${a} `) : line;
|
||||||
} else {
|
} else {
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ async function handleAutocompletionPromise(line) {
|
|||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
let ret = l.map(a => toCommandLine(a));
|
let ret = l.map(a => toCommandLine(a));
|
||||||
ret.prefix = toCommandLine(words.slice(0, -1)) + ' ';
|
ret.prefix = `${toCommandLine(words.slice(0, -1))} `;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
//Complete an argument
|
//Complete an argument
|
||||||
@ -74,23 +74,23 @@ async function handleAutocompletionPromise(line) {
|
|||||||
const currentFolder = app().currentFolder();
|
const currentFolder = app().currentFolder();
|
||||||
|
|
||||||
if (argName == 'note' || argName == 'note-pattern') {
|
if (argName == 'note' || argName == 'note-pattern') {
|
||||||
const notes = currentFolder ? await Note.previews(currentFolder.id, { titlePattern: next + '*' }) : [];
|
const notes = currentFolder ? await Note.previews(currentFolder.id, { titlePattern: `${next}*` }) : [];
|
||||||
l.push(...notes.map(n => n.title));
|
l.push(...notes.map(n => n.title));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argName == 'notebook') {
|
if (argName == 'notebook') {
|
||||||
const folders = await Folder.search({ titlePattern: next + '*' });
|
const folders = await Folder.search({ titlePattern: `${next}*` });
|
||||||
l.push(...folders.map(n => n.title));
|
l.push(...folders.map(n => n.title));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argName == 'item') {
|
if (argName == 'item') {
|
||||||
const notes = currentFolder ? await Note.previews(currentFolder.id, { titlePattern: next + '*' }) : [];
|
const notes = currentFolder ? await Note.previews(currentFolder.id, { titlePattern: `${next}*` }) : [];
|
||||||
const folders = await Folder.search({ titlePattern: next + '*' });
|
const folders = await Folder.search({ titlePattern: `${next}*` });
|
||||||
l.push(...notes.map(n => n.title), folders.map(n => n.title));
|
l.push(...notes.map(n => n.title), folders.map(n => n.title));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argName == 'tag') {
|
if (argName == 'tag') {
|
||||||
let tags = await Tag.search({ titlePattern: next + '*' });
|
let tags = await Tag.search({ titlePattern: `${next}*` });
|
||||||
l.push(...tags.map(n => n.title));
|
l.push(...tags.map(n => n.title));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ async function handleAutocompletionPromise(line) {
|
|||||||
return toCommandLine([...words.slice(0, -1), l[0]]);
|
return toCommandLine([...words.slice(0, -1), l[0]]);
|
||||||
} else if (l.length > 1) {
|
} else if (l.length > 1) {
|
||||||
let ret = l.map(a => toCommandLine(a));
|
let ret = l.map(a => toCommandLine(a));
|
||||||
ret.prefix = toCommandLine(words.slice(0, -1)) + ' ';
|
ret.prefix = `${toCommandLine(words.slice(0, -1))} `;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return line;
|
return line;
|
||||||
@ -128,9 +128,9 @@ function toCommandLine(args) {
|
|||||||
return args
|
return args
|
||||||
.map(function(a) {
|
.map(function(a) {
|
||||||
if (a.indexOf('"') !== -1 || a.indexOf(' ') !== -1) {
|
if (a.indexOf('"') !== -1 || a.indexOf(' ') !== -1) {
|
||||||
return '\'' + a + '\'';
|
return `'${a}'`;
|
||||||
} else if (a.indexOf('\'') !== -1) {
|
} else if (a.indexOf('\'') !== -1) {
|
||||||
return '"' + a + '"';
|
return `"${a}"`;
|
||||||
} else {
|
} else {
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
@ -138,11 +138,11 @@ function toCommandLine(args) {
|
|||||||
.join(' ');
|
.join(' ');
|
||||||
} else {
|
} else {
|
||||||
if (args.indexOf('"') !== -1 || args.indexOf(' ') !== -1) {
|
if (args.indexOf('"') !== -1 || args.indexOf(' ') !== -1) {
|
||||||
return '\'' + args + '\' ';
|
return `'${args}' `;
|
||||||
} else if (args.indexOf('\'') !== -1) {
|
} else if (args.indexOf('\'') !== -1) {
|
||||||
return '"' + args + '" ';
|
return `"${args}" `;
|
||||||
} else {
|
} else {
|
||||||
return args + ' ';
|
return `${args} `;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ function getCommands() {
|
|||||||
const ext = fileExtension(path);
|
const ext = fileExtension(path);
|
||||||
if (ext != 'js') return;
|
if (ext != 'js') return;
|
||||||
|
|
||||||
let CommandClass = require('./' + path);
|
let CommandClass = require(`./${path}`);
|
||||||
let cmd = new CommandClass();
|
let cmd = new CommandClass();
|
||||||
if (!cmd.enabled()) return;
|
if (!cmd.enabled()) return;
|
||||||
if (cmd.hidden()) return;
|
if (cmd.hidden()) return;
|
||||||
@ -102,14 +102,14 @@ function getFooter() {
|
|||||||
|
|
||||||
output.push('WEBSITE');
|
output.push('WEBSITE');
|
||||||
output.push('');
|
output.push('');
|
||||||
output.push(INDENT + 'https://joplinapp.org');
|
output.push(`${INDENT}https://joplinapp.org`);
|
||||||
|
|
||||||
output.push('');
|
output.push('');
|
||||||
|
|
||||||
output.push('LICENSE');
|
output.push('LICENSE');
|
||||||
output.push('');
|
output.push('');
|
||||||
let filePath = rootDir + '/LICENSE_' + languageCode();
|
let filePath = `${rootDir}/LICENSE_${languageCode()}`;
|
||||||
if (!fs.existsSync(filePath)) filePath = rootDir + '/LICENSE';
|
if (!fs.existsSync(filePath)) filePath = `${rootDir}/LICENSE`;
|
||||||
const licenseText = fs.readFileSync(filePath, 'utf8');
|
const licenseText = fs.readFileSync(filePath, 'utf8');
|
||||||
output.push(wrap(licenseText, INDENT));
|
output.push(wrap(licenseText, INDENT));
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ async function main() {
|
|||||||
const commandsText = commandBlocks.join('\n\n');
|
const commandsText = commandBlocks.join('\n\n');
|
||||||
const footerText = getFooter();
|
const footerText = getFooter();
|
||||||
|
|
||||||
console.info(headerText + '\n\n' + 'USAGE' + '\n\n' + commandsText + '\n\n' + footerText);
|
console.info(`${headerText}\n\n` + 'USAGE' + `\n\n${commandsText}\n\n${footerText}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
main().catch(error => {
|
main().catch(error => {
|
||||||
|
@ -16,8 +16,8 @@ process.on('unhandledRejection', (reason, p) => {
|
|||||||
console.error('Unhandled promise rejection', p, 'reason:', reason);
|
console.error('Unhandled promise rejection', p, 'reason:', reason);
|
||||||
});
|
});
|
||||||
|
|
||||||
const baseDir = dirname(__dirname) + '/tests/cli-integration';
|
const baseDir = `${dirname(__dirname)}/tests/cli-integration`;
|
||||||
const joplinAppPath = __dirname + '/main.js';
|
const joplinAppPath = `${__dirname}/main.js`;
|
||||||
|
|
||||||
const logger = new Logger();
|
const logger = new Logger();
|
||||||
logger.addTarget('console');
|
logger.addTarget('console');
|
||||||
@ -33,16 +33,16 @@ db.setLogger(dbLogger);
|
|||||||
function createClient(id) {
|
function createClient(id) {
|
||||||
return {
|
return {
|
||||||
id: id,
|
id: id,
|
||||||
profileDir: baseDir + '/client' + id,
|
profileDir: `${baseDir}/client${id}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = createClient(1);
|
const client = createClient(1);
|
||||||
|
|
||||||
function execCommand(client, command) {
|
function execCommand(client, command) {
|
||||||
let exePath = 'node ' + joplinAppPath;
|
let exePath = `node ${joplinAppPath}`;
|
||||||
let cmd = exePath + ' --update-geolocation-disabled --env dev --profile ' + client.profileDir + ' ' + command;
|
let cmd = `${exePath} --update-geolocation-disabled --env dev --profile ${client.profileDir} ${command}`;
|
||||||
logger.info(client.id + ': ' + command);
|
logger.info(`${client.id}: ${command}`);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
exec(cmd, (error, stdout, stderr) => {
|
exec(cmd, (error, stdout, stderr) => {
|
||||||
@ -217,7 +217,7 @@ async function main() {
|
|||||||
|
|
||||||
logger.info(await execCommand(client, 'version'));
|
logger.info(await execCommand(client, 'version'));
|
||||||
|
|
||||||
await db.open({ name: client.profileDir + '/database.sqlite' });
|
await db.open({ name: `${client.profileDir}/database.sqlite` });
|
||||||
BaseModel.db_ = db;
|
BaseModel.db_ = db;
|
||||||
await Setting.load();
|
await Setting.load();
|
||||||
|
|
||||||
@ -230,7 +230,7 @@ async function main() {
|
|||||||
|
|
||||||
await clearDatabase();
|
await clearDatabase();
|
||||||
let testName = n.substr(4).toLowerCase();
|
let testName = n.substr(4).toLowerCase();
|
||||||
process.stdout.write(testName + ': ');
|
process.stdout.write(`${testName}: `);
|
||||||
await testUnits[n]();
|
await testUnits[n]();
|
||||||
console.info('');
|
console.info('');
|
||||||
}
|
}
|
||||||
|
@ -58,7 +58,7 @@ cliUtils.parseFlags = function(flags) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
cliUtils.parseCommandArg = function(arg) {
|
cliUtils.parseCommandArg = function(arg) {
|
||||||
if (arg.length <= 2) throw new Error('Invalid command arg: ' + arg);
|
if (arg.length <= 2) throw new Error(`Invalid command arg: ${arg}`);
|
||||||
|
|
||||||
const c1 = arg[0];
|
const c1 = arg[0];
|
||||||
const c2 = arg[arg.length - 1];
|
const c2 = arg[arg.length - 1];
|
||||||
@ -69,7 +69,7 @@ cliUtils.parseCommandArg = function(arg) {
|
|||||||
} else if (c1 == '[' && c2 == ']') {
|
} else if (c1 == '[' && c2 == ']') {
|
||||||
return { required: false, name: name };
|
return { required: false, name: name };
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Invalid command arg: ' + arg);
|
throw new Error(`Invalid command arg: ${arg}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ cliUtils.makeCommandArgs = function(cmd, argv) {
|
|||||||
let booleanFlags = [];
|
let booleanFlags = [];
|
||||||
let aliases = {};
|
let aliases = {};
|
||||||
for (let i = 0; i < options.length; i++) {
|
for (let i = 0; i < options.length; i++) {
|
||||||
if (options[i].length != 2) throw new Error('Invalid options: ' + options[i]);
|
if (options[i].length != 2) throw new Error(`Invalid options: ${options[i]}`);
|
||||||
let flags = options[i][0];
|
let flags = options[i][0];
|
||||||
|
|
||||||
flags = cliUtils.parseFlags(flags);
|
flags = cliUtils.parseFlags(flags);
|
||||||
@ -136,7 +136,7 @@ cliUtils.promptMcq = function(message, answers) {
|
|||||||
message += '\n\n';
|
message += '\n\n';
|
||||||
for (let n in answers) {
|
for (let n in answers) {
|
||||||
if (!answers.hasOwnProperty(n)) continue;
|
if (!answers.hasOwnProperty(n)) continue;
|
||||||
message += _('%s: %s', n, answers[n]) + '\n';
|
message += `${_('%s: %s', n, answers[n])}\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
message += '\n';
|
message += '\n';
|
||||||
@ -165,10 +165,10 @@ cliUtils.promptConfirm = function(message, answers = null) {
|
|||||||
output: process.stdout,
|
output: process.stdout,
|
||||||
});
|
});
|
||||||
|
|
||||||
message += ' (' + answers.join('/') + ')';
|
message += ` (${answers.join('/')})`;
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
rl.question(message + ' ', answer => {
|
rl.question(`${message} `, answer => {
|
||||||
const ok = !answer || answer.toLowerCase() == answers[0].toLowerCase();
|
const ok = !answer || answer.toLowerCase() == answers[0].toLowerCase();
|
||||||
rl.close();
|
rl.close();
|
||||||
resolve(ok);
|
resolve(ok);
|
||||||
|
@ -168,7 +168,7 @@ class Command extends BaseCommand {
|
|||||||
// });
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.push('# ' + toTitleCase(tableName));
|
lines.push(`# ${toTitleCase(tableName)}`);
|
||||||
lines.push('');
|
lines.push('');
|
||||||
|
|
||||||
if (model.type === BaseModel.TYPE_FOLDER) {
|
if (model.type === BaseModel.TYPE_FOLDER) {
|
||||||
@ -181,9 +181,9 @@ class Command extends BaseCommand {
|
|||||||
lines.push(this.createPropertiesTable(tableFields));
|
lines.push(this.createPropertiesTable(tableFields));
|
||||||
lines.push('');
|
lines.push('');
|
||||||
|
|
||||||
lines.push('## GET /' + tableName);
|
lines.push(`## GET /${tableName}`);
|
||||||
lines.push('');
|
lines.push('');
|
||||||
lines.push('Gets all ' + tableName);
|
lines.push(`Gets all ${tableName}`);
|
||||||
lines.push('');
|
lines.push('');
|
||||||
|
|
||||||
if (model.type === BaseModel.TYPE_FOLDER) {
|
if (model.type === BaseModel.TYPE_FOLDER) {
|
||||||
@ -191,9 +191,9 @@ class Command extends BaseCommand {
|
|||||||
lines.push('');
|
lines.push('');
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.push('## GET /' + tableName + '/:id');
|
lines.push(`## GET /${tableName}/:id`);
|
||||||
lines.push('');
|
lines.push('');
|
||||||
lines.push('Gets ' + singular + ' with ID :id');
|
lines.push(`Gets ${singular} with ID :id`);
|
||||||
lines.push('');
|
lines.push('');
|
||||||
|
|
||||||
if (model.type === BaseModel.TYPE_TAG) {
|
if (model.type === BaseModel.TYPE_TAG) {
|
||||||
@ -224,9 +224,9 @@ class Command extends BaseCommand {
|
|||||||
lines.push('');
|
lines.push('');
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.push('## POST /' + tableName);
|
lines.push(`## POST /${tableName}`);
|
||||||
lines.push('');
|
lines.push('');
|
||||||
lines.push('Creates a new ' + singular);
|
lines.push(`Creates a new ${singular}`);
|
||||||
lines.push('');
|
lines.push('');
|
||||||
|
|
||||||
if (model.type === BaseModel.TYPE_RESOURCE) {
|
if (model.type === BaseModel.TYPE_RESOURCE) {
|
||||||
@ -270,14 +270,14 @@ class Command extends BaseCommand {
|
|||||||
lines.push('');
|
lines.push('');
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.push('## PUT /' + tableName + '/:id');
|
lines.push(`## PUT /${tableName}/:id`);
|
||||||
lines.push('');
|
lines.push('');
|
||||||
lines.push('Sets the properties of the ' + singular + ' with ID :id');
|
lines.push(`Sets the properties of the ${singular} with ID :id`);
|
||||||
lines.push('');
|
lines.push('');
|
||||||
|
|
||||||
lines.push('## DELETE /' + tableName + '/:id');
|
lines.push(`## DELETE /${tableName}/:id`);
|
||||||
lines.push('');
|
lines.push('');
|
||||||
lines.push('Deletes the ' + singular + ' with ID :id');
|
lines.push(`Deletes the ${singular} with ID :id`);
|
||||||
lines.push('');
|
lines.push('');
|
||||||
|
|
||||||
if (model.type === BaseModel.TYPE_TAG) {
|
if (model.type === BaseModel.TYPE_TAG) {
|
||||||
|
@ -97,13 +97,13 @@ class Command extends BaseCommand {
|
|||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
const outputDir = options.output ? options.output : require('os').tmpdir();
|
const outputDir = options.output ? options.output : require('os').tmpdir();
|
||||||
let outFile = outputDir + '/' + pathUtils.filename(args.path) + '.' + Date.now() + '.bin';
|
let outFile = `${outputDir}/${pathUtils.filename(args.path)}.${Date.now()}.bin`;
|
||||||
await EncryptionService.instance().decryptFile(args.path, outFile);
|
await EncryptionService.instance().decryptFile(args.path, outFile);
|
||||||
const buffer = await readChunk(outFile, 0, 64);
|
const buffer = await readChunk(outFile, 0, 64);
|
||||||
const detectedType = imageType(buffer);
|
const detectedType = imageType(buffer);
|
||||||
|
|
||||||
if (detectedType) {
|
if (detectedType) {
|
||||||
const newOutFile = outFile + '.' + detectedType.ext;
|
const newOutFile = `${outFile}.${detectedType.ext}`;
|
||||||
await shim.fsDriver().move(outFile, newOutFile);
|
await shim.fsDriver().move(outFile, newOutFile);
|
||||||
outFile = newOutFile;
|
outFile = newOutFile;
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
for (let i = 0; i < paths.length; i++) {
|
for (let i = 0; i < paths.length; i++) {
|
||||||
const path = paths[i];
|
const path = paths[i];
|
||||||
const fullPath = targetPath + '/' + path;
|
const fullPath = `${targetPath}/${path}`;
|
||||||
const stat = await fs.stat(fullPath);
|
const stat = await fs.stat(fullPath);
|
||||||
|
|
||||||
// this.stdout(fullPath);
|
// this.stdout(fullPath);
|
||||||
@ -160,7 +160,7 @@ class Command extends BaseCommand {
|
|||||||
for (let j = 0; j < resourcePaths.length; j++) {
|
for (let j = 0; j < resourcePaths.length; j++) {
|
||||||
const resourcePath = resourcePaths[j];
|
const resourcePath = resourcePaths[j];
|
||||||
resourceCount++;
|
resourceCount++;
|
||||||
const fullResourcePath = fullPath + '/' + resourcePath;
|
const fullResourcePath = `${fullPath}/${resourcePath}`;
|
||||||
const isEncrypted = await EncryptionService.instance().fileIsEncrypted(fullResourcePath);
|
const isEncrypted = await EncryptionService.instance().fileIsEncrypted(fullResourcePath);
|
||||||
if (isEncrypted) {
|
if (isEncrypted) {
|
||||||
encryptedResourceCount++;
|
encryptedResourceCount++;
|
||||||
@ -194,9 +194,9 @@ class Command extends BaseCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stdout('Encrypted items: ' + encryptedItemCount + '/' + itemCount);
|
this.stdout(`Encrypted items: ${encryptedItemCount}/${itemCount}`);
|
||||||
this.stdout('Encrypted resources: ' + encryptedResourceCount + '/' + resourceCount);
|
this.stdout(`Encrypted resources: ${encryptedResourceCount}/${resourceCount}`);
|
||||||
this.stdout('Other items (never encrypted): ' + otherItemCount);
|
this.stdout(`Other items (never encrypted): ${otherItemCount}`);
|
||||||
|
|
||||||
if (options.verbose) {
|
if (options.verbose) {
|
||||||
this.stdout('');
|
this.stdout('');
|
||||||
|
@ -60,7 +60,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
const originalContent = await Note.serializeForEdit(note);
|
const originalContent = await Note.serializeForEdit(note);
|
||||||
|
|
||||||
tempFilePath = Setting.value('tempDir') + '/' + uuid.create() + '.md';
|
tempFilePath = `${Setting.value('tempDir')}/${uuid.create()}.md`;
|
||||||
editorArgs.push(tempFilePath);
|
editorArgs.push(tempFilePath);
|
||||||
|
|
||||||
await fs.writeFile(tempFilePath, originalContent);
|
await fs.writeFile(tempFilePath, originalContent);
|
||||||
|
@ -20,9 +20,9 @@ class Command extends BaseCommand {
|
|||||||
async action() {
|
async action() {
|
||||||
const service = new ReportService();
|
const service = new ReportService();
|
||||||
const csv = await service.basicItemList({ format: 'csv' });
|
const csv = await service.basicItemList({ format: 'csv' });
|
||||||
const filePath = Setting.value('profileDir') + '/syncReport-' + new Date().getTime() + '.csv';
|
const filePath = `${Setting.value('profileDir')}/syncReport-${new Date().getTime()}.csv`;
|
||||||
await fs.writeFileSync(filePath, csv);
|
await fs.writeFileSync(filePath, csv);
|
||||||
this.stdout('Sync status exported to ' + filePath);
|
this.stdout(`Sync status exported to ${filePath}`);
|
||||||
|
|
||||||
app()
|
app()
|
||||||
.gui()
|
.gui()
|
||||||
|
@ -18,7 +18,7 @@ class Command extends BaseCommand {
|
|||||||
const formats = service
|
const formats = service
|
||||||
.modules()
|
.modules()
|
||||||
.filter(m => m.type === 'exporter')
|
.filter(m => m.type === 'exporter')
|
||||||
.map(m => m.format + (m.description ? ' (' + m.description + ')' : ''));
|
.map(m => m.format + (m.description ? ` (${m.description})` : ''));
|
||||||
|
|
||||||
return [['--format <format>', _('Destination format: %s', formats.join(', '))], ['--note <note>', _('Exports only the given note.')], ['--notebook <notebook>', _('Exports only the given notebook.')]];
|
return [['--format <format>', _('Destination format: %s', formats.join(', '))], ['--note <note>', _('Exports only the given note.')], ['--notebook <notebook>', _('Exports only the given notebook.')]];
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
let title = item.title;
|
let title = item.title;
|
||||||
if (!shortIdShown && (seenTitles.indexOf(item.title) >= 0 || !item.title)) {
|
if (!shortIdShown && (seenTitles.indexOf(item.title) >= 0 || !item.title)) {
|
||||||
title += ' (' + BaseModel.shortId(item.id) + ')';
|
title += ` (${BaseModel.shortId(item.id)})`;
|
||||||
} else {
|
} else {
|
||||||
seenTitles.push(item.title);
|
seenTitles.push(item.title);
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ class Command extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
description() {
|
description() {
|
||||||
return _('Start, stop or check the API server. To specify on which port it should run, set the api.port config variable. Commands are (%s).', ['start', 'stop', 'status'].join('|')) + ' This is an experimental feature - use at your own risks! It is recommended that the server runs off its own separate profile so that no two CLI instances access that profile at the same time. Use --profile to specify the profile path.';
|
return `${_('Start, stop or check the API server. To specify on which port it should run, set the api.port config variable. Commands are (%s).', ['start', 'stop', 'status'].join('|'))} This is an experimental feature - use at your own risks! It is recommended that the server runs off its own separate profile so that no two CLI instances access that profile at the same time. Use --profile to specify the profile path.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async action(args) {
|
async action(args) {
|
||||||
@ -20,7 +20,7 @@ class Command extends BaseCommand {
|
|||||||
const ClipperServer = require('lib/ClipperServer');
|
const ClipperServer = require('lib/ClipperServer');
|
||||||
const stdoutFn = (s) => this.stdout(s);
|
const stdoutFn = (s) => this.stdout(s);
|
||||||
const clipperLogger = new Logger();
|
const clipperLogger = new Logger();
|
||||||
clipperLogger.addTarget('file', { path: Setting.value('profileDir') + '/log-clipper.txt' });
|
clipperLogger.addTarget('file', { path: `${Setting.value('profileDir')}/log-clipper.txt` });
|
||||||
clipperLogger.addTarget('console', { console: {
|
clipperLogger.addTarget('console', { console: {
|
||||||
info: stdoutFn,
|
info: stdoutFn,
|
||||||
warn: stdoutFn,
|
warn: stdoutFn,
|
||||||
@ -29,7 +29,7 @@ class Command extends BaseCommand {
|
|||||||
ClipperServer.instance().setDispatch(() => {});
|
ClipperServer.instance().setDispatch(() => {});
|
||||||
ClipperServer.instance().setLogger(clipperLogger);
|
ClipperServer.instance().setLogger(clipperLogger);
|
||||||
|
|
||||||
const pidPath = Setting.value('profileDir') + '/clipper-pid.txt';
|
const pidPath = `${Setting.value('profileDir')}/clipper-pid.txt`;
|
||||||
const runningOnPort = await ClipperServer.instance().isRunning();
|
const runningOnPort = await ClipperServer.instance().isRunning();
|
||||||
|
|
||||||
if (command === 'start') {
|
if (command === 'start') {
|
||||||
|
@ -16,7 +16,7 @@ class Command extends BaseCommand {
|
|||||||
for (let i = 0; i < fields.length; i++) {
|
for (let i = 0; i < fields.length; i++) {
|
||||||
const f = fields[i];
|
const f = fields[i];
|
||||||
if (f.name === 'id') continue;
|
if (f.name === 'id') continue;
|
||||||
s.push(f.name + ' (' + Database.enumName('fieldType', f.type) + ')');
|
s.push(`${f.name} (${Database.enumName('fieldType', f.type)})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _('Sets the property <name> of the given <note> to the given [value]. Possible properties are:\n\n%s', s.join(', '));
|
return _('Sets the property <name> of the given <note> to the given [value]. Possible properties are:\n\n%s', s.join(', '));
|
||||||
|
@ -22,7 +22,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
if (i > 0) this.stdout('');
|
if (i > 0) this.stdout('');
|
||||||
|
|
||||||
this.stdout('# ' + section.title);
|
this.stdout(`# ${section.title}`);
|
||||||
this.stdout('');
|
this.stdout('');
|
||||||
|
|
||||||
for (let n in section.body) {
|
for (let n in section.body) {
|
||||||
|
@ -72,7 +72,7 @@ class Command extends BaseCommand {
|
|||||||
});
|
});
|
||||||
this.oneDriveApiUtils_ = null;
|
this.oneDriveApiUtils_ = null;
|
||||||
|
|
||||||
Setting.setValue('sync.' + this.syncTargetId_ + '.auth', auth ? JSON.stringify(auth) : null);
|
Setting.setValue(`sync.${this.syncTargetId_}.auth`, auth ? JSON.stringify(auth) : null);
|
||||||
if (!auth) {
|
if (!auth) {
|
||||||
this.stdout(_('Authentication was not completed (did not receive an authentication token).'));
|
this.stdout(_('Authentication was not completed (did not receive an authentication token).'));
|
||||||
return false;
|
return false;
|
||||||
@ -93,7 +93,7 @@ class Command extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const response = await api.execAuthToken(authCode);
|
const response = await api.execAuthToken(authCode);
|
||||||
Setting.setValue('sync.' + this.syncTargetId_ + '.auth', response.access_token);
|
Setting.setValue(`sync.${this.syncTargetId_}.auth`, response.access_token);
|
||||||
api.setAuthToken(response.access_token);
|
api.setAuthToken(response.access_token);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ class Command extends BaseCommand {
|
|||||||
this.releaseLockFn_ = null;
|
this.releaseLockFn_ = null;
|
||||||
|
|
||||||
// Lock is unique per profile/database
|
// Lock is unique per profile/database
|
||||||
const lockFilePath = require('os').tmpdir() + '/synclock_' + md5(escape(Setting.value('profileDir'))); // https://github.com/pvorb/node-md5/issues/41
|
const lockFilePath = `${require('os').tmpdir()}/synclock_${md5(escape(Setting.value('profileDir')))}`; // https://github.com/pvorb/node-md5/issues/41
|
||||||
if (!(await fs.pathExists(lockFilePath))) await fs.writeFile(lockFilePath, 'synclock');
|
if (!(await fs.pathExists(lockFilePath))) await fs.writeFile(lockFilePath, 'synclock');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -178,7 +178,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
this.stdout(_('Starting synchronisation...'));
|
this.stdout(_('Starting synchronisation...'));
|
||||||
|
|
||||||
const contextKey = 'sync.' + this.syncTargetId_ + '.context';
|
const contextKey = `sync.${this.syncTargetId_}.context`;
|
||||||
let context = Setting.value(contextKey);
|
let context = Setting.value(contextKey);
|
||||||
|
|
||||||
context = context ? JSON.parse(context) : {};
|
context = context ? JSON.parse(context) : {};
|
||||||
|
@ -9,9 +9,9 @@ const lodash = require('lodash');
|
|||||||
const exec = require('child_process').exec;
|
const exec = require('child_process').exec;
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
|
|
||||||
const baseDir = dirname(__dirname) + '/tests/fuzzing';
|
const baseDir = `${dirname(__dirname)}/tests/fuzzing`;
|
||||||
const syncDir = baseDir + '/sync';
|
const syncDir = `${baseDir}/sync`;
|
||||||
const joplinAppPath = __dirname + '/main.js';
|
const joplinAppPath = `${__dirname}/main.js`;
|
||||||
let syncDurations = [];
|
let syncDurations = [];
|
||||||
|
|
||||||
const fsDriver = new FsDriverNode();
|
const fsDriver = new FsDriverNode();
|
||||||
@ -29,7 +29,7 @@ process.on('unhandledRejection', (reason, p) => {
|
|||||||
function createClient(id) {
|
function createClient(id) {
|
||||||
return {
|
return {
|
||||||
id: id,
|
id: id,
|
||||||
profileDir: baseDir + '/client' + id,
|
profileDir: `${baseDir}/client${id}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ async function createClients() {
|
|||||||
promises.push(fs.remove(client.profileDir));
|
promises.push(fs.remove(client.profileDir));
|
||||||
promises.push(
|
promises.push(
|
||||||
execCommand(client, 'config sync.target 2').then(() => {
|
execCommand(client, 'config sync.target 2').then(() => {
|
||||||
return execCommand(client, 'config sync.2.path ' + syncDir);
|
return execCommand(client, `config sync.2.path ${syncDir}`);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
output.push(client);
|
output.push(client);
|
||||||
@ -2064,12 +2064,12 @@ function randomWord() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function execCommand(client, command, options = {}) {
|
function execCommand(client, command, options = {}) {
|
||||||
let exePath = 'node ' + joplinAppPath;
|
let exePath = `node ${joplinAppPath}`;
|
||||||
let cmd = exePath + ' --update-geolocation-disabled --env dev --log-level debug --profile ' + client.profileDir + ' ' + command;
|
let cmd = `${exePath} --update-geolocation-disabled --env dev --log-level debug --profile ${client.profileDir} ${command}`;
|
||||||
logger.info(client.id + ': ' + command);
|
logger.info(`${client.id}: ${command}`);
|
||||||
|
|
||||||
if (options.killAfter) {
|
if (options.killAfter) {
|
||||||
logger.info('Kill after: ' + options.killAfter);
|
logger.info(`Kill after: ${options.killAfter}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@ -2100,7 +2100,7 @@ async function clientItems(client) {
|
|||||||
try {
|
try {
|
||||||
return JSON.parse(itemsJson);
|
return JSON.parse(itemsJson);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error('Cannot parse JSON: ' + itemsJson);
|
throw new Error(`Cannot parse JSON: ${itemsJson}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2136,13 +2136,13 @@ async function execRandomCommand(client) {
|
|||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
if (item.type_ == 1) {
|
if (item.type_ == 1) {
|
||||||
return execCommand(client, 'rm -f ' + item.id);
|
return execCommand(client, `rm -f ${item.id}`);
|
||||||
} else if (item.type_ == 2) {
|
} else if (item.type_ == 2) {
|
||||||
return execCommand(client, 'rm -r -f ' + item.id);
|
return execCommand(client, `rm -r -f ${item.id}`);
|
||||||
} else if (item.type_ == 5) {
|
} else if (item.type_ == 5) {
|
||||||
// tag
|
// tag
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unknown type: ' + item.type_);
|
throw new Error(`Unknown type: ${item.type_}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
30,
|
30,
|
||||||
@ -2168,7 +2168,7 @@ async function execRandomCommand(client) {
|
|||||||
let item = randomNote(items);
|
let item = randomNote(items);
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
return execCommand(client, 'set ' + item.id + ' title "' + randomWord() + '"');
|
return execCommand(client, `set ${item.id} title "${randomWord()}"`);
|
||||||
},
|
},
|
||||||
50,
|
50,
|
||||||
],
|
],
|
||||||
@ -2180,9 +2180,9 @@ async function execRandomCommand(client) {
|
|||||||
if (!note) return;
|
if (!note) return;
|
||||||
|
|
||||||
let tag = randomTag(items);
|
let tag = randomTag(items);
|
||||||
let tagTitle = !tag || Math.random() >= 0.9 ? 'tag-' + randomWord() : tag.title;
|
let tagTitle = !tag || Math.random() >= 0.9 ? `tag-${randomWord()}` : tag.title;
|
||||||
|
|
||||||
return execCommand(client, 'tag add ' + tagTitle + ' ' + note.id);
|
return execCommand(client, `tag add ${tagTitle} ${note.id}`);
|
||||||
},
|
},
|
||||||
50,
|
50,
|
||||||
],
|
],
|
||||||
@ -2211,7 +2211,7 @@ function averageSyncDuration() {
|
|||||||
|
|
||||||
function randomNextCheckTime() {
|
function randomNextCheckTime() {
|
||||||
let output = time.unixMs() + 1000 + Math.random() * 1000 * 120;
|
let output = time.unixMs() + 1000 + Math.random() * 1000 * 120;
|
||||||
logger.info('Next sync check: ' + time.unixMsToIso(output) + ' (' + Math.round((output - time.unixMs()) / 1000) + ' sec.)');
|
logger.info(`Next sync check: ${time.unixMsToIso(output)} (${Math.round((output - time.unixMs()) / 1000)} sec.)`);
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2274,7 +2274,7 @@ async function compareClientItems(clientItems) {
|
|||||||
let items = clientItems[i];
|
let items = clientItems[i];
|
||||||
itemCounts.push(items.length);
|
itemCounts.push(items.length);
|
||||||
}
|
}
|
||||||
logger.info('Item count: ' + itemCounts.join(', '));
|
logger.info(`Item count: ${itemCounts.join(', ')}`);
|
||||||
|
|
||||||
let missingItems = findMissingItems(clientItems[0], clientItems[1]);
|
let missingItems = findMissingItems(clientItems[0], clientItems[1]);
|
||||||
if (missingItems[0].length || missingItems[1].length) {
|
if (missingItems[0].length || missingItems[1].length) {
|
||||||
@ -2290,7 +2290,7 @@ async function compareClientItems(clientItems) {
|
|||||||
for (let clientId = 1; clientId < clientItems.length; clientId++) {
|
for (let clientId = 1; clientId < clientItems.length; clientId++) {
|
||||||
let item2 = findItem(clientItems[clientId], item1.id);
|
let item2 = findItem(clientItems[clientId], item1.id);
|
||||||
if (!item2) {
|
if (!item2) {
|
||||||
logger.error('Item not found on client ' + clientId + ':');
|
logger.error(`Item not found on client ${clientId}:`);
|
||||||
logger.error(item1);
|
logger.error(item1);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
@ -2329,12 +2329,12 @@ async function main() {
|
|||||||
|
|
||||||
execRandomCommand(clients[clientId])
|
execRandomCommand(clients[clientId])
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
logger.info('Client ' + clientId + ':');
|
logger.info(`Client ${clientId}:`);
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
})
|
})
|
||||||
.then(r => {
|
.then(r => {
|
||||||
if (r) {
|
if (r) {
|
||||||
logger.info('Client ' + clientId + ':\n' + r.trim());
|
logger.info(`Client ${clientId}:\n${r.trim()}`);
|
||||||
}
|
}
|
||||||
clients[clientId].activeCommandCount--;
|
clients[clientId].activeCommandCount--;
|
||||||
});
|
});
|
||||||
|
@ -26,7 +26,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
} else if (item.type_ === Folder.modelType()) {
|
} else if (item.type_ === Folder.modelType()) {
|
||||||
output.push(' '.repeat(this.folderDepth(this.folders, item.id)) + Folder.displayTitle(item));
|
output.push(' '.repeat(this.folderDepth(this.folders, item.id)) + Folder.displayTitle(item));
|
||||||
} else if (item.type_ === Tag.modelType()) {
|
} else if (item.type_ === Tag.modelType()) {
|
||||||
output.push('[' + Folder.displayTitle(item) + ']');
|
output.push(`[${Folder.displayTitle(item)}]`);
|
||||||
} else if (item.type_ === BaseModel.TYPE_SEARCH) {
|
} else if (item.type_ === BaseModel.TYPE_SEARCH) {
|
||||||
output.push(_('Search:'));
|
output.push(_('Search:'));
|
||||||
output.push(item.title);
|
output.push(item.title);
|
||||||
@ -172,7 +172,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
if (this.notesParentType === 'Folder') return this.selectedFolderId;
|
if (this.notesParentType === 'Folder') return this.selectedFolderId;
|
||||||
if (this.notesParentType === 'Tag') return this.selectedTagId;
|
if (this.notesParentType === 'Tag') return this.selectedTagId;
|
||||||
if (this.notesParentType === 'Search') return this.selectedSearchId;
|
if (this.notesParentType === 'Search') return this.selectedSearchId;
|
||||||
throw new Error('Unknown parent type: ' + this.notesParentType);
|
throw new Error(`Unknown parent type: ${this.notesParentType}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
get selectedJoplinItem() {
|
get selectedJoplinItem() {
|
||||||
|
@ -11,7 +11,7 @@ class NoteListWidget extends ListWidget {
|
|||||||
this.itemRenderer = note => {
|
this.itemRenderer = note => {
|
||||||
let label = Note.displayTitle(note); // + ' ' + note.id;
|
let label = Note.displayTitle(note); // + ' ' + note.id;
|
||||||
if (note.is_todo) {
|
if (note.is_todo) {
|
||||||
label = '[' + (note.todo_completed ? 'X' : ' ') + '] ' + label;
|
label = `[${note.todo_completed ? 'X' : ' '}] ${label}`;
|
||||||
}
|
}
|
||||||
return label;
|
return label;
|
||||||
};
|
};
|
||||||
|
@ -47,7 +47,7 @@ class NoteWidget extends TextWidget {
|
|||||||
if (this.note_ && this.note_.encryption_applied) {
|
if (this.note_ && this.note_.encryption_applied) {
|
||||||
this.text = _('One or more items are currently encrypted and you may need to supply a master password. To do so please type `e2ee decrypt`. If you have already supplied the password, the encrypted items are being decrypted in the background and will be available soon.');
|
this.text = _('One or more items are currently encrypted and you may need to supply a master password. To do so please type `e2ee decrypt`. If you have already supplied the password, the encrypted items are being decrypted in the background and will be available soon.');
|
||||||
} else {
|
} else {
|
||||||
this.text = this.note_ ? this.note_.title + '\n\n' + this.note_.body : '';
|
this.text = this.note_ ? `${this.note_.title}\n\n${this.note_.body}` : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.lastLoadedNoteId_ !== this.noteId_) this.scrollTop = 0;
|
if (this.lastLoadedNoteId_ !== this.noteId_) this.scrollTop = 0;
|
||||||
|
@ -60,7 +60,7 @@ function renderCommandHelp(cmd, width = null) {
|
|||||||
|
|
||||||
if ('value' in md) {
|
if ('value' in md) {
|
||||||
if (md.type === Setting.TYPE_STRING) {
|
if (md.type === Setting.TYPE_STRING) {
|
||||||
defaultString = md.value ? '"' + md.value + '"' : null;
|
defaultString = md.value ? `"${md.value}"` : null;
|
||||||
} else if (md.type === Setting.TYPE_INT) {
|
} else if (md.type === Setting.TYPE_INT) {
|
||||||
defaultString = (md.value ? md.value : 0).toString();
|
defaultString = (md.value ? md.value : 0).toString();
|
||||||
} else if (md.type === Setting.TYPE_BOOL) {
|
} else if (md.type === Setting.TYPE_BOOL) {
|
||||||
|
@ -9,7 +9,7 @@ require('app-module-path').addPath(__dirname);
|
|||||||
const compareVersion = require('compare-version');
|
const compareVersion = require('compare-version');
|
||||||
const nodeVersion = process && process.versions && process.versions.node ? process.versions.node : '0.0.0';
|
const nodeVersion = process && process.versions && process.versions.node ? process.versions.node : '0.0.0';
|
||||||
if (compareVersion(nodeVersion, '8.0.0') < 0) {
|
if (compareVersion(nodeVersion, '8.0.0') < 0) {
|
||||||
console.error('Joplin requires Node 8+. Detected version ' + nodeVersion);
|
console.error(`Joplin requires Node 8+. Detected version ${nodeVersion}`);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class OneDriveApiNodeUtils {
|
|||||||
const port = await netUtils.findAvailablePort(this.possibleOAuthDancePorts(), 0);
|
const port = await netUtils.findAvailablePort(this.possibleOAuthDancePorts(), 0);
|
||||||
if (!port) throw new Error(_('All potential ports are in use - please report the issue at %s', 'https://github.com/laurent22/joplin'));
|
if (!port) throw new Error(_('All potential ports are in use - please report the issue at %s', 'https://github.com/laurent22/joplin'));
|
||||||
|
|
||||||
let authCodeUrl = this.api().authCodeUrl('http://localhost:' + port);
|
let authCodeUrl = this.api().authCodeUrl(`http://localhost:${port}`);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.oauthServer_ = http.createServer();
|
this.oauthServer_ = http.createServer();
|
||||||
@ -80,7 +80,7 @@ class OneDriveApiNodeUtils {
|
|||||||
if (!query.code) return writeResponse(400, '"code" query parameter is missing');
|
if (!query.code) return writeResponse(400, '"code" query parameter is missing');
|
||||||
|
|
||||||
this.api()
|
this.api()
|
||||||
.execTokenRequest(query.code, 'http://localhost:' + port.toString())
|
.execTokenRequest(query.code, `http://localhost:${port.toString()}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
writeResponse(200, _('The application has been authorised - you may now close this browser tab.'));
|
writeResponse(200, _('The application has been authorised - you may now close this browser tab.'));
|
||||||
targetConsole.log('');
|
targetConsole.log('');
|
||||||
@ -114,7 +114,7 @@ class OneDriveApiNodeUtils {
|
|||||||
|
|
||||||
targetConsole.log(_('Please open the following URL in your browser to authenticate the application. The application will create a directory in "Apps/Joplin" and will only read and write files in this directory. It will have no access to any files outside this directory nor to any other personal data. No data will be shared with any third party.'));
|
targetConsole.log(_('Please open the following URL in your browser to authenticate the application. The application will create a directory in "Apps/Joplin" and will only read and write files in this directory. It will have no access to any files outside this directory nor to any other personal data. No data will be shared with any third party.'));
|
||||||
targetConsole.log('');
|
targetConsole.log('');
|
||||||
targetConsole.log('http://127.0.0.1:' + port + '/auth');
|
targetConsole.log(`http://127.0.0.1:${port}/auth`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,22 +27,22 @@ describe('EnexToMd', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should convert from Enex to Markdown', asyncTest(async () => {
|
it('should convert from Enex to Markdown', asyncTest(async () => {
|
||||||
const basePath = __dirname + '/enex_to_md';
|
const basePath = `${__dirname}/enex_to_md`;
|
||||||
const files = await shim.fsDriver().readDirStats(basePath);
|
const files = await shim.fsDriver().readDirStats(basePath);
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
const htmlFilename = files[i].path;
|
const htmlFilename = files[i].path;
|
||||||
if (htmlFilename.indexOf('.html') < 0) continue;
|
if (htmlFilename.indexOf('.html') < 0) continue;
|
||||||
|
|
||||||
const htmlPath = basePath + '/' + htmlFilename;
|
const htmlPath = `${basePath}/${htmlFilename}`;
|
||||||
const mdPath = basePath + '/' + filename(htmlFilename) + '.md';
|
const mdPath = `${basePath}/${filename(htmlFilename)}.md`;
|
||||||
|
|
||||||
// if (htmlFilename !== 'multiline_inner_text.html') continue;
|
// if (htmlFilename !== 'multiline_inner_text.html') continue;
|
||||||
|
|
||||||
const html = await shim.fsDriver().readFile(htmlPath);
|
const html = await shim.fsDriver().readFile(htmlPath);
|
||||||
let expectedMd = await shim.fsDriver().readFile(mdPath);
|
let expectedMd = await shim.fsDriver().readFile(mdPath);
|
||||||
|
|
||||||
let actualMd = await enexXmlToMd('<div>' + html + '</div>', []);
|
let actualMd = await enexXmlToMd(`<div>${html}</div>`, []);
|
||||||
|
|
||||||
if (os.EOL === '\r\n') {
|
if (os.EOL === '\r\n') {
|
||||||
expectedMd = expectedMd.replace(/\r\n/g, '\n');
|
expectedMd = expectedMd.replace(/\r\n/g, '\n');
|
||||||
@ -51,7 +51,7 @@ describe('EnexToMd', function() {
|
|||||||
|
|
||||||
if (actualMd !== expectedMd) {
|
if (actualMd !== expectedMd) {
|
||||||
console.info('');
|
console.info('');
|
||||||
console.info('Error converting file: ' + htmlFilename);
|
console.info(`Error converting file: ${htmlFilename}`);
|
||||||
console.info('--------------------------------- Got:');
|
console.info('--------------------------------- Got:');
|
||||||
console.info(actualMd.split('\n'));
|
console.info(actualMd.split('\n'));
|
||||||
console.info('--------------------------------- Expected:');
|
console.info('--------------------------------- Expected:');
|
||||||
|
@ -28,7 +28,7 @@ describe('HtmlToMd', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should convert from Html to Markdown', asyncTest(async () => {
|
it('should convert from Html to Markdown', asyncTest(async () => {
|
||||||
const basePath = __dirname + '/html_to_md';
|
const basePath = `${__dirname}/html_to_md`;
|
||||||
const files = await shim.fsDriver().readDirStats(basePath);
|
const files = await shim.fsDriver().readDirStats(basePath);
|
||||||
const htmlToMd = new HtmlToMd();
|
const htmlToMd = new HtmlToMd();
|
||||||
|
|
||||||
@ -36,8 +36,8 @@ describe('HtmlToMd', function() {
|
|||||||
const htmlFilename = files[i].path;
|
const htmlFilename = files[i].path;
|
||||||
if (htmlFilename.indexOf('.html') < 0) continue;
|
if (htmlFilename.indexOf('.html') < 0) continue;
|
||||||
|
|
||||||
const htmlPath = basePath + '/' + htmlFilename;
|
const htmlPath = `${basePath}/${htmlFilename}`;
|
||||||
const mdPath = basePath + '/' + filename(htmlFilename) + '.md';
|
const mdPath = `${basePath}/${filename(htmlFilename)}.md`;
|
||||||
|
|
||||||
// if (htmlFilename !== 'table_with_pipe.html') continue;
|
// if (htmlFilename !== 'table_with_pipe.html') continue;
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ describe('HtmlToMd', function() {
|
|||||||
const html = await shim.fsDriver().readFile(htmlPath);
|
const html = await shim.fsDriver().readFile(htmlPath);
|
||||||
let expectedMd = await shim.fsDriver().readFile(mdPath);
|
let expectedMd = await shim.fsDriver().readFile(mdPath);
|
||||||
|
|
||||||
let actualMd = await htmlToMd.parse('<div>' + html + '</div>', htmlToMdOptions);
|
let actualMd = await htmlToMd.parse(`<div>${html}</div>`, htmlToMdOptions);
|
||||||
|
|
||||||
if (os.EOL === '\r\n') {
|
if (os.EOL === '\r\n') {
|
||||||
expectedMd = expectedMd.replace(/\r\n/g, '\n');
|
expectedMd = expectedMd.replace(/\r\n/g, '\n');
|
||||||
@ -63,7 +63,7 @@ describe('HtmlToMd', function() {
|
|||||||
|
|
||||||
if (actualMd !== expectedMd) {
|
if (actualMd !== expectedMd) {
|
||||||
console.info('');
|
console.info('');
|
||||||
console.info('Error converting file: ' + htmlFilename);
|
console.info(`Error converting file: ${htmlFilename}`);
|
||||||
console.info('--------------------------------- Got:');
|
console.info('--------------------------------- Got:');
|
||||||
console.info(actualMd);
|
console.info(actualMd);
|
||||||
console.info('--------------------------------- Raw:');
|
console.info('--------------------------------- Raw:');
|
||||||
|
@ -38,7 +38,7 @@ describe('StringUtils', function() {
|
|||||||
|
|
||||||
const actual = StringUtils.surroundKeywords(keywords, input, prefix, suffix);
|
const actual = StringUtils.surroundKeywords(keywords, input, prefix, suffix);
|
||||||
|
|
||||||
expect(actual).toBe(expected, 'Test case ' + i);
|
expect(actual).toBe(expected, `Test case ${i}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
@ -165,9 +165,9 @@ describe('Encryption', function() {
|
|||||||
masterKey = await MasterKey.save(masterKey);
|
masterKey = await MasterKey.save(masterKey);
|
||||||
await service.loadMasterKey(masterKey, '123456', true);
|
await service.loadMasterKey(masterKey, '123456', true);
|
||||||
|
|
||||||
const sourcePath = __dirname + '/../tests/support/photo.jpg';
|
const sourcePath = `${__dirname}/../tests/support/photo.jpg`;
|
||||||
const encryptedPath = __dirname + '/data/photo.crypted';
|
const encryptedPath = `${__dirname}/data/photo.crypted`;
|
||||||
const decryptedPath = __dirname + '/data/photo.jpg';
|
const decryptedPath = `${__dirname}/data/photo.jpg`;
|
||||||
|
|
||||||
await service.encryptFile(sourcePath, encryptedPath);
|
await service.encryptFile(sourcePath, encryptedPath);
|
||||||
await service.decryptFile(encryptedPath, decryptedPath);
|
await service.decryptFile(encryptedPath, decryptedPath);
|
||||||
|
@ -25,23 +25,23 @@ describe('models_Note', function() {
|
|||||||
it('should find resource and note IDs', asyncTest(async () => {
|
it('should find resource and note IDs', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
let note2 = await Note.save({ title: 'ma deuxième note', body: 'Lien vers première note : ' + Note.markdownTag(note1), parent_id: folder1.id });
|
let note2 = await Note.save({ title: 'ma deuxième note', body: `Lien vers première note : ${Note.markdownTag(note1)}`, parent_id: folder1.id });
|
||||||
|
|
||||||
let items = await Note.linkedItems(note2.body);
|
let items = await Note.linkedItems(note2.body);
|
||||||
expect(items.length).toBe(1);
|
expect(items.length).toBe(1);
|
||||||
expect(items[0].id).toBe(note1.id);
|
expect(items[0].id).toBe(note1.id);
|
||||||
|
|
||||||
await shim.attachFileToNote(note2, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note2, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
note2 = await Note.load(note2.id);
|
note2 = await Note.load(note2.id);
|
||||||
items = await Note.linkedItems(note2.body);
|
items = await Note.linkedItems(note2.body);
|
||||||
expect(items.length).toBe(2);
|
expect(items.length).toBe(2);
|
||||||
expect(items[0].type_).toBe(BaseModel.TYPE_NOTE);
|
expect(items[0].type_).toBe(BaseModel.TYPE_NOTE);
|
||||||
expect(items[1].type_).toBe(BaseModel.TYPE_RESOURCE);
|
expect(items[1].type_).toBe(BaseModel.TYPE_RESOURCE);
|
||||||
|
|
||||||
const resource2 = await shim.createResourceFromPath(__dirname + '/../tests/support/photo.jpg');
|
const resource2 = await shim.createResourceFromPath(`${__dirname}/../tests/support/photo.jpg`);
|
||||||
const resource3 = await shim.createResourceFromPath(__dirname + '/../tests/support/photo.jpg');
|
const resource3 = await shim.createResourceFromPath(`${__dirname}/../tests/support/photo.jpg`);
|
||||||
note2.body += '<img alt="bla" src=":/' + resource2.id + '"/>';
|
note2.body += `<img alt="bla" src=":/${resource2.id}"/>`;
|
||||||
note2.body += '<img src=\':/' + resource3.id + '\' />';
|
note2.body += `<img src=':/${resource3.id}' />`;
|
||||||
items = await Note.linkedItems(note2.body);
|
items = await Note.linkedItems(note2.body);
|
||||||
expect(items.length).toBe(4);
|
expect(items.length).toBe(4);
|
||||||
}));
|
}));
|
||||||
|
@ -16,7 +16,7 @@ process.on('unhandledRejection', (reason, p) => {
|
|||||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||||
});
|
});
|
||||||
|
|
||||||
const testImagePath = __dirname + '/../tests/support/photo.jpg';
|
const testImagePath = `${__dirname}/../tests/support/photo.jpg`;
|
||||||
|
|
||||||
describe('models_Resource', function() {
|
describe('models_Resource', function() {
|
||||||
|
|
||||||
|
@ -22,13 +22,13 @@ process.on('unhandledRejection', (reason, p) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function exportDir() {
|
function exportDir() {
|
||||||
return __dirname + '/export';
|
return `${__dirname}/export`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fieldsEqual(model1, model2, fieldNames) {
|
function fieldsEqual(model1, model2, fieldNames) {
|
||||||
for (let i = 0; i < fieldNames.length; i++) {
|
for (let i = 0; i < fieldNames.length; i++) {
|
||||||
const f = fieldNames[i];
|
const f = fieldNames[i];
|
||||||
expect(model1[f]).toBe(model2[f], 'For key ' + f);
|
expect(model1[f]).toBe(model2[f], `For key ${f}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ describe('services_InteropService', function() {
|
|||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
folder1 = await Folder.load(folder1.id);
|
folder1 = await Folder.load(folder1.id);
|
||||||
const filePath = exportDir() + '/test.jex';
|
const filePath = `${exportDir()}/test.jex`;
|
||||||
|
|
||||||
await service.export({ path: filePath });
|
await service.export({ path: filePath });
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ describe('services_InteropService', function() {
|
|||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
note1 = await Note.load(note1.id);
|
note1 = await Note.load(note1.id);
|
||||||
const filePath = exportDir() + '/test.jex';
|
const filePath = `${exportDir()}/test.jex`;
|
||||||
|
|
||||||
await service.export({ path: filePath });
|
await service.export({ path: filePath });
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ describe('services_InteropService', function() {
|
|||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
note1 = await Note.load(note1.id);
|
note1 = await Note.load(note1.id);
|
||||||
const filePath = exportDir() + '/test.jex';
|
const filePath = `${exportDir()}/test.jex`;
|
||||||
|
|
||||||
await service.export({ path: filePath });
|
await service.export({ path: filePath });
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ describe('services_InteropService', function() {
|
|||||||
|
|
||||||
it('should export and import tags', asyncTest(async () => {
|
it('should export and import tags', asyncTest(async () => {
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
const filePath = exportDir() + '/test.jex';
|
const filePath = `${exportDir()}/test.jex`;
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
let tag1 = await Tag.save({ title: 'mon tag' });
|
let tag1 = await Tag.save({ title: 'mon tag' });
|
||||||
@ -179,10 +179,10 @@ describe('services_InteropService', function() {
|
|||||||
|
|
||||||
it('should export and import resources', asyncTest(async () => {
|
it('should export and import resources', asyncTest(async () => {
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
const filePath = exportDir() + '/test.jex';
|
const filePath = `${exportDir()}/test.jex`;
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
note1 = await Note.load(note1.id);
|
note1 = await Note.load(note1.id);
|
||||||
let resourceIds = await Note.linkedResourceIds(note1.body);
|
let resourceIds = await Note.linkedResourceIds(note1.body);
|
||||||
let resource1 = await Resource.load(resourceIds[0]);
|
let resource1 = await Resource.load(resourceIds[0]);
|
||||||
@ -215,7 +215,7 @@ describe('services_InteropService', function() {
|
|||||||
|
|
||||||
it('should export and import single notes', asyncTest(async () => {
|
it('should export and import single notes', asyncTest(async () => {
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
const filePath = exportDir() + '/test.jex';
|
const filePath = `${exportDir()}/test.jex`;
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
|
|
||||||
@ -235,7 +235,7 @@ describe('services_InteropService', function() {
|
|||||||
|
|
||||||
it('should export and import single folders', asyncTest(async () => {
|
it('should export and import single folders', asyncTest(async () => {
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
const filePath = exportDir() + '/test.jex';
|
const filePath = `${exportDir()}/test.jex`;
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
|
|
||||||
@ -256,7 +256,7 @@ describe('services_InteropService', function() {
|
|||||||
it('should export and import folder and its sub-folders', asyncTest(async () => {
|
it('should export and import folder and its sub-folders', asyncTest(async () => {
|
||||||
|
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
const filePath = exportDir() + '/test.jex';
|
const filePath = `${exportDir()}/test.jex`;
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let folder2 = await Folder.save({ title: 'folder2', parent_id: folder1.id });
|
let folder2 = await Folder.save({ title: 'folder2', parent_id: folder1.id });
|
||||||
let folder3 = await Folder.save({ title: 'folder3', parent_id: folder2.id });
|
let folder3 = await Folder.save({ title: 'folder3', parent_id: folder2.id });
|
||||||
@ -290,10 +290,10 @@ describe('services_InteropService', function() {
|
|||||||
|
|
||||||
it('should export and import links to notes', asyncTest(async () => {
|
it('should export and import links to notes', asyncTest(async () => {
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
const filePath = exportDir() + '/test.jex';
|
const filePath = `${exportDir()}/test.jex`;
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
let note2 = await Note.save({ title: 'ma deuxième note', body: 'Lien vers première note : ' + Note.markdownTag(note1), parent_id: folder1.id });
|
let note2 = await Note.save({ title: 'ma deuxième note', body: `Lien vers première note : ${Note.markdownTag(note1)}`, parent_id: folder1.id });
|
||||||
|
|
||||||
await service.export({ path: filePath, sourceFolderIds: [folder1.id] });
|
await service.export({ path: filePath, sourceFolderIds: [folder1.id] });
|
||||||
|
|
||||||
@ -324,7 +324,7 @@ describe('services_InteropService', function() {
|
|||||||
// verify that the json files exist and can be parsed
|
// verify that the json files exist and can be parsed
|
||||||
const items = [folder1, note1];
|
const items = [folder1, note1];
|
||||||
for (let i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
const jsonFile = filePath + '/' + items[i].id + '.json';
|
const jsonFile = `${filePath}/${items[i].id}.json`;
|
||||||
let json = await fs.readFile(jsonFile, 'utf-8');
|
let json = await fs.readFile(jsonFile, 'utf-8');
|
||||||
let obj = JSON.parse(json);
|
let obj = JSON.parse(json);
|
||||||
expect(obj.id).toBe(items[i].id);
|
expect(obj.id).toBe(items[i].id);
|
||||||
@ -350,13 +350,13 @@ describe('services_InteropService', function() {
|
|||||||
|
|
||||||
await service.export({ path: outDir, format: 'md' });
|
await service.export({ path: outDir, format: 'md' });
|
||||||
|
|
||||||
expect(await shim.fsDriver().exists(outDir + '/folder1/生活.md')).toBe(true);
|
expect(await shim.fsDriver().exists(`${outDir}/folder1/生活.md`)).toBe(true);
|
||||||
expect(await shim.fsDriver().exists(outDir + '/folder1/生活 (1).md')).toBe(true);
|
expect(await shim.fsDriver().exists(`${outDir}/folder1/生活 (1).md`)).toBe(true);
|
||||||
expect(await shim.fsDriver().exists(outDir + '/folder1/生活 (2).md')).toBe(true);
|
expect(await shim.fsDriver().exists(`${outDir}/folder1/生活 (2).md`)).toBe(true);
|
||||||
expect(await shim.fsDriver().exists(outDir + '/folder1/Untitled.md')).toBe(true);
|
expect(await shim.fsDriver().exists(`${outDir}/folder1/Untitled.md`)).toBe(true);
|
||||||
expect(await shim.fsDriver().exists(outDir + '/folder1/Untitled (1).md')).toBe(true);
|
expect(await shim.fsDriver().exists(`${outDir}/folder1/Untitled (1).md`)).toBe(true);
|
||||||
expect(await shim.fsDriver().exists(outDir + '/folder1/salut, ça roule _.md')).toBe(true);
|
expect(await shim.fsDriver().exists(`${outDir}/folder1/salut, ça roule _.md`)).toBe(true);
|
||||||
expect(await shim.fsDriver().exists(outDir + '/ジョプリン/ジョプリン.md')).toBe(true);
|
expect(await shim.fsDriver().exists(`${outDir}/ジョプリン/ジョプリン.md`)).toBe(true);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -26,13 +26,13 @@ process.on('unhandledRejection', (reason, p) => {
|
|||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
|
||||||
|
|
||||||
function exportDir() {
|
function exportDir() {
|
||||||
return __dirname + '/export';
|
return `${__dirname}/export`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fieldsEqual(model1, model2, fieldNames) {
|
function fieldsEqual(model1, model2, fieldNames) {
|
||||||
for (let i = 0; i < fieldNames.length; i++) {
|
for (let i = 0; i < fieldNames.length; i++) {
|
||||||
const f = fieldNames[i];
|
const f = fieldNames[i];
|
||||||
expect(model1[f]).toBe(model2[f], 'For key ' + f);
|
expect(model1[f]).toBe(model2[f], `For key ${f}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ describe('services_ResourceService', function() {
|
|||||||
|
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
note1 = await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
note1 = await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
let resource1 = (await Resource.all())[0];
|
let resource1 = (await Resource.all())[0];
|
||||||
const resourcePath = Resource.fullPath(resource1);
|
const resourcePath = Resource.fullPath(resource1);
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ describe('services_ResourceService', function() {
|
|||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
let note2 = await Note.save({ title: 'ma deuxième note', parent_id: folder1.id });
|
let note2 = await Note.save({ title: 'ma deuxième note', parent_id: folder1.id });
|
||||||
note1 = await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
note1 = await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
let resource1 = (await Resource.all())[0];
|
let resource1 = (await Resource.all())[0];
|
||||||
|
|
||||||
await service.indexNoteResources();
|
await service.indexNoteResources();
|
||||||
@ -102,7 +102,7 @@ describe('services_ResourceService', function() {
|
|||||||
|
|
||||||
it('should not delete a resource that has never been associated with any note, because it probably means the resource came via sync, and associated note has not arrived yet', asyncTest(async () => {
|
it('should not delete a resource that has never been associated with any note, because it probably means the resource came via sync, and associated note has not arrived yet', asyncTest(async () => {
|
||||||
const service = new ResourceService();
|
const service = new ResourceService();
|
||||||
const resource = await shim.createResourceFromPath(__dirname + '/../tests/support/photo.jpg');
|
const resource = await shim.createResourceFromPath(`${__dirname}/../tests/support/photo.jpg`);
|
||||||
|
|
||||||
await service.indexNoteResources();
|
await service.indexNoteResources();
|
||||||
await service.deleteOrphanResources(0);
|
await service.deleteOrphanResources(0);
|
||||||
@ -115,12 +115,12 @@ describe('services_ResourceService', function() {
|
|||||||
|
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
note1 = await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
note1 = await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
let resource1 = (await Resource.all())[0];
|
let resource1 = (await Resource.all())[0];
|
||||||
|
|
||||||
await service.indexNoteResources();
|
await service.indexNoteResources();
|
||||||
|
|
||||||
await Note.save({ id: note1.id, body: 'This is HTML: <img src=":/' + resource1.id + '"/>' });
|
await Note.save({ id: note1.id, body: `This is HTML: <img src=":/${resource1.id}"/>` });
|
||||||
|
|
||||||
await service.indexNoteResources();
|
await service.indexNoteResources();
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ describe('services_ResourceService', function() {
|
|||||||
|
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
note1 = await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
note1 = await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
let resource1 = (await Resource.all())[0];
|
let resource1 = (await Resource.all())[0];
|
||||||
|
|
||||||
await service.indexNoteResources();
|
await service.indexNoteResources();
|
||||||
@ -171,7 +171,7 @@ describe('services_ResourceService', function() {
|
|||||||
await encryptionService().loadMasterKeysFromSettings();
|
await encryptionService().loadMasterKeysFromSettings();
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg'); // R1
|
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`); // R1
|
||||||
await resourceService().indexNoteResources();
|
await resourceService().indexNoteResources();
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
expect(await allSyncTargetItemsEncrypted()).toBe(true);
|
expect(await allSyncTargetItemsEncrypted()).toBe(true);
|
||||||
@ -184,7 +184,7 @@ describe('services_ResourceService', function() {
|
|||||||
await decryptionWorker().start();
|
await decryptionWorker().start();
|
||||||
{
|
{
|
||||||
const n1 = await Note.load(note1.id);
|
const n1 = await Note.load(note1.id);
|
||||||
await shim.attachFileToNote(n1, __dirname + '/../tests/support/photo.jpg'); // R2
|
await shim.attachFileToNote(n1, `${__dirname}/../tests/support/photo.jpg`); // R2
|
||||||
}
|
}
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
@ -201,7 +201,7 @@ describe('services_ResourceService', function() {
|
|||||||
|
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
note1 = await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
note1 = await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
await resourceService().indexNoteResources();
|
await resourceService().indexNoteResources();
|
||||||
const bodyWithResource = note1.body;
|
const bodyWithResource = note1.body;
|
||||||
await Note.save({ id: note1.id, body: '' });
|
await Note.save({ id: note1.id, body: '' });
|
||||||
|
@ -297,9 +297,9 @@ describe('services_SearchEngine', function() {
|
|||||||
const titleValues = actual.terms.title ? actual.terms.title.map(v => v.value) : undefined;
|
const titleValues = actual.terms.title ? actual.terms.title.map(v => v.value) : undefined;
|
||||||
const bodyValues = actual.terms.body ? actual.terms.body.map(v => v.value) : undefined;
|
const bodyValues = actual.terms.body ? actual.terms.body.map(v => v.value) : undefined;
|
||||||
|
|
||||||
expect(JSON.stringify(_Values)).toBe(JSON.stringify(expected._), 'Test case (_) ' + i);
|
expect(JSON.stringify(_Values)).toBe(JSON.stringify(expected._), `Test case (_) ${i}`);
|
||||||
expect(JSON.stringify(titleValues)).toBe(JSON.stringify(expected.title), 'Test case (title) ' + i);
|
expect(JSON.stringify(titleValues)).toBe(JSON.stringify(expected.title), `Test case (title) ${i}`);
|
||||||
expect(JSON.stringify(bodyValues)).toBe(JSON.stringify(expected.body), 'Test case (body) ' + i);
|
expect(JSON.stringify(bodyValues)).toBe(JSON.stringify(expected.body), `Test case (body) ${i}`);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ describe('services_rest_Api', function() {
|
|||||||
|
|
||||||
it('should update folders', async (done) => {
|
it('should update folders', async (done) => {
|
||||||
let f1 = await Folder.save({ title: 'mon carnet' });
|
let f1 = await Folder.save({ title: 'mon carnet' });
|
||||||
const response = await api.route('PUT', 'folders/' + f1.id, null, JSON.stringify({
|
const response = await api.route('PUT', `folders/${f1.id}`, null, JSON.stringify({
|
||||||
title: 'modifié',
|
title: 'modifié',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ describe('services_rest_Api', function() {
|
|||||||
|
|
||||||
it('should delete folders', async (done) => {
|
it('should delete folders', async (done) => {
|
||||||
let f1 = await Folder.save({ title: 'mon carnet' });
|
let f1 = await Folder.save({ title: 'mon carnet' });
|
||||||
await api.route('DELETE', 'folders/' + f1.id);
|
await api.route('DELETE', `folders/${f1.id}`);
|
||||||
|
|
||||||
let f1b = await Folder.load(f1.id);
|
let f1b = await Folder.load(f1.id);
|
||||||
expect(!f1b).toBe(true);
|
expect(!f1b).toBe(true);
|
||||||
@ -87,7 +87,7 @@ describe('services_rest_Api', function() {
|
|||||||
|
|
||||||
it('should get one folder', async (done) => {
|
it('should get one folder', async (done) => {
|
||||||
let f1 = await Folder.save({ title: 'mon carnet' });
|
let f1 = await Folder.save({ title: 'mon carnet' });
|
||||||
const response = await api.route('GET', 'folders/' + f1.id);
|
const response = await api.route('GET', `folders/${f1.id}`);
|
||||||
expect(response.id).toBe(f1.id);
|
expect(response.id).toBe(f1.id);
|
||||||
|
|
||||||
const hasThrown = await checkThrowAsync(async () => await api.route('GET', 'folders/doesntexist'));
|
const hasThrown = await checkThrowAsync(async () => await api.route('GET', 'folders/doesntexist'));
|
||||||
@ -98,12 +98,12 @@ describe('services_rest_Api', function() {
|
|||||||
|
|
||||||
it('should get the folder notes', async (done) => {
|
it('should get the folder notes', async (done) => {
|
||||||
let f1 = await Folder.save({ title: 'mon carnet' });
|
let f1 = await Folder.save({ title: 'mon carnet' });
|
||||||
const response2 = await api.route('GET', 'folders/' + f1.id + '/notes');
|
const response2 = await api.route('GET', `folders/${f1.id}/notes`);
|
||||||
expect(response2.length).toBe(0);
|
expect(response2.length).toBe(0);
|
||||||
|
|
||||||
const n1 = await Note.save({ title: 'un', parent_id: f1.id });
|
const n1 = await Note.save({ title: 'un', parent_id: f1.id });
|
||||||
const n2 = await Note.save({ title: 'deux', parent_id: f1.id });
|
const n2 = await Note.save({ title: 'deux', parent_id: f1.id });
|
||||||
const response = await api.route('GET', 'folders/' + f1.id + '/notes');
|
const response = await api.route('GET', `folders/${f1.id}/notes`);
|
||||||
expect(response.length).toBe(2);
|
expect(response.length).toBe(2);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
@ -127,10 +127,10 @@ describe('services_rest_Api', function() {
|
|||||||
response = await api.route('GET', 'notes');
|
response = await api.route('GET', 'notes');
|
||||||
expect(response.length).toBe(3);
|
expect(response.length).toBe(3);
|
||||||
|
|
||||||
response = await api.route('GET', 'notes/' + n1.id);
|
response = await api.route('GET', `notes/${n1.id}`);
|
||||||
expect(response.id).toBe(n1.id);
|
expect(response.id).toBe(n1.id);
|
||||||
|
|
||||||
response = await api.route('GET', 'notes/' + n3.id, { fields: 'id,title' });
|
response = await api.route('GET', `notes/${n3.id}`, { fields: 'id,title' });
|
||||||
expect(Object.getOwnPropertyNames(response).length).toBe(3);
|
expect(Object.getOwnPropertyNames(response).length).toBe(3);
|
||||||
expect(response.id).toBe(n3.id);
|
expect(response.id).toBe(n3.id);
|
||||||
expect(response.title).toBe('trois');
|
expect(response.title).toBe('trois');
|
||||||
@ -270,7 +270,7 @@ describe('services_rest_Api', function() {
|
|||||||
const filePath = Resource.fullPath(resource);
|
const filePath = Resource.fullPath(resource);
|
||||||
expect(await shim.fsDriver().exists(filePath)).toBe(true);
|
expect(await shim.fsDriver().exists(filePath)).toBe(true);
|
||||||
|
|
||||||
await api.route('DELETE', 'resources/' + resource.id);
|
await api.route('DELETE', `resources/${resource.id}`);
|
||||||
expect(await shim.fsDriver().exists(filePath)).toBe(false);
|
expect(await shim.fsDriver().exists(filePath)).toBe(false);
|
||||||
expect(!(await Resource.load(resource.id))).toBe(true);
|
expect(!(await Resource.load(resource.id))).toBe(true);
|
||||||
|
|
||||||
@ -329,7 +329,7 @@ describe('services_rest_Api', function() {
|
|||||||
const tag = await Tag.save({ title: 'mon étiquette' });
|
const tag = await Tag.save({ title: 'mon étiquette' });
|
||||||
const note = await Note.save({ title: 'ma note' });
|
const note = await Note.save({ title: 'ma note' });
|
||||||
|
|
||||||
const response = await api.route('POST', 'tags/' + tag.id + '/notes', null, JSON.stringify({
|
const response = await api.route('POST', `tags/${tag.id}/notes`, null, JSON.stringify({
|
||||||
id: note.id,
|
id: note.id,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -344,7 +344,7 @@ describe('services_rest_Api', function() {
|
|||||||
const note = await Note.save({ title: 'ma note' });
|
const note = await Note.save({ title: 'ma note' });
|
||||||
await Tag.addNote(tag.id, note.id);
|
await Tag.addNote(tag.id, note.id);
|
||||||
|
|
||||||
const response = await api.route('DELETE', 'tags/' + tag.id + '/notes/' + note.id);
|
const response = await api.route('DELETE', `tags/${tag.id}/notes/${note.id}`);
|
||||||
|
|
||||||
const noteIds = await Tag.noteIds(tag.id);
|
const noteIds = await Tag.noteIds(tag.id);
|
||||||
expect(noteIds.length).toBe(0);
|
expect(noteIds.length).toBe(0);
|
||||||
@ -360,15 +360,15 @@ describe('services_rest_Api', function() {
|
|||||||
await Tag.addNote(tag.id, note1.id);
|
await Tag.addNote(tag.id, note1.id);
|
||||||
await Tag.addNote(tag.id, note2.id);
|
await Tag.addNote(tag.id, note2.id);
|
||||||
|
|
||||||
const response = await api.route('GET', 'tags/' + tag.id + '/notes');
|
const response = await api.route('GET', `tags/${tag.id}/notes`);
|
||||||
expect(response.length).toBe(2);
|
expect(response.length).toBe(2);
|
||||||
expect('id' in response[0]).toBe(true);
|
expect('id' in response[0]).toBe(true);
|
||||||
expect('title' in response[0]).toBe(true);
|
expect('title' in response[0]).toBe(true);
|
||||||
|
|
||||||
const response2 = await api.route('GET', 'notes/' + note1.id + '/tags');
|
const response2 = await api.route('GET', `notes/${note1.id}/tags`);
|
||||||
expect(response2.length).toBe(1);
|
expect(response2.length).toBe(1);
|
||||||
await Tag.addNote(tag2.id, note1.id);
|
await Tag.addNote(tag2.id, note1.id);
|
||||||
const response3 = await api.route('GET', 'notes/' + note1.id + '/tags');
|
const response3 = await api.route('GET', `notes/${note1.id}/tags`);
|
||||||
expect(response3.length).toBe(2);
|
expect(response3.length).toBe(2);
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
@ -196,13 +196,13 @@ describe('Synchronizer', function() {
|
|||||||
for (let n in conflictedNote) {
|
for (let n in conflictedNote) {
|
||||||
if (!conflictedNote.hasOwnProperty(n)) continue;
|
if (!conflictedNote.hasOwnProperty(n)) continue;
|
||||||
if (n == 'id' || n == 'is_conflict') continue;
|
if (n == 'id' || n == 'is_conflict') continue;
|
||||||
expect(conflictedNote[n]).toBe(note2conf[n], 'Property: ' + n);
|
expect(conflictedNote[n]).toBe(note2conf[n], `Property: ${n}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let noteUpdatedFromRemote = await Note.load(note1.id);
|
let noteUpdatedFromRemote = await Note.load(note1.id);
|
||||||
for (let n in noteUpdatedFromRemote) {
|
for (let n in noteUpdatedFromRemote) {
|
||||||
if (!noteUpdatedFromRemote.hasOwnProperty(n)) continue;
|
if (!noteUpdatedFromRemote.hasOwnProperty(n)) continue;
|
||||||
expect(noteUpdatedFromRemote[n]).toBe(note2[n], 'Property: ' + n);
|
expect(noteUpdatedFromRemote[n]).toBe(note2[n], `Property: ${n}`);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -850,7 +850,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
let resource1 = (await Resource.all())[0];
|
let resource1 = (await Resource.all())[0];
|
||||||
let resourcePath1 = Resource.fullPath(resource1);
|
let resourcePath1 = Resource.fullPath(resource1);
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
@ -883,7 +883,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
let resource1 = (await Resource.all())[0];
|
let resource1 = (await Resource.all())[0];
|
||||||
let resourcePath1 = Resource.fullPath(resource1);
|
let resourcePath1 = Resource.fullPath(resource1);
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
@ -910,7 +910,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@ -933,7 +933,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
let resource1 = (await Resource.all())[0];
|
let resource1 = (await Resource.all())[0];
|
||||||
let resourcePath1 = Resource.fullPath(resource1);
|
let resourcePath1 = Resource.fullPath(resource1);
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
@ -949,7 +949,7 @@ describe('Synchronizer', function() {
|
|||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
expect((await remoteNotesFoldersResources()).length).toBe(2);
|
expect((await remoteNotesFoldersResources()).length).toBe(2);
|
||||||
|
|
||||||
const remoteBlob = await fileApi().stat('.resource/' + resource1.id);
|
const remoteBlob = await fileApi().stat(`.resource/${resource1.id}`);
|
||||||
expect(!remoteBlob).toBe(true);
|
expect(!remoteBlob).toBe(true);
|
||||||
|
|
||||||
await switchClient(1);
|
await switchClient(1);
|
||||||
@ -967,7 +967,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
let resource1 = (await Resource.all())[0];
|
let resource1 = (await Resource.all())[0];
|
||||||
let resourcePath1 = Resource.fullPath(resource1);
|
let resourcePath1 = Resource.fullPath(resource1);
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
@ -1049,7 +1049,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
let resource1 = (await Resource.all())[0];
|
let resource1 = (await Resource.all())[0];
|
||||||
await Resource.setFileSizeOnly(resource1.id, -1);
|
await Resource.setFileSizeOnly(resource1.id, -1);
|
||||||
let resourcePath1 = Resource.fullPath(resource1);
|
let resourcePath1 = Resource.fullPath(resource1);
|
||||||
@ -1075,7 +1075,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
expect(await allSyncTargetItemsEncrypted()).toBe(false);
|
expect(await allSyncTargetItemsEncrypted()).toBe(false);
|
||||||
@ -1094,7 +1094,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
let folder1 = await Folder.save({ title: 'folder1' });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder1.id });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
const masterKey = await loadEncryptionMasterKey();
|
const masterKey = await loadEncryptionMasterKey();
|
||||||
await encryptionService().enableEncryption(masterKey, '123456');
|
await encryptionService().enableEncryption(masterKey, '123456');
|
||||||
await encryptionService().loadMasterKeysFromSettings();
|
await encryptionService().loadMasterKeysFromSettings();
|
||||||
@ -1307,7 +1307,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
it('should not download resources over the limit', asyncTest(async () => {
|
it('should not download resources over the limit', asyncTest(async () => {
|
||||||
const note1 = await Note.save({ title: 'note' });
|
const note1 = await Note.save({ title: 'note' });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@ -1337,7 +1337,7 @@ describe('Synchronizer', function() {
|
|||||||
// does get uploaded.
|
// does get uploaded.
|
||||||
|
|
||||||
const note1 = await Note.save({ title: 'note' });
|
const note1 = await Note.save({ title: 'note' });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
const resource = (await Resource.all())[0];
|
const resource = (await Resource.all())[0];
|
||||||
await Resource.setLocalState(resource.id, { fetch_status: Resource.FETCH_STATUS_IDLE });
|
await Resource.setLocalState(resource.id, { fetch_status: Resource.FETCH_STATUS_IDLE });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
@ -1352,7 +1352,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
it('should decrypt the resource metadata, but not try to decrypt the file, if it is not present', asyncTest(async () => {
|
it('should decrypt the resource metadata, but not try to decrypt the file, if it is not present', asyncTest(async () => {
|
||||||
const note1 = await Note.save({ title: 'note' });
|
const note1 = await Note.save({ title: 'note' });
|
||||||
await shim.attachFileToNote(note1, __dirname + '/../tests/support/photo.jpg');
|
await shim.attachFileToNote(note1, `${__dirname}/../tests/support/photo.jpg`);
|
||||||
const masterKey = await loadEncryptionMasterKey();
|
const masterKey = await loadEncryptionMasterKey();
|
||||||
await encryptionService().enableEncryption(masterKey, '123456');
|
await encryptionService().enableEncryption(masterKey, '123456');
|
||||||
await encryptionService().loadMasterKeysFromSettings();
|
await encryptionService().loadMasterKeysFromSettings();
|
||||||
|
@ -56,8 +56,8 @@ Resource.fsDriver_ = fsDriver;
|
|||||||
EncryptionService.fsDriver_ = fsDriver;
|
EncryptionService.fsDriver_ = fsDriver;
|
||||||
FileApiDriverLocal.fsDriver_ = fsDriver;
|
FileApiDriverLocal.fsDriver_ = fsDriver;
|
||||||
|
|
||||||
const logDir = __dirname + '/../tests/logs';
|
const logDir = `${__dirname}/../tests/logs`;
|
||||||
const tempDir = __dirname + '/../tests/tmp';
|
const tempDir = `${__dirname}/../tests/tmp`;
|
||||||
fs.mkdirpSync(logDir, 0o755);
|
fs.mkdirpSync(logDir, 0o755);
|
||||||
fs.mkdirpSync(tempDir, 0o755);
|
fs.mkdirpSync(tempDir, 0o755);
|
||||||
|
|
||||||
@ -71,20 +71,20 @@ SyncTargetRegistry.addClass(SyncTargetDropbox);
|
|||||||
const syncTargetId_ = SyncTargetRegistry.nameToId('memory');
|
const syncTargetId_ = SyncTargetRegistry.nameToId('memory');
|
||||||
//const syncTargetId_ = SyncTargetRegistry.nameToId('filesystem');
|
//const syncTargetId_ = SyncTargetRegistry.nameToId('filesystem');
|
||||||
// const syncTargetId_ = SyncTargetRegistry.nameToId('dropbox');
|
// const syncTargetId_ = SyncTargetRegistry.nameToId('dropbox');
|
||||||
const syncDir = __dirname + '/../tests/sync';
|
const syncDir = `${__dirname}/../tests/sync`;
|
||||||
|
|
||||||
const sleepTime = syncTargetId_ == SyncTargetRegistry.nameToId('filesystem') ? 1001 : 100;//400;
|
const sleepTime = syncTargetId_ == SyncTargetRegistry.nameToId('filesystem') ? 1001 : 100;//400;
|
||||||
|
|
||||||
console.info('Testing with sync target: ' + SyncTargetRegistry.idToName(syncTargetId_));
|
console.info(`Testing with sync target: ${SyncTargetRegistry.idToName(syncTargetId_)}`);
|
||||||
|
|
||||||
const dbLogger = new Logger();
|
const dbLogger = new Logger();
|
||||||
dbLogger.addTarget('console');
|
dbLogger.addTarget('console');
|
||||||
dbLogger.addTarget('file', { path: logDir + '/log.txt' });
|
dbLogger.addTarget('file', { path: `${logDir}/log.txt` });
|
||||||
dbLogger.setLevel(Logger.LEVEL_WARN);
|
dbLogger.setLevel(Logger.LEVEL_WARN);
|
||||||
|
|
||||||
const logger = new Logger();
|
const logger = new Logger();
|
||||||
logger.addTarget('console');
|
logger.addTarget('console');
|
||||||
logger.addTarget('file', { path: logDir + '/log.txt' });
|
logger.addTarget('file', { path: `${logDir}/log.txt` });
|
||||||
logger.setLevel(Logger.LEVEL_WARN); // Set to DEBUG to display sync process in console
|
logger.setLevel(Logger.LEVEL_WARN); // Set to DEBUG to display sync process in console
|
||||||
|
|
||||||
BaseItem.loadClass('Note', Note);
|
BaseItem.loadClass('Note', Note);
|
||||||
@ -116,7 +116,7 @@ function sleep(n) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function switchClient(id) {
|
async function switchClient(id) {
|
||||||
if (!databases_[id]) throw new Error('Call setupDatabaseAndSynchronizer(' + id + ') first!!');
|
if (!databases_[id]) throw new Error(`Call setupDatabaseAndSynchronizer(${id}) first!!`);
|
||||||
|
|
||||||
await time.msleep(sleepTime); // Always leave a little time so that updated_time properties don't overlap
|
await time.msleep(sleepTime); // Always leave a little time so that updated_time properties don't overlap
|
||||||
await Setting.saveAll();
|
await Setting.saveAll();
|
||||||
@ -162,8 +162,8 @@ async function clearDatabase(id = null) {
|
|||||||
|
|
||||||
const queries = [];
|
const queries = [];
|
||||||
for (const n of tableNames) {
|
for (const n of tableNames) {
|
||||||
queries.push('DELETE FROM ' + n);
|
queries.push(`DELETE FROM ${n}`);
|
||||||
queries.push('DELETE FROM sqlite_sequence WHERE name="' + n + '"'); // Reset autoincremented IDs
|
queries.push(`DELETE FROM sqlite_sequence WHERE name="${n}"`); // Reset autoincremented IDs
|
||||||
}
|
}
|
||||||
|
|
||||||
await databases_[id].transactionExecBatch(queries);
|
await databases_[id].transactionExecBatch(queries);
|
||||||
@ -181,7 +181,7 @@ async function setupDatabase(id = null) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filePath = __dirname + '/data/test-' + id + '.sqlite';
|
const filePath = `${__dirname}/data/test-${id}.sqlite`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fs.unlink(filePath);
|
await fs.unlink(filePath);
|
||||||
@ -199,7 +199,7 @@ async function setupDatabase(id = null) {
|
|||||||
|
|
||||||
function resourceDir(id = null) {
|
function resourceDir(id = null) {
|
||||||
if (id === null) id = currentClient_;
|
if (id === null) id = currentClient_;
|
||||||
return __dirname + '/data/resources-' + id;
|
return `${__dirname}/data/resources-${id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setupDatabaseAndSynchronizer(id = null) {
|
async function setupDatabaseAndSynchronizer(id = null) {
|
||||||
@ -310,9 +310,9 @@ function fileApi() {
|
|||||||
fileApi_ = new FileApi('', new FileApiDriverWebDav(api));
|
fileApi_ = new FileApi('', new FileApiDriverWebDav(api));
|
||||||
} else if (syncTargetId_ == SyncTargetRegistry.nameToId('dropbox')) {
|
} else if (syncTargetId_ == SyncTargetRegistry.nameToId('dropbox')) {
|
||||||
const api = new DropboxApi();
|
const api = new DropboxApi();
|
||||||
const authTokenPath = __dirname + '/support/dropbox-auth.txt';
|
const authTokenPath = `${__dirname}/support/dropbox-auth.txt`;
|
||||||
const authToken = fs.readFileSync(authTokenPath, 'utf8');
|
const authToken = fs.readFileSync(authTokenPath, 'utf8');
|
||||||
if (!authToken) throw new Error('Dropbox auth token missing in ' + authTokenPath);
|
if (!authToken) throw new Error(`Dropbox auth token missing in ${authTokenPath}`);
|
||||||
api.setAuthToken(authToken);
|
api.setAuthToken(authToken);
|
||||||
fileApi_ = new FileApi('', new FileApiDriverDropbox(api));
|
fileApi_ = new FileApi('', new FileApiDriverDropbox(api));
|
||||||
}
|
}
|
||||||
@ -380,7 +380,7 @@ async function allSyncTargetItemsEncrypted() {
|
|||||||
totalCount++;
|
totalCount++;
|
||||||
|
|
||||||
if (remoteContent.type_ === BaseModel.TYPE_RESOURCE) {
|
if (remoteContent.type_ === BaseModel.TYPE_RESOURCE) {
|
||||||
const content = await fileApi().get('.resource/' + remoteContent.id);
|
const content = await fileApi().get(`.resource/${remoteContent.id}`);
|
||||||
totalCount++;
|
totalCount++;
|
||||||
if (content.substr(0, 5) === 'JED01') encryptedCount++;
|
if (content.substr(0, 5) === 'JED01') encryptedCount++;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ browser_.runtime.onMessage.addListener(async (command) => {
|
|||||||
newArea.height *= zoom;
|
newArea.height *= zoom;
|
||||||
content.crop_rect = newArea;
|
content.crop_rect = newArea;
|
||||||
|
|
||||||
fetch(command.api_base_url + '/notes', {
|
fetch(`${command.api_base_url}/notes`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
|
@ -26,9 +26,9 @@
|
|||||||
if (url.indexOf('//') === 0) {
|
if (url.indexOf('//') === 0) {
|
||||||
return location.protocol + url;
|
return location.protocol + url;
|
||||||
} else if (url[0] === '/') {
|
} else if (url[0] === '/') {
|
||||||
return location.protocol + '//' + location.host + url;
|
return `${location.protocol}//${location.host}${url}`;
|
||||||
} else {
|
} else {
|
||||||
return baseUrl() + '/' + url;
|
return `${baseUrl()}/${url}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,7 +255,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function prepareCommandResponse(command) {
|
async function prepareCommandResponse(command) {
|
||||||
console.info('Got command: ' + command.name);
|
console.info(`Got command: ${command.name}`);
|
||||||
|
|
||||||
const convertToMarkup = command.preProcessFor ? command.preProcessFor : 'markdown';
|
const convertToMarkup = command.preProcessFor ? command.preProcessFor : 'markdown';
|
||||||
|
|
||||||
@ -343,15 +343,15 @@
|
|||||||
messageComp.style.position = 'fixed';
|
messageComp.style.position = 'fixed';
|
||||||
messageComp.style.opacity = '0.95';
|
messageComp.style.opacity = '0.95';
|
||||||
messageComp.style.fontSize = '14px';
|
messageComp.style.fontSize = '14px';
|
||||||
messageComp.style.width = messageCompWidth + 'px';
|
messageComp.style.width = `${messageCompWidth}px`;
|
||||||
messageComp.style.maxWidth = messageCompWidth + 'px';
|
messageComp.style.maxWidth = `${messageCompWidth}px`;
|
||||||
messageComp.style.border = '1px solid black';
|
messageComp.style.border = '1px solid black';
|
||||||
messageComp.style.background = 'white';
|
messageComp.style.background = 'white';
|
||||||
messageComp.style.color = 'black';
|
messageComp.style.color = 'black';
|
||||||
messageComp.style.top = '10px';
|
messageComp.style.top = '10px';
|
||||||
messageComp.style.textAlign = 'center';
|
messageComp.style.textAlign = 'center';
|
||||||
messageComp.style.padding = '10px';
|
messageComp.style.padding = '10px';
|
||||||
messageComp.style.left = Math.round(document.body.clientWidth / 2 - messageCompWidth / 2) + 'px';
|
messageComp.style.left = `${Math.round(document.body.clientWidth / 2 - messageCompWidth / 2)}px`;
|
||||||
messageComp.style.zIndex = overlay.style.zIndex + 1;
|
messageComp.style.zIndex = overlay.style.zIndex + 1;
|
||||||
|
|
||||||
messageComp.textContent = 'Drag and release to capture a screenshot';
|
messageComp.textContent = 'Drag and release to capture a screenshot';
|
||||||
@ -375,10 +375,10 @@
|
|||||||
let selectionArea = {};
|
let selectionArea = {};
|
||||||
|
|
||||||
const updateSelection = function() {
|
const updateSelection = function() {
|
||||||
selection.style.left = selectionArea.x + 'px';
|
selection.style.left = `${selectionArea.x}px`;
|
||||||
selection.style.top = selectionArea.y + 'px';
|
selection.style.top = `${selectionArea.y}px`;
|
||||||
selection.style.width = selectionArea.width + 'px';
|
selection.style.width = `${selectionArea.width}px`;
|
||||||
selection.style.height = selectionArea.height + 'px';
|
selection.style.height = `${selectionArea.height}px`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const setSelectionSizeFromMouse = function(event) {
|
const setSelectionSizeFromMouse = function(event) {
|
||||||
@ -448,7 +448,7 @@
|
|||||||
return clippedContentResponse(pageTitle(), url, getImageSizes(document), getAnchorNames(document));
|
return clippedContentResponse(pageTitle(), url, getImageSizes(document), getAnchorNames(document));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unknown command: ' + JSON.stringify(command));
|
throw new Error(`Unknown command: ${JSON.stringify(command)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
|
|
||||||
fs.copySync(__dirname + '/../../../../ReactNativeClient/lib/randomClipperPort.js', __dirname + '/../src/randomClipperPort.js');
|
fs.copySync(`${__dirname}/../../../../ReactNativeClient/lib/randomClipperPort.js`, `${__dirname}/../src/randomClipperPort.js`);
|
||||||
|
@ -16,7 +16,7 @@ function commandUserString(command) {
|
|||||||
if (command.name === 'pageUrl') s.push('URL only');
|
if (command.name === 'pageUrl') s.push('URL only');
|
||||||
|
|
||||||
const p = command.preProcessFor ? command.preProcessFor : 'markdown';
|
const p = command.preProcessFor ? command.preProcessFor : 'markdown';
|
||||||
s.push('(' + p + ')');
|
s.push(`(${p})`);
|
||||||
|
|
||||||
return s.join(' ');
|
return s.join(' ');
|
||||||
}
|
}
|
||||||
@ -234,7 +234,7 @@ class AppComponent extends Component {
|
|||||||
this.focusNewTagInput_ = false;
|
this.focusNewTagInput_ = false;
|
||||||
let lastRef = null;
|
let lastRef = null;
|
||||||
for (let i = 0; i < 100; i++) {
|
for (let i = 0; i < 100; i++) {
|
||||||
const ref = this.refs['tagSelector' + i];
|
const ref = this.refs[`tagSelector${i}`];
|
||||||
if (!ref) break;
|
if (!ref) break;
|
||||||
lastRef = ref;
|
lastRef = ref;
|
||||||
}
|
}
|
||||||
@ -245,7 +245,7 @@ class AppComponent extends Component {
|
|||||||
render() {
|
render() {
|
||||||
if (!this.state.contentScriptLoaded) {
|
if (!this.state.contentScriptLoaded) {
|
||||||
let msg = 'Loading...';
|
let msg = 'Loading...';
|
||||||
if (this.state.contentScriptError) msg = 'The Joplin extension is not available on this tab due to: ' + this.state.contentScriptError;
|
if (this.state.contentScriptError) msg = `The Joplin extension is not available on this tab due to: ${this.state.contentScriptError}`;
|
||||||
return <div style={{padding: 10, fontSize: 12, maxWidth: 200}}>{msg}</div>;
|
return <div style={{padding: 10, fontSize: 12, maxWidth: 200}}>{msg}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ class AppComponent extends Component {
|
|||||||
} else if (operation.success) {
|
} else if (operation.success) {
|
||||||
msg = 'Note was successfully created!';
|
msg = 'Note was successfully created!';
|
||||||
} else {
|
} else {
|
||||||
msg = 'There was some error creating the note: ' + operation.errorMessage;
|
msg = `There was some error creating the note: ${operation.errorMessage}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
previewComponent = (
|
previewComponent = (
|
||||||
@ -300,7 +300,7 @@ class AppComponent extends Component {
|
|||||||
const foundState = this.props.clipperServer.foundState;
|
const foundState = this.props.clipperServer.foundState;
|
||||||
|
|
||||||
if (foundState === 'found') {
|
if (foundState === 'found') {
|
||||||
msg = 'Ready on port ' + this.props.clipperServer.port;
|
msg = `Ready on port ${this.props.clipperServer.port}`;
|
||||||
led = led_green;
|
led = led_green;
|
||||||
} else {
|
} else {
|
||||||
msg = stateToString(foundState);
|
msg = stateToString(foundState);
|
||||||
@ -308,7 +308,7 @@ class AppComponent extends Component {
|
|||||||
if (foundState === 'not_found') helpLink = <a className="Help" onClick={this.clipperServerHelpLink_click} href="help">[Help]</a>;
|
if (foundState === 'not_found') helpLink = <a className="Help" onClick={this.clipperServerHelpLink_click} href="help">[Help]</a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = 'Service status: ' + msg;
|
msg = `Service status: ${msg}`;
|
||||||
|
|
||||||
return <div className="StatusBar"><img alt={foundState} className="Led" src={led}/><span className="ServerStatus">{ msg }{ helpLink }</span></div>;
|
return <div className="StatusBar"><img alt={foundState} className="Led" src={led}/><span className="ServerStatus">{ msg }{ helpLink }</span></div>;
|
||||||
};
|
};
|
||||||
@ -346,7 +346,7 @@ class AppComponent extends Component {
|
|||||||
for (let i = 0; i < this.state.selectedTags.length; i++) {
|
for (let i = 0; i < this.state.selectedTags.length; i++) {
|
||||||
comps.push(<div key={i}>
|
comps.push(<div key={i}>
|
||||||
<input
|
<input
|
||||||
ref={'tagSelector' + i}
|
ref={`tagSelector${i}`}
|
||||||
data-index={i}
|
data-index={i}
|
||||||
type="text"
|
type="text"
|
||||||
list="tags"
|
list="tags"
|
||||||
|
@ -19,7 +19,7 @@ class Bridge {
|
|||||||
console.info('Popup: Got command:', command);
|
console.info('Popup: Got command:', command);
|
||||||
|
|
||||||
if (command.warning) {
|
if (command.warning) {
|
||||||
console.warn('Popup: Got warning: ' + command.warning);
|
console.warn(`Popup: Got warning: ${command.warning}`);
|
||||||
this.dispatch({ type: 'WARNING_SET', text: command.warning });
|
this.dispatch({ type: 'WARNING_SET', text: command.warning });
|
||||||
} else {
|
} else {
|
||||||
this.dispatch({ type: 'WARNING_SET', text: '' });
|
this.dispatch({ type: 'WARNING_SET', text: '' });
|
||||||
@ -125,10 +125,10 @@ class Bridge {
|
|||||||
state = randomClipperPort(state, this.env());
|
state = randomClipperPort(state, this.env());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.info('findClipperServerPort: Trying ' + state.port);
|
console.info(`findClipperServerPort: Trying ${state.port}`);
|
||||||
const response = await fetch('http://127.0.0.1:' + state.port + '/ping');
|
const response = await fetch(`http://127.0.0.1:${state.port}/ping`);
|
||||||
const text = await response.text();
|
const text = await response.text();
|
||||||
console.info('findClipperServerPort: Got response: ' + text);
|
console.info(`findClipperServerPort: Got response: ${text}`);
|
||||||
if (text.trim() === 'JoplinClipperServer') {
|
if (text.trim() === 'JoplinClipperServer') {
|
||||||
this.clipperServerPortStatus_ = 'found';
|
this.clipperServerPortStatus_ = 'found';
|
||||||
this.clipperServerPort_ = state.port;
|
this.clipperServerPort_ = state.port;
|
||||||
@ -182,7 +182,7 @@ class Bridge {
|
|||||||
|
|
||||||
async clipperServerBaseUrl() {
|
async clipperServerBaseUrl() {
|
||||||
const port = await this.clipperServerPort();
|
const port = await this.clipperServerPort();
|
||||||
return 'http://127.0.0.1:' + port;
|
return `http://127.0.0.1:${port}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async tabsExecuteScript(options) {
|
async tabsExecuteScript(options) {
|
||||||
@ -192,7 +192,7 @@ class Bridge {
|
|||||||
this.browser().tabs.executeScript(options, () => {
|
this.browser().tabs.executeScript(options, () => {
|
||||||
const e = this.browser().runtime.lastError;
|
const e = this.browser().runtime.lastError;
|
||||||
if (e) {
|
if (e) {
|
||||||
const msg = ['tabsExecuteScript: Cannot load ' + JSON.stringify(options)];
|
const msg = [`tabsExecuteScript: Cannot load ${JSON.stringify(options)}`];
|
||||||
if (e.message) msg.push(e.message);
|
if (e.message) msg.push(e.message);
|
||||||
reject(new Error(msg.join(': ')));
|
reject(new Error(msg.join(': ')));
|
||||||
}
|
}
|
||||||
@ -277,7 +277,7 @@ class Bridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async clipperApiExec(method, path, query, body) {
|
async clipperApiExec(method, path, query, body) {
|
||||||
console.info('Popup: ' + method + ' ' + path);
|
console.info(`Popup: ${method} ${path}`);
|
||||||
|
|
||||||
const baseUrl = await this.clipperServerBaseUrl();
|
const baseUrl = await this.clipperServerBaseUrl();
|
||||||
|
|
||||||
@ -295,13 +295,13 @@ class Bridge {
|
|||||||
const s = [];
|
const s = [];
|
||||||
for (const k in query) {
|
for (const k in query) {
|
||||||
if (!query.hasOwnProperty(k)) continue;
|
if (!query.hasOwnProperty(k)) continue;
|
||||||
s.push(encodeURIComponent(k) + '=' + encodeURIComponent(query[k]));
|
s.push(`${encodeURIComponent(k)}=${encodeURIComponent(query[k])}`);
|
||||||
}
|
}
|
||||||
queryString = s.join('&');
|
queryString = s.join('&');
|
||||||
if (queryString) queryString = '?' + queryString;
|
if (queryString) queryString = `?${queryString}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch(baseUrl + '/' + path + queryString, fetchOptions);
|
const response = await fetch(`${baseUrl}/${path}${queryString}`, fetchOptions);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const msg = await response.text();
|
const msg = await response.text();
|
||||||
throw new Error(msg);
|
throw new Error(msg);
|
||||||
|
@ -39,7 +39,7 @@ class ElectronAppWrapper {
|
|||||||
const stateOptions = {
|
const stateOptions = {
|
||||||
defaultWidth: 800,
|
defaultWidth: 800,
|
||||||
defaultHeight: 600,
|
defaultHeight: 600,
|
||||||
file: 'window-state-' + this.env_ + '.json',
|
file: `window-state-${this.env_}.json`,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.profilePath_) stateOptions.path = this.profilePath_;
|
if (this.profilePath_) stateOptions.path = this.profilePath_;
|
||||||
@ -145,9 +145,9 @@ class ElectronAppWrapper {
|
|||||||
|
|
||||||
buildDir() {
|
buildDir() {
|
||||||
if (this.buildDir_) return this.buildDir_;
|
if (this.buildDir_) return this.buildDir_;
|
||||||
let dir = __dirname + '/build';
|
let dir = `${__dirname}/build`;
|
||||||
if (!fs.pathExistsSync(dir)) {
|
if (!fs.pathExistsSync(dir)) {
|
||||||
dir = dirname(__dirname) + '/build';
|
dir = `${dirname(__dirname)}/build`;
|
||||||
if (!fs.pathExistsSync(dir)) throw new Error('Cannot find build dir');
|
if (!fs.pathExistsSync(dir)) throw new Error('Cannot find build dir');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +172,7 @@ class ElectronAppWrapper {
|
|||||||
// Note: this must be called only after the "ready" event of the app has been dispatched
|
// Note: this must be called only after the "ready" event of the app has been dispatched
|
||||||
createTray(contextMenu) {
|
createTray(contextMenu) {
|
||||||
try {
|
try {
|
||||||
this.tray_ = new Tray(this.buildDir() + '/icons/' + this.trayIconFilename_());
|
this.tray_ = new Tray(`${this.buildDir()}/icons/${this.trayIconFilename_()}`);
|
||||||
this.tray_.setToolTip(this.electronApp_.getName());
|
this.tray_.setToolTip(this.electronApp_.getName());
|
||||||
this.tray_.setContextMenu(contextMenu);
|
this.tray_.setContextMenu(contextMenu);
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ class Application extends BaseApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkForUpdateLoggerPath() {
|
checkForUpdateLoggerPath() {
|
||||||
return Setting.value('profileDir') + '/log-autoupdater.txt';
|
return `${Setting.value('profileDir')}/log-autoupdater.txt`;
|
||||||
}
|
}
|
||||||
|
|
||||||
reducer(state = appDefaultState, action) {
|
reducer(state = appDefaultState, action) {
|
||||||
@ -203,7 +203,7 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
error.message = 'In reducer: ' + error.message + ' Action: ' + JSON.stringify(action);
|
error.message = `In reducer: ${error.message} Action: ${JSON.stringify(action)}`;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,16 +272,16 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
const sortNoteFolderItems = (type) => {
|
const sortNoteFolderItems = (type) => {
|
||||||
const sortItems = [];
|
const sortItems = [];
|
||||||
const sortOptions = Setting.enumOptions(type + '.sortOrder.field');
|
const sortOptions = Setting.enumOptions(`${type}.sortOrder.field`);
|
||||||
for (let field in sortOptions) {
|
for (let field in sortOptions) {
|
||||||
if (!sortOptions.hasOwnProperty(field)) continue;
|
if (!sortOptions.hasOwnProperty(field)) continue;
|
||||||
sortItems.push({
|
sortItems.push({
|
||||||
label: sortOptions[field],
|
label: sortOptions[field],
|
||||||
screens: ['Main'],
|
screens: ['Main'],
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
checked: Setting.value(type + '.sortOrder.field') === field,
|
checked: Setting.value(`${type}.sortOrder.field`) === field,
|
||||||
click: () => {
|
click: () => {
|
||||||
Setting.setValue(type + '.sortOrder.field', field);
|
Setting.setValue(`${type}.sortOrder.field`, field);
|
||||||
this.refreshMenu();
|
this.refreshMenu();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -290,12 +290,12 @@ class Application extends BaseApplication {
|
|||||||
sortItems.push({ type: 'separator' });
|
sortItems.push({ type: 'separator' });
|
||||||
|
|
||||||
sortItems.push({
|
sortItems.push({
|
||||||
label: Setting.settingMetadata(type + '.sortOrder.reverse').label(),
|
label: Setting.settingMetadata(`${type}.sortOrder.reverse`).label(),
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
checked: Setting.value(type + '.sortOrder.reverse'),
|
checked: Setting.value(`${type}.sortOrder.reverse`),
|
||||||
screens: ['Main'],
|
screens: ['Main'],
|
||||||
click: () => {
|
click: () => {
|
||||||
Setting.setValue(type + '.sortOrder.reverse', !Setting.value(type + '.sortOrder.reverse'));
|
Setting.setValue(`${type}.sortOrder.reverse`, !Setting.value(`${type}.sortOrder.reverse`));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -408,7 +408,7 @@ class Application extends BaseApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exportItems.push({
|
exportItems.push({
|
||||||
label: 'PDF - ' + _('PDF File'),
|
label: `PDF - ${_('PDF File')}`,
|
||||||
screens: ['Main'],
|
screens: ['Main'],
|
||||||
click: async () => {
|
click: async () => {
|
||||||
this.dispatch({
|
this.dispatch({
|
||||||
@ -567,11 +567,11 @@ class Application extends BaseApplication {
|
|||||||
_('%s %s (%s, %s)', p.name, p.version, Setting.value('env'), process.platform),
|
_('%s %s (%s, %s)', p.name, p.version, Setting.value('env'), process.platform),
|
||||||
];
|
];
|
||||||
if (gitInfo) {
|
if (gitInfo) {
|
||||||
message.push('\n' + gitInfo);
|
message.push(`\n${gitInfo}`);
|
||||||
console.info(gitInfo);
|
console.info(gitInfo);
|
||||||
}
|
}
|
||||||
bridge().showInfoMessageBox(message.join('\n'), {
|
bridge().showInfoMessageBox(message.join('\n'), {
|
||||||
icon: bridge().electronApp().buildDir() + '/icons/32x32.png',
|
icon: `${bridge().electronApp().buildDir()}/icons/32x32.png`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1027,7 +1027,7 @@ class Application extends BaseApplication {
|
|||||||
const note = selectedNoteIds.length === 1 ? await Note.load(selectedNoteIds[0]) : null;
|
const note = selectedNoteIds.length === 1 ? await Note.load(selectedNoteIds[0]) : null;
|
||||||
|
|
||||||
for (const itemId of ['copy', 'paste', 'cut', 'selectAll', 'bold', 'italic', 'link', 'code', 'insertDateTime', 'commandStartExternalEditing', 'setTags', 'showLocalSearch']) {
|
for (const itemId of ['copy', 'paste', 'cut', 'selectAll', 'bold', 'italic', 'link', 'code', 'insertDateTime', 'commandStartExternalEditing', 'setTags', 'showLocalSearch']) {
|
||||||
const menuItem = Menu.getApplicationMenu().getMenuItemById('edit:' + itemId);
|
const menuItem = Menu.getApplicationMenu().getMenuItemById(`edit:${itemId}`);
|
||||||
if (!menuItem) continue;
|
if (!menuItem) continue;
|
||||||
menuItem.enabled = !!note && note.markup_language === Note.MARKUP_LANGUAGE_MARKDOWN;
|
menuItem.enabled = !!note && note.markup_language === Note.MARKUP_LANGUAGE_MARKDOWN;
|
||||||
}
|
}
|
||||||
@ -1052,13 +1052,13 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
updateEditorFont() {
|
updateEditorFont() {
|
||||||
const fontFamilies = [];
|
const fontFamilies = [];
|
||||||
if (Setting.value('style.editor.fontFamily')) fontFamilies.push('"' + Setting.value('style.editor.fontFamily') + '"');
|
if (Setting.value('style.editor.fontFamily')) fontFamilies.push(`"${Setting.value('style.editor.fontFamily')}"`);
|
||||||
fontFamilies.push('monospace');
|
fontFamilies.push('monospace');
|
||||||
|
|
||||||
// The '*' and '!important' parts are necessary to make sure Russian text is displayed properly
|
// The '*' and '!important' parts are necessary to make sure Russian text is displayed properly
|
||||||
// https://github.com/laurent22/joplin/issues/155
|
// https://github.com/laurent22/joplin/issues/155
|
||||||
|
|
||||||
const css = '.ace_editor * { font-family: ' + fontFamilies.join(', ') + ' !important; }';
|
const css = `.ace_editor * { font-family: ${fontFamilies.join(', ')} !important; }`;
|
||||||
const styleTag = document.createElement('style');
|
const styleTag = document.createElement('style');
|
||||||
styleTag.type = 'text/css';
|
styleTag.type = 'text/css';
|
||||||
styleTag.appendChild(document.createTextNode(css));
|
styleTag.appendChild(document.createTextNode(css));
|
||||||
@ -1073,7 +1073,7 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let msg = error.message ? error.message : '';
|
let msg = error.message ? error.message : '';
|
||||||
msg = 'Could not load custom css from ' + filePath + '\n' + msg;
|
msg = `Could not load custom css from ${filePath}\n${msg}`;
|
||||||
error.message = msg;
|
error.message = msg;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@ -1139,7 +1139,7 @@ class Application extends BaseApplication {
|
|||||||
ids: Setting.value('collapsedFolderIds'),
|
ids: Setting.value('collapsedFolderIds'),
|
||||||
});
|
});
|
||||||
|
|
||||||
const cssString = await this.loadCustomCss(Setting.value('profileDir') + '/userstyle.css');
|
const cssString = await this.loadCustomCss(`${Setting.value('profileDir')}/userstyle.css`);
|
||||||
|
|
||||||
this.store().dispatch({
|
this.store().dispatch({
|
||||||
type: 'LOAD_CUSTOM_CSS',
|
type: 'LOAD_CUSTOM_CSS',
|
||||||
@ -1193,7 +1193,7 @@ class Application extends BaseApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const clipperLogger = new Logger();
|
const clipperLogger = new Logger();
|
||||||
clipperLogger.addTarget('file', { path: Setting.value('profileDir') + '/log-clipper.txt' });
|
clipperLogger.addTarget('file', { path: `${Setting.value('profileDir')}/log-clipper.txt` });
|
||||||
clipperLogger.addTarget('console');
|
clipperLogger.addTarget('console');
|
||||||
|
|
||||||
ClipperServer.instance().setLogger(clipperLogger);
|
ClipperServer.instance().setLogger(clipperLogger);
|
||||||
|
@ -42,7 +42,7 @@ async function fetchLatestRelease(options) {
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const responseText = await response.text();
|
const responseText = await response.text();
|
||||||
throw new Error('Cannot get latest release info: ' + responseText.substr(0,500));
|
throw new Error(`Cannot get latest release info: ${responseText.substr(0,500)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
json = await response.json();
|
json = await response.json();
|
||||||
@ -53,7 +53,7 @@ async function fetchLatestRelease(options) {
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const responseText = await response.text();
|
const responseText = await response.text();
|
||||||
throw new Error('Cannot get latest release info: ' + responseText.substr(0,500));
|
throw new Error(`Cannot get latest release info: ${responseText.substr(0,500)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
json = await response.json();
|
json = await response.json();
|
||||||
@ -112,11 +112,11 @@ function checkForUpdates(inBackground, window, logFilePath, options) {
|
|||||||
|
|
||||||
checkInBackground_ = inBackground;
|
checkInBackground_ = inBackground;
|
||||||
|
|
||||||
autoUpdateLogger_.info('checkForUpdates: Checking with options ' + JSON.stringify(options));
|
autoUpdateLogger_.info(`checkForUpdates: Checking with options ${JSON.stringify(options)}`);
|
||||||
|
|
||||||
fetchLatestRelease(options).then(release => {
|
fetchLatestRelease(options).then(release => {
|
||||||
autoUpdateLogger_.info('Current version: ' + packageInfo.version);
|
autoUpdateLogger_.info(`Current version: ${packageInfo.version}`);
|
||||||
autoUpdateLogger_.info('Latest version: ' + release.version);
|
autoUpdateLogger_.info(`Latest version: ${release.version}`);
|
||||||
autoUpdateLogger_.info('Is Pre-release:', release.prerelease);
|
autoUpdateLogger_.info('Is Pre-release:', release.prerelease);
|
||||||
|
|
||||||
if (compareVersions(release.version, packageInfo.version) <= 0) {
|
if (compareVersions(release.version, packageInfo.version) <= 0) {
|
||||||
@ -126,12 +126,12 @@ function checkForUpdates(inBackground, window, logFilePath, options) {
|
|||||||
buttons: [_('OK')],
|
buttons: [_('OK')],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const releaseNotes = release.notes.trim() ? '\n\n' + release.notes.trim() : '';
|
const releaseNotes = release.notes.trim() ? `\n\n${release.notes.trim()}` : '';
|
||||||
const newVersionString = release.prerelease ? _('%s (pre-release)', release.version) : release.version;
|
const newVersionString = release.prerelease ? _('%s (pre-release)', release.version) : release.version;
|
||||||
|
|
||||||
const buttonIndex = dialog.showMessageBox(parentWindow_, {
|
const buttonIndex = dialog.showMessageBox(parentWindow_, {
|
||||||
type: 'info',
|
type: 'info',
|
||||||
message: _('An update is available, do you want to download it now?') + '\n\n' + _('Your version: %s', packageInfo.version) + '\n' + _('New version: %s', newVersionString) + releaseNotes,
|
message: `${_('An update is available, do you want to download it now?')}\n\n${_('Your version: %s', packageInfo.version)}\n${_('New version: %s', newVersionString)}${releaseNotes}`,
|
||||||
buttons: [_('Yes'), _('No')],
|
buttons: [_('Yes'), _('No')],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ const execSync = require('child_process').execSync;
|
|||||||
// Electron Builder strip off certain important keys from package.json, which we need, in particular build.appId
|
// Electron Builder strip off certain important keys from package.json, which we need, in particular build.appId
|
||||||
// so this script is used to preserve the keys that we need.
|
// so this script is used to preserve the keys that we need.
|
||||||
|
|
||||||
const packageInfo = require(__dirname + '/package.json');
|
const packageInfo = require(`${__dirname}/package.json`);
|
||||||
|
|
||||||
let removeKeys = ['scripts', 'devDependencies', 'optionalDependencies', 'dependencies'];
|
let removeKeys = ['scripts', 'devDependencies', 'optionalDependencies', 'dependencies'];
|
||||||
|
|
||||||
@ -30,8 +30,8 @@ if (typeof branch !== 'undefined' && typeof hash !== 'undefined') {
|
|||||||
packageInfo.git = { branch: branch, hash: hash };
|
packageInfo.git = { branch: branch, hash: hash };
|
||||||
}
|
}
|
||||||
|
|
||||||
let fileContent = '// Auto-generated by compile-package-info.js\n// Do not change directly\nconst packageInfo = ' + JSON.stringify(packageInfo, null, 4) + ';';
|
let fileContent = `// Auto-generated by compile-package-info.js\n// Do not change directly\nconst packageInfo = ${JSON.stringify(packageInfo, null, 4)};`;
|
||||||
fileContent += '\n';
|
fileContent += '\n';
|
||||||
fileContent += 'module.exports = packageInfo;';
|
fileContent += 'module.exports = packageInfo;';
|
||||||
|
|
||||||
fs.writeFileSync(__dirname + '/packageInfo.js', fileContent);
|
fs.writeFileSync(`${__dirname}/packageInfo.js`, fileContent);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const spawnSync = require('child_process').spawnSync;
|
const spawnSync = require('child_process').spawnSync;
|
||||||
|
|
||||||
const babelPath = __dirname + '/node_modules/.bin/babel' + (process.platform === 'win32' ? '.cmd' : '');
|
const babelPath = `${__dirname}/node_modules/.bin/babel${process.platform === 'win32' ? '.cmd' : ''}`;
|
||||||
const basePath = __dirname + '/../..';
|
const basePath = `${__dirname}/../..`;
|
||||||
|
|
||||||
function fileIsNewerThan(path1, path2) {
|
function fileIsNewerThan(path1, path2) {
|
||||||
if (!fs.existsSync(path2)) return true;
|
if (!fs.existsSync(path2)) return true;
|
||||||
@ -15,7 +15,7 @@ function fileIsNewerThan(path1, path2) {
|
|||||||
|
|
||||||
function convertJsx(path) {
|
function convertJsx(path) {
|
||||||
fs.readdirSync(path).forEach((filename) => {
|
fs.readdirSync(path).forEach((filename) => {
|
||||||
const jsxPath = path + '/' + filename;
|
const jsxPath = `${path}/${filename}`;
|
||||||
const p = jsxPath.split('.');
|
const p = jsxPath.split('.');
|
||||||
if (p.length <= 1) return;
|
if (p.length <= 1) return;
|
||||||
const ext = p[p.length - 1];
|
const ext = p[p.length - 1];
|
||||||
@ -24,10 +24,10 @@ function convertJsx(path) {
|
|||||||
|
|
||||||
const basePath = p.join('.');
|
const basePath = p.join('.');
|
||||||
|
|
||||||
const jsPath = basePath + '.min.js';
|
const jsPath = `${basePath}.min.js`;
|
||||||
|
|
||||||
if (fileIsNewerThan(jsxPath, jsPath)) {
|
if (fileIsNewerThan(jsxPath, jsPath)) {
|
||||||
console.info('Compiling ' + jsxPath + '...');
|
console.info(`Compiling ${jsxPath}...`);
|
||||||
const result = spawnSync(babelPath, ['--presets', 'react', '--out-file', jsPath, jsxPath]);
|
const result = spawnSync(babelPath, ['--presets', 'react', '--out-file', jsPath, jsxPath]);
|
||||||
if (result.status !== 0) {
|
if (result.status !== 0) {
|
||||||
const msg = [];
|
const msg = [];
|
||||||
@ -41,13 +41,13 @@ function convertJsx(path) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
convertJsx(__dirname + '/gui');
|
convertJsx(`${__dirname}/gui`);
|
||||||
convertJsx(__dirname + '/plugins');
|
convertJsx(`${__dirname}/plugins`);
|
||||||
|
|
||||||
const libContent = [
|
const libContent = [
|
||||||
fs.readFileSync(basePath + '/ReactNativeClient/lib/string-utils-common.js', 'utf8'),
|
fs.readFileSync(`${basePath}/ReactNativeClient/lib/string-utils-common.js`, 'utf8'),
|
||||||
fs.readFileSync(basePath + '/ReactNativeClient/lib/markJsUtils.js', 'utf8'),
|
fs.readFileSync(`${basePath}/ReactNativeClient/lib/markJsUtils.js`, 'utf8'),
|
||||||
fs.readFileSync(basePath + '/ReactNativeClient/lib/renderers/webviewLib.js', 'utf8'),
|
fs.readFileSync(`${basePath}/ReactNativeClient/lib/renderers/webviewLib.js`, 'utf8'),
|
||||||
];
|
];
|
||||||
|
|
||||||
fs.writeFileSync(__dirname + '/gui/note-viewer/lib.js', libContent.join('\n'), 'utf8');
|
fs.writeFileSync(`${__dirname}/gui/note-viewer/lib.js`, libContent.join('\n'), 'utf8');
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
const execCommand = function(command) {
|
const execCommand = function(command) {
|
||||||
const exec = require('child_process').exec;
|
const exec = require('child_process').exec;
|
||||||
|
|
||||||
console.info('Running: ' + command);
|
console.info(`Running: ${command}`);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
exec(command, (error, stdout) => {
|
exec(command, (error, stdout) => {
|
||||||
@ -25,14 +25,14 @@ const isWindows = () => {
|
|||||||
async function main() {
|
async function main() {
|
||||||
// electron-rebuild --arch ia32 && electron-rebuild --arch x64
|
// electron-rebuild --arch ia32 && electron-rebuild --arch x64
|
||||||
|
|
||||||
let exePath = __dirname + '/node_modules/.bin/electron-rebuild';
|
let exePath = `${__dirname}/node_modules/.bin/electron-rebuild`;
|
||||||
if (isWindows()) exePath += '.cmd';
|
if (isWindows()) exePath += '.cmd';
|
||||||
|
|
||||||
if (isWindows()) {
|
if (isWindows()) {
|
||||||
console.info(await execCommand(['"' + exePath + '"', '--arch ia32'].join(' ')));
|
console.info(await execCommand([`"${exePath}"`, '--arch ia32'].join(' ')));
|
||||||
console.info(await execCommand(['"' + exePath + '"', '--arch x64'].join(' ')));
|
console.info(await execCommand([`"${exePath}"`, '--arch x64'].join(' ')));
|
||||||
} else {
|
} else {
|
||||||
console.info(await execCommand(['"' + exePath + '"'].join(' ')));
|
console.info(await execCommand([`"${exePath}"`].join(' ')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ function ConfigMenuBarButton(props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<button style={style.button} onClick={props.onClick}>
|
<button style={style.button} onClick={props.onClick}>
|
||||||
<i style={iconStyle} className={'fa ' + props.iconName}></i>
|
<i style={iconStyle} className={`fa ${props.iconName}`}></i>
|
||||||
<span style={labelStyle}>{props.label}</span>
|
<span style={labelStyle}>{props.label}</span>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
@ -49,14 +49,14 @@ class ConfigScreenComponent extends React.Component {
|
|||||||
if (section.name === name) return section;
|
if (section.name === name) return section;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('Invalid section name: ' + name);
|
throw new Error(`Invalid section name: ${name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
screenFromName(screenName) {
|
screenFromName(screenName) {
|
||||||
if (screenName === 'encryption') return <EncryptionConfigScreen theme={this.props.theme}/>;
|
if (screenName === 'encryption') return <EncryptionConfigScreen theme={this.props.theme}/>;
|
||||||
if (screenName === 'server') return <ClipperConfigScreen theme={this.props.theme}/>;
|
if (screenName === 'server') return <ClipperConfigScreen theme={this.props.theme}/>;
|
||||||
|
|
||||||
throw new Error('Invalid screen name: ' + screenName);
|
throw new Error(`Invalid screen name: ${screenName}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
switchSection(name) {
|
switchSection(name) {
|
||||||
@ -249,7 +249,7 @@ class ConfigScreenComponent extends React.Component {
|
|||||||
<div key={key + value.toString()} style={rowStyle}>
|
<div key={key + value.toString()} style={rowStyle}>
|
||||||
<div style={controlStyle}>
|
<div style={controlStyle}>
|
||||||
<input
|
<input
|
||||||
id={'setting_checkbox_' + key}
|
id={`setting_checkbox_${key}`}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={!!value}
|
checked={!!value}
|
||||||
onChange={event => {
|
onChange={event => {
|
||||||
@ -261,7 +261,7 @@ class ConfigScreenComponent extends React.Component {
|
|||||||
onCheckboxClick(event);
|
onCheckboxClick(event);
|
||||||
}}
|
}}
|
||||||
style={checkboxLabelStyle}
|
style={checkboxLabelStyle}
|
||||||
htmlFor={'setting_checkbox_' + key}
|
htmlFor={`setting_checkbox_${key}`}
|
||||||
>
|
>
|
||||||
{md.label()}
|
{md.label()}
|
||||||
</label>
|
</label>
|
||||||
@ -289,7 +289,7 @@ class ConfigScreenComponent extends React.Component {
|
|||||||
if (!cmdArray[0] && !cmdArray[1]) return '';
|
if (!cmdArray[0] && !cmdArray[1]) return '';
|
||||||
let cmdString = pathUtils.quotePath(cmdArray[0]);
|
let cmdString = pathUtils.quotePath(cmdArray[0]);
|
||||||
if (!cmdString) cmdString = '""';
|
if (!cmdString) cmdString = '""';
|
||||||
if (cmdArray[1]) cmdString += ' ' + cmdArray[1];
|
if (cmdArray[1]) cmdString += ` ${cmdArray[1]}`;
|
||||||
return cmdString;
|
return cmdString;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -390,7 +390,7 @@ class ConfigScreenComponent extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const label = [md.label()];
|
const label = [md.label()];
|
||||||
if (md.unitLabel) label.push('(' + md.unitLabel() + ')');
|
if (md.unitLabel) label.push(`(${md.unitLabel()})`);
|
||||||
|
|
||||||
const inputStyle = Object.assign({}, textInputBaseStyle);
|
const inputStyle = Object.assign({}, textInputBaseStyle);
|
||||||
|
|
||||||
@ -414,7 +414,7 @@ class ConfigScreenComponent extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.warn('Type not implemented: ' + key);
|
console.warn(`Type not implemented: ${key}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
@ -6,19 +6,19 @@ const { _ } = require('lib/locale.js');
|
|||||||
function platformAssets(type) {
|
function platformAssets(type) {
|
||||||
if (type === 'firefox') {
|
if (type === 'firefox') {
|
||||||
return {
|
return {
|
||||||
logoImage: bridge().buildDir() + '/images/firefox-logo.svg',
|
logoImage: `${bridge().buildDir()}/images/firefox-logo.svg`,
|
||||||
locationLabel: _('Firefox Extension'),
|
locationLabel: _('Firefox Extension'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'chrome') {
|
if (type === 'chrome') {
|
||||||
return {
|
return {
|
||||||
logoImage: bridge().buildDir() + '/images/chrome-logo.svg',
|
logoImage: `${bridge().buildDir()}/images/chrome-logo.svg`,
|
||||||
locationLabel: _('Chrome Web Store'),
|
locationLabel: _('Chrome Web Store'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('Invalid type:' + type);
|
throw new Error(`Invalid type:${type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ExtensionBadge(props) {
|
function ExtensionBadge(props) {
|
||||||
|
@ -123,9 +123,9 @@ class HeaderComponent extends React.Component {
|
|||||||
if (options.title) iconStyle.marginRight = 5;
|
if (options.title) iconStyle.marginRight = 5;
|
||||||
if ('undefined' != typeof options.iconRotation) {
|
if ('undefined' != typeof options.iconRotation) {
|
||||||
iconStyle.transition = 'transform 0.15s ease-in-out';
|
iconStyle.transition = 'transform 0.15s ease-in-out';
|
||||||
iconStyle.transform = 'rotate(' + options.iconRotation + 'deg)';
|
iconStyle.transform = `rotate(${options.iconRotation}deg)`;
|
||||||
}
|
}
|
||||||
icon = <i style={iconStyle} className={'fa ' + options.iconName}></i>;
|
icon = <i style={iconStyle} className={`fa ${options.iconName}`}></i>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isEnabled = !('enabled' in options) || options.enabled;
|
const isEnabled = !('enabled' in options) || options.enabled;
|
||||||
@ -195,7 +195,7 @@ class HeaderComponent extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const iconName = state.searchQuery ? 'fa-times' : 'fa-search';
|
const iconName = state.searchQuery ? 'fa-times' : 'fa-search';
|
||||||
const icon = <i style={iconStyle} className={'fa ' + iconName}></i>;
|
const icon = <i style={iconStyle} className={`fa ${iconName}`}></i>;
|
||||||
if (options.onQuery) this.searchOnQuery_ = options.onQuery;
|
if (options.onQuery) this.searchOnQuery_ = options.onQuery;
|
||||||
|
|
||||||
const usageLink = !this.state.showSearchUsageLink ? null : (
|
const usageLink = !this.state.showSearchUsageLink ? null : (
|
||||||
@ -222,7 +222,7 @@ class HeaderComponent extends React.Component {
|
|||||||
style.height = theme.headerHeight;
|
style.height = theme.headerHeight;
|
||||||
style.display = 'flex';
|
style.display = 'flex';
|
||||||
style.flexDirection = 'row';
|
style.flexDirection = 'row';
|
||||||
style.borderBottom = '1px solid ' + theme.dividerColor;
|
style.borderBottom = `1px solid ${theme.dividerColor}`;
|
||||||
style.boxSizing = 'border-box';
|
style.boxSizing = 'border-box';
|
||||||
|
|
||||||
const items = [];
|
const items = [];
|
||||||
@ -252,9 +252,9 @@ class HeaderComponent extends React.Component {
|
|||||||
const item = this.props.items[i];
|
const item = this.props.items[i];
|
||||||
|
|
||||||
if (item.type === 'search') {
|
if (item.type === 'search') {
|
||||||
items.push(this.makeSearch('item_' + i + '_search', itemStyle, item, this.state));
|
items.push(this.makeSearch(`item_${i}_search`, itemStyle, item, this.state));
|
||||||
} else {
|
} else {
|
||||||
items.push(this.makeButton('item_' + i + '_' + item.title, itemStyle, item));
|
items.push(this.makeButton(`item_${i}_${item.title}`, itemStyle, item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ class IconButton extends React.Component {
|
|||||||
color: theme.color,
|
color: theme.color,
|
||||||
fontSize: theme.fontSize * 1.4,
|
fontSize: theme.fontSize * 1.4,
|
||||||
};
|
};
|
||||||
const icon = <i style={iconStyle} className={'fa ' + this.props.iconName}></i>;
|
const icon = <i style={iconStyle} className={`fa ${this.props.iconName}`}></i>;
|
||||||
|
|
||||||
const rootStyle = Object.assign(
|
const rootStyle = Object.assign(
|
||||||
{
|
{
|
||||||
|
@ -40,7 +40,7 @@ class NoteListComponent extends React.Component {
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'stretch',
|
alignItems: 'stretch',
|
||||||
backgroundColor: theme.backgroundColor,
|
backgroundColor: theme.backgroundColor,
|
||||||
borderBottom: '1px solid ' + theme.dividerColor,
|
borderBottom: `1px solid ${theme.dividerColor}`,
|
||||||
},
|
},
|
||||||
listItemSelected: {
|
listItemSelected: {
|
||||||
backgroundColor: theme.selectedColor,
|
backgroundColor: theme.selectedColor,
|
||||||
@ -222,7 +222,7 @@ class NoteListComponent extends React.Component {
|
|||||||
// Need to include "todo_completed" in key so that checkbox is updated when
|
// Need to include "todo_completed" in key so that checkbox is updated when
|
||||||
// item is changed via sync.
|
// item is changed via sync.
|
||||||
return (
|
return (
|
||||||
<div key={item.id + '_' + item.todo_completed} style={style}>
|
<div key={`${item.id}_${item.todo_completed}`} style={style}>
|
||||||
{checkbox}
|
{checkbox}
|
||||||
<a
|
<a
|
||||||
ref={ref}
|
ref={ref}
|
||||||
@ -393,7 +393,7 @@ class NoteListComponent extends React.Component {
|
|||||||
const padding = 10;
|
const padding = 10;
|
||||||
const emptyDivStyle = Object.assign(
|
const emptyDivStyle = Object.assign(
|
||||||
{
|
{
|
||||||
padding: padding + 'px',
|
padding: `${padding}px`,
|
||||||
fontSize: theme.fontSize,
|
fontSize: theme.fontSize,
|
||||||
color: theme.color,
|
color: theme.color,
|
||||||
backgroundColor: theme.backgroundColor,
|
backgroundColor: theme.backgroundColor,
|
||||||
|
@ -76,7 +76,7 @@ class NotePropertiesDialog extends React.Component {
|
|||||||
|
|
||||||
formNote.location = '';
|
formNote.location = '';
|
||||||
if (Number(note.latitude) || Number(note.longitude)) {
|
if (Number(note.latitude) || Number(note.longitude)) {
|
||||||
formNote.location = note.latitude + ', ' + note.longitude;
|
formNote.location = `${note.latitude}, ${note.longitude}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
formNote.revisionsLink = note.id;
|
formNote.revisionsLink = note.id;
|
||||||
@ -328,7 +328,7 @@ class NotePropertiesDialog extends React.Component {
|
|||||||
if (editCompHandler) {
|
if (editCompHandler) {
|
||||||
editComp = (
|
editComp = (
|
||||||
<a href="#" onClick={editCompHandler} style={styles.editPropertyButton}>
|
<a href="#" onClick={editCompHandler} style={styles.editPropertyButton}>
|
||||||
<i className={'fa ' + editCompIcon} aria-hidden="true" style={{ marginLeft: '.5em' }}></i>
|
<i className={`fa ${editCompIcon}`} aria-hidden="true" style={{ marginLeft: '.5em' }}></i>
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ class NoteRevisionViewerComponent extends React.PureComponent {
|
|||||||
const theme = themeStyle(this.props.theme);
|
const theme = themeStyle(this.props.theme);
|
||||||
|
|
||||||
const markupToHtml = new MarkupToHtml({
|
const markupToHtml = new MarkupToHtml({
|
||||||
resourceBaseUrl: 'file://' + Setting.value('resourceDir') + '/',
|
resourceBaseUrl: `file://${Setting.value('resourceDir')}/`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = markupToHtml.render(markupLanguage, noteBody, theme, {
|
const result = markupToHtml.render(markupLanguage, noteBody, theme, {
|
||||||
@ -138,7 +138,7 @@ class NoteRevisionViewerComponent extends React.PureComponent {
|
|||||||
|
|
||||||
revisionListItems.push(
|
revisionListItems.push(
|
||||||
<option key={rev.id} value={rev.id}>
|
<option key={rev.id} value={rev.id}>
|
||||||
{time.formatMsToLocal(rev.item_updated_time) + ' (' + stats + ')'}
|
{`${time.formatMsToLocal(rev.item_updated_time)} (${stats})`}
|
||||||
</option>
|
</option>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ class NoteRevisionViewerComponent extends React.PureComponent {
|
|||||||
const titleInput = (
|
const titleInput = (
|
||||||
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', marginBottom: 10, borderWidth: 1, borderBottomStyle: 'solid', borderColor: theme.dividerColor, paddingBottom: 10 }}>
|
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', marginBottom: 10, borderWidth: 1, borderBottomStyle: 'solid', borderColor: theme.dividerColor, paddingBottom: 10 }}>
|
||||||
<button onClick={this.backButton_click} style={Object.assign({}, theme.buttonStyle, { marginRight: 10, height: theme.inputStyle.height })}>
|
<button onClick={this.backButton_click} style={Object.assign({}, theme.buttonStyle, { marginRight: 10, height: theme.inputStyle.height })}>
|
||||||
{'⬅ ' + _('Back')}
|
{`⬅ ${_('Back')}`}
|
||||||
</button>
|
</button>
|
||||||
<input readOnly type="text" style={style.titleInput} value={this.state.note ? this.state.note.title : ''} />
|
<input readOnly type="text" style={style.titleInput} value={this.state.note ? this.state.note.title : ''} />
|
||||||
<select disabled={!this.state.revisions.length} value={this.state.currentRevId} style={style.revisionList} onChange={this.revisionList_onChange}>
|
<select disabled={!this.state.revisions.length} value={this.state.currentRevId} style={style.revisionList} onChange={this.revisionList_onChange}>
|
||||||
|
@ -53,7 +53,7 @@ class NoteSearchBarComponent extends React.Component {
|
|||||||
color: theme.color,
|
color: theme.color,
|
||||||
};
|
};
|
||||||
|
|
||||||
const icon = <i style={iconStyle} className={'fa ' + iconName}></i>;
|
const icon = <i style={iconStyle} className={`fa ${iconName}`}></i>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<a href="#" style={searchButton} onClick={clickHandler}>
|
<a href="#" style={searchButton} onClick={clickHandler}>
|
||||||
|
@ -135,7 +135,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
const image = clipboard.readImage();
|
const image = clipboard.readImage();
|
||||||
|
|
||||||
const fileExt = mimeUtils.toFileExtension(format);
|
const fileExt = mimeUtils.toFileExtension(format);
|
||||||
const filePath = Setting.value('tempDir') + '/' + md5(Date.now()) + '.' + fileExt;
|
const filePath = `${Setting.value('tempDir')}/${md5(Date.now())}.${fileExt}`;
|
||||||
|
|
||||||
await shim.writeImageToFile(image, format, filePath);
|
await shim.writeImageToFile(image, format, filePath);
|
||||||
await this.commandAttachFile([filePath]);
|
await this.commandAttachFile([filePath]);
|
||||||
@ -362,7 +362,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
markupToHtml() {
|
markupToHtml() {
|
||||||
if (this.markupToHtml_) return this.markupToHtml_;
|
if (this.markupToHtml_) return this.markupToHtml_;
|
||||||
this.markupToHtml_ = new MarkupToHtml({
|
this.markupToHtml_ = new MarkupToHtml({
|
||||||
resourceBaseUrl: 'file://' + Setting.value('resourceDir') + '/',
|
resourceBaseUrl: `file://${Setting.value('resourceDir')}/`,
|
||||||
});
|
});
|
||||||
return this.markupToHtml_;
|
return this.markupToHtml_;
|
||||||
}
|
}
|
||||||
@ -712,7 +712,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
const args = event.args;
|
const args = event.args;
|
||||||
const arg0 = args && args.length >= 1 ? args[0] : null;
|
const arg0 = args && args.length >= 1 ? args[0] : null;
|
||||||
|
|
||||||
if (msg !== 'percentScroll') console.info('Got ipc-message: ' + msg, args);
|
if (msg !== 'percentScroll') console.info(`Got ipc-message: ${msg}`, args);
|
||||||
|
|
||||||
if (msg.indexOf('checkboxclick:') === 0) {
|
if (msg.indexOf('checkboxclick:') === 0) {
|
||||||
// Ugly hack because setting the body here will make the scrollbar
|
// Ugly hack because setting the body here will make the scrollbar
|
||||||
@ -733,7 +733,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
this.setState({ localSearch: ls });
|
this.setState({ localSearch: ls });
|
||||||
} else if (msg.indexOf('markForDownload:') === 0) {
|
} else if (msg.indexOf('markForDownload:') === 0) {
|
||||||
const s = msg.split(':');
|
const s = msg.split(':');
|
||||||
if (s.length < 2) throw new Error('Invalid message: ' + msg);
|
if (s.length < 2) throw new Error(`Invalid message: ${msg}`);
|
||||||
ResourceFetcher.instance().markForDownload(s[1]);
|
ResourceFetcher.instance().markForDownload(s[1]);
|
||||||
} else if (msg === 'percentScroll') {
|
} else if (msg === 'percentScroll') {
|
||||||
this.ignoreNextEditorScroll_ = true;
|
this.ignoreNextEditorScroll_ = true;
|
||||||
@ -751,7 +751,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
new MenuItem({
|
new MenuItem({
|
||||||
label: _('Open...'),
|
label: _('Open...'),
|
||||||
click: async () => {
|
click: async () => {
|
||||||
const ok = bridge().openExternal('file://' + resourcePath);
|
const ok = bridge().openExternal(`file://${resourcePath}`);
|
||||||
if (!ok) bridge().showErrorMessageBox(_('This file could not be opened: %s', resourcePath));
|
if (!ok) bridge().showErrorMessageBox(_('This file could not be opened: %s', resourcePath));
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -797,7 +797,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
reg.logger().error('Unhandled item type: ' + itemType);
|
reg.logger().error(`Unhandled item type: ${itemType}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -807,7 +807,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
const itemId = resourceUrlInfo.itemId;
|
const itemId = resourceUrlInfo.itemId;
|
||||||
const item = await BaseItem.loadItemById(itemId);
|
const item = await BaseItem.loadItemById(itemId);
|
||||||
|
|
||||||
if (!item) throw new Error('No item with ID ' + itemId);
|
if (!item) throw new Error(`No item with ID ${itemId}`);
|
||||||
|
|
||||||
if (item.type_ === BaseModel.TYPE_RESOURCE) {
|
if (item.type_ === BaseModel.TYPE_RESOURCE) {
|
||||||
const localState = await Resource.localState(item);
|
const localState = await Resource.localState(item);
|
||||||
@ -829,7 +829,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Unsupported item type: ' + item.type_);
|
throw new Error(`Unsupported item type: ${item.type_}`);
|
||||||
}
|
}
|
||||||
} else if (urlUtils.urlProtocol(msg)) {
|
} else if (urlUtils.urlProtocol(msg)) {
|
||||||
if (msg.indexOf('file://') === 0) {
|
if (msg.indexOf('file://') === 0) {
|
||||||
@ -929,8 +929,8 @@ class NoteTextComponent extends React.Component {
|
|||||||
const letters = ['F', 'T', 'P', 'Q', 'L', ',', 'G', 'K'];
|
const letters = ['F', 'T', 'P', 'Q', 'L', ',', 'G', 'K'];
|
||||||
for (let i = 0; i < letters.length; i++) {
|
for (let i = 0; i < letters.length; i++) {
|
||||||
const l = letters[i];
|
const l = letters[i];
|
||||||
cancelledKeys.push('Ctrl+' + l);
|
cancelledKeys.push(`Ctrl+${l}`);
|
||||||
cancelledKeys.push('Command+' + l);
|
cancelledKeys.push(`Command+${l}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < cancelledKeys.length; i++) {
|
for (let i = 0; i < cancelledKeys.length; i++) {
|
||||||
@ -940,7 +940,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
// an exception from this undocumented function seems to cancel it without any
|
// an exception from this undocumented function seems to cancel it without any
|
||||||
// side effect.
|
// side effect.
|
||||||
// https://stackoverflow.com/questions/36075846
|
// https://stackoverflow.com/questions/36075846
|
||||||
throw new Error('HACK: Overriding Ace Editor shortcut: ' + k);
|
throw new Error(`HACK: Overriding Ace Editor shortcut: ${k}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -970,12 +970,12 @@ class NoteTextComponent extends React.Component {
|
|||||||
const leftSpaces = lineLeftSpaces(line);
|
const leftSpaces = lineLeftSpaces(line);
|
||||||
const lineNoLeftSpaces = line.trimLeft();
|
const lineNoLeftSpaces = line.trimLeft();
|
||||||
|
|
||||||
if (lineNoLeftSpaces.indexOf('- [ ] ') === 0 || lineNoLeftSpaces.indexOf('- [x] ') === 0 || lineNoLeftSpaces.indexOf('- [X] ') === 0) return leftSpaces + '- [ ] ';
|
if (lineNoLeftSpaces.indexOf('- [ ] ') === 0 || lineNoLeftSpaces.indexOf('- [x] ') === 0 || lineNoLeftSpaces.indexOf('- [X] ') === 0) return `${leftSpaces}- [ ] `;
|
||||||
if (lineNoLeftSpaces.indexOf('- ') === 0) return leftSpaces + '- ';
|
if (lineNoLeftSpaces.indexOf('- ') === 0) return `${leftSpaces}- `;
|
||||||
if (lineNoLeftSpaces.indexOf('* ') === 0 && line.trim() !== '* * *') return leftSpaces + '* ';
|
if (lineNoLeftSpaces.indexOf('* ') === 0 && line.trim() !== '* * *') return `${leftSpaces}* `;
|
||||||
|
|
||||||
const bulletNumber = markdownUtils.olLineNumber(lineNoLeftSpaces);
|
const bulletNumber = markdownUtils.olLineNumber(lineNoLeftSpaces);
|
||||||
if (bulletNumber) return leftSpaces + (bulletNumber + 1) + '. ';
|
if (bulletNumber) return `${leftSpaces + (bulletNumber + 1)}. `;
|
||||||
|
|
||||||
return this.$getIndent(line);
|
return this.$getIndent(line);
|
||||||
};
|
};
|
||||||
@ -1032,7 +1032,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
|
|
||||||
if (!bodyToRender.trim() && visiblePanes.indexOf('viewer') >= 0 && visiblePanes.indexOf('editor') < 0) {
|
if (!bodyToRender.trim() && visiblePanes.indexOf('viewer') >= 0 && visiblePanes.indexOf('editor') < 0) {
|
||||||
// Fixes https://github.com/laurent22/joplin/issues/217
|
// Fixes https://github.com/laurent22/joplin/issues/217
|
||||||
bodyToRender = '<i>' + _('This note has no content. Click on "%s" to toggle the editor and edit the note.', _('Layout')) + '</i>';
|
bodyToRender = `<i>${_('This note has no content. Click on "%s" to toggle the editor and edit the note.', _('Layout'))}</i>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = this.markupToHtml().render(markupLanguage, bodyToRender, theme, mdOptions);
|
const result = this.markupToHtml().render(markupLanguage, bodyToRender, theme, mdOptions);
|
||||||
@ -1155,7 +1155,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
for (let i = 0; i < filePaths.length; i++) {
|
for (let i = 0; i < filePaths.length; i++) {
|
||||||
const filePath = filePaths[i];
|
const filePath = filePaths[i];
|
||||||
try {
|
try {
|
||||||
reg.logger().info('Attaching ' + filePath);
|
reg.logger().info(`Attaching ${filePath}`);
|
||||||
note = await shim.attachFileToNote(note, filePath, position, createFileURL);
|
note = await shim.attachFileToNote(note, filePath, position, createFileURL);
|
||||||
reg.logger().info('File was attached.');
|
reg.logger().info('File was attached.');
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -1183,7 +1183,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
|
|
||||||
// helper function to style the title for printing
|
// helper function to style the title for printing
|
||||||
title_(title) {
|
title_(title) {
|
||||||
return '<div style="font-size: 2em; font-weight: bold; border-bottom: 1px solid rgb(230,230,230); padding-bottom: .3em;">' + title + '</div><br>';
|
return `<div style="font-size: 2em; font-weight: bold; border-bottom: 1px solid rgb(230,230,230); padding-bottom: .3em;">${title}</div><br>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async printTo_(target, options) {
|
async printTo_(target, options) {
|
||||||
@ -1192,7 +1192,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const previousBody = this.state.note.body;
|
const previousBody = this.state.note.body;
|
||||||
const tempBody = this.title_(this.state.note.title) + '\n\n' + previousBody;
|
const tempBody = `${this.title_(this.state.note.title)}\n\n${previousBody}`;
|
||||||
|
|
||||||
const previousTheme = Setting.value('theme');
|
const previousTheme = Setting.value('theme');
|
||||||
Setting.setValue('theme', Setting.THEME_LIGHT);
|
Setting.setValue('theme', Setting.THEME_LIGHT);
|
||||||
@ -1470,7 +1470,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
let bulletNumber = markdownUtils.olLineNumber(this.selectionRangeCurrentLine());
|
let bulletNumber = markdownUtils.olLineNumber(this.selectionRangeCurrentLine());
|
||||||
if (!bulletNumber) bulletNumber = markdownUtils.olLineNumber(this.selectionRangePreviousLine());
|
if (!bulletNumber) bulletNumber = markdownUtils.olLineNumber(this.selectionRangePreviousLine());
|
||||||
if (!bulletNumber) bulletNumber = 0;
|
if (!bulletNumber) bulletNumber = 0;
|
||||||
this.addListItem(bulletNumber + 1 + '. ', '', _('List item'));
|
this.addListItem(`${bulletNumber + 1}. `, '', _('List item'));
|
||||||
}
|
}
|
||||||
|
|
||||||
commandTextHeading() {
|
commandTextHeading() {
|
||||||
@ -1483,7 +1483,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
|
|
||||||
async commandTextLink() {
|
async commandTextLink() {
|
||||||
const url = await dialogs.prompt(_('Insert Hyperlink'));
|
const url = await dialogs.prompt(_('Insert Hyperlink'));
|
||||||
this.wrapSelectionWithStrings('[', '](' + url + ')');
|
this.wrapSelectionWithStrings('[', `](${url})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
itemContextMenu() {
|
itemContextMenu() {
|
||||||
@ -1796,7 +1796,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
|
|
||||||
const rootStyle = Object.assign(
|
const rootStyle = Object.assign(
|
||||||
{
|
{
|
||||||
borderLeft: borderWidth + 'px solid ' + theme.dividerColor,
|
borderLeft: `${borderWidth}px solid ${theme.dividerColor}`,
|
||||||
boxSizing: 'border-box',
|
boxSizing: 'border-box',
|
||||||
paddingLeft: 10,
|
paddingLeft: 10,
|
||||||
paddingRight: 0,
|
paddingRight: 0,
|
||||||
@ -1887,9 +1887,9 @@ class NoteTextComponent extends React.Component {
|
|||||||
overflowY: 'hidden',
|
overflowY: 'hidden',
|
||||||
float: 'left',
|
float: 'left',
|
||||||
verticalAlign: 'top',
|
verticalAlign: 'top',
|
||||||
paddingTop: paddingTop + 'px',
|
paddingTop: `${paddingTop}px`,
|
||||||
lineHeight: theme.textAreaLineHeight + 'px',
|
lineHeight: `${theme.textAreaLineHeight}px`,
|
||||||
fontSize: theme.editorFontSize + 'px',
|
fontSize: `${theme.editorFontSize}px`,
|
||||||
color: theme.color,
|
color: theme.color,
|
||||||
backgroundColor: theme.backgroundColor,
|
backgroundColor: theme.backgroundColor,
|
||||||
editorTheme: theme.editorTheme,
|
editorTheme: theme.editorTheme,
|
||||||
@ -1913,7 +1913,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (visiblePanes.indexOf('viewer') >= 0 && visiblePanes.indexOf('editor') >= 0) {
|
if (visiblePanes.indexOf('viewer') >= 0 && visiblePanes.indexOf('editor') >= 0) {
|
||||||
viewerStyle.borderLeft = '1px solid ' + theme.dividerColor;
|
viewerStyle.borderLeft = `1px solid ${theme.dividerColor}`;
|
||||||
} else {
|
} else {
|
||||||
viewerStyle.borderLeft = 'none';
|
viewerStyle.borderLeft = 'none';
|
||||||
}
|
}
|
||||||
@ -2010,8 +2010,8 @@ class NoteTextComponent extends React.Component {
|
|||||||
mode={markupLanguage === Note.MARKUP_LANGUAGE_HTML ? 'text' : 'markdown'}
|
mode={markupLanguage === Note.MARKUP_LANGUAGE_HTML ? 'text' : 'markdown'}
|
||||||
theme={editorRootStyle.editorTheme}
|
theme={editorRootStyle.editorTheme}
|
||||||
style={editorRootStyle}
|
style={editorRootStyle}
|
||||||
width={editorStyle.width + 'px'}
|
width={`${editorStyle.width}px`}
|
||||||
height={editorStyle.height + 'px'}
|
height={`${editorStyle.height}px`}
|
||||||
fontSize={editorStyle.fontSize}
|
fontSize={editorStyle.fontSize}
|
||||||
showGutter={false}
|
showGutter={false}
|
||||||
name="note-editor"
|
name="note-editor"
|
||||||
@ -2038,7 +2038,7 @@ class NoteTextComponent extends React.Component {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const noteSearchBarComp = !this.state.showLocalSearch ? null : <NoteSearchBar ref={this.noteSearchBar_} style={{ display: 'flex', height: searchBarHeight, width: innerWidth, borderTop: '1px solid ' + theme.dividerColor }} onChange={this.noteSearchBar_change} onNext={this.noteSearchBar_next} onPrevious={this.noteSearchBar_previous} onClose={this.noteSearchBar_close} />;
|
const noteSearchBarComp = !this.state.showLocalSearch ? null : <NoteSearchBar ref={this.noteSearchBar_} style={{ display: 'flex', height: searchBarHeight, width: innerWidth, borderTop: `1px solid ${theme.dividerColor}` }} onChange={this.noteSearchBar_change} onNext={this.noteSearchBar_next} onPrevious={this.noteSearchBar_previous} onClose={this.noteSearchBar_close} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={rootStyle} onDrop={this.onDrop_}>
|
<div style={rootStyle} onDrop={this.onDrop_}>
|
||||||
|
@ -56,7 +56,7 @@ class OneDriveLoginScreenComponent extends React.Component {
|
|||||||
this.props.dispatch({ type: 'NAV_BACK' });
|
this.props.dispatch({ type: 'NAV_BACK' });
|
||||||
reg.scheduleSync(0);
|
reg.scheduleSync(0);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
bridge().showErrorMessageBox('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;
|
this.authCode_ = null;
|
||||||
|
@ -39,7 +39,7 @@ class PromptDialog extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
styles(themeId, width, height, visible) {
|
styles(themeId, width, height, visible) {
|
||||||
const styleKey = themeId + '_' + width + '_' + height + '_' + visible;
|
const styleKey = `${themeId}_${width}_${height}_${visible}`;
|
||||||
if (styleKey === this.styleKey_) return this.styles_;
|
if (styleKey === this.styleKey_) return this.styles_;
|
||||||
|
|
||||||
const theme = themeStyle(themeId);
|
const theme = themeStyle(themeId);
|
||||||
@ -61,7 +61,7 @@ class PromptDialog extends React.Component {
|
|||||||
display: visible ? 'flex' : 'none',
|
display: visible ? 'flex' : 'none',
|
||||||
alignItems: 'flex-start',
|
alignItems: 'flex-start',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
paddingTop: paddingTop + 'px',
|
paddingTop: `${paddingTop}px`,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.styles_.promptDialog = {
|
this.styles_.promptDialog = {
|
||||||
|
@ -427,7 +427,7 @@ class SideBarComponent extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const iconName = this.props.collapsedFolderIds.indexOf(folder.id) >= 0 ? 'fa-plus-square' : 'fa-minus-square';
|
const iconName = this.props.collapsedFolderIds.indexOf(folder.id) >= 0 ? 'fa-plus-square' : 'fa-minus-square';
|
||||||
const expandIcon = <i style={expandIconStyle} className={'fa ' + iconName}></i>;
|
const expandIcon = <i style={expandIconStyle} className={`fa ${iconName}`}></i>;
|
||||||
const expandLink = hasChildren ? (
|
const expandLink = hasChildren ? (
|
||||||
<a style={expandLinkStyle} href="#" folderid={folder.id} onClick={this.onFolderToggleClick_}>
|
<a style={expandLinkStyle} href="#" folderid={folder.id} onClick={this.onFolderToggleClick_}>
|
||||||
{expandIcon}
|
{expandIcon}
|
||||||
@ -515,7 +515,7 @@ class SideBarComponent extends React.Component {
|
|||||||
|
|
||||||
makeHeader(key, label, iconName, extraProps = {}) {
|
makeHeader(key, label, iconName, extraProps = {}) {
|
||||||
const style = this.style().header;
|
const style = this.style().header;
|
||||||
const icon = <i style={{ fontSize: style.fontSize, marginRight: 5 }} className={'fa ' + iconName} />;
|
const icon = <i style={{ fontSize: style.fontSize, marginRight: 5 }} className={`fa ${iconName}`} />;
|
||||||
|
|
||||||
if (extraProps.toggleblock || extraProps.onClick) {
|
if (extraProps.toggleblock || extraProps.onClick) {
|
||||||
style.cursor = 'pointer';
|
style.cursor = 'pointer';
|
||||||
@ -603,7 +603,7 @@ class SideBarComponent extends React.Component {
|
|||||||
|
|
||||||
const focusItem = focusItems[newIndex];
|
const focusItem = focusItems[newIndex];
|
||||||
|
|
||||||
let actionName = focusItem.type.toUpperCase() + '_SELECT';
|
let actionName = `${focusItem.type.toUpperCase()}_SELECT`;
|
||||||
|
|
||||||
this.props.dispatch({
|
this.props.dispatch({
|
||||||
type: actionName,
|
type: actionName,
|
||||||
@ -664,7 +664,7 @@ class SideBarComponent extends React.Component {
|
|||||||
iconStyle.animation = 'icon-infinite-rotation 1s linear infinite';
|
iconStyle.animation = 'icon-infinite-rotation 1s linear infinite';
|
||||||
}
|
}
|
||||||
|
|
||||||
const icon = <i style={iconStyle} className={'fa ' + iconName} />;
|
const icon = <i style={iconStyle} className={`fa ${iconName}`} />;
|
||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
className="synchronize-button"
|
className="synchronize-button"
|
||||||
|
@ -27,7 +27,7 @@ class StatusScreenComponent extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async exportDebugReportClick() {
|
async exportDebugReportClick() {
|
||||||
const filename = 'syncReport-' + new Date().getTime() + '.csv';
|
const filename = `syncReport-${new Date().getTime()}.csv`;
|
||||||
|
|
||||||
const filePath = bridge().showSaveDialog({
|
const filePath = bridge().showSaveDialog({
|
||||||
title: _('Please select where the sync status should be exported to'),
|
title: _('Please select where the sync status should be exported to'),
|
||||||
@ -57,7 +57,7 @@ class StatusScreenComponent extends React.Component {
|
|||||||
|
|
||||||
function renderSectionTitleHtml(key, title) {
|
function renderSectionTitleHtml(key, title) {
|
||||||
return (
|
return (
|
||||||
<h2 key={'section_' + key} style={theme.h2Style}>
|
<h2 key={`section_${key}`} style={theme.h2Style}>
|
||||||
{title}
|
{title}
|
||||||
</h2>
|
</h2>
|
||||||
);
|
);
|
||||||
@ -95,7 +95,7 @@ class StatusScreenComponent extends React.Component {
|
|||||||
if (!text) text = '\xa0';
|
if (!text) text = '\xa0';
|
||||||
|
|
||||||
itemsHtml.push(
|
itemsHtml.push(
|
||||||
<div style={theme.textStyle} key={'item_' + n}>
|
<div style={theme.textStyle} key={`item_${n}`}>
|
||||||
<span>{text}</span>
|
<span>{text}</span>
|
||||||
{retryLink}
|
{retryLink}
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,7 +11,7 @@ class TagListComponent extends React.Component {
|
|||||||
|
|
||||||
style.display = 'flex';
|
style.display = 'flex';
|
||||||
style.flexDirection = 'row';
|
style.flexDirection = 'row';
|
||||||
style.borderBottom = '1px solid ' + theme.dividerColor;
|
style.borderBottom = `1px solid ${theme.dividerColor}`;
|
||||||
style.boxSizing = 'border-box';
|
style.boxSizing = 'border-box';
|
||||||
style.fontSize = theme.fontSize;
|
style.fontSize = theme.fontSize;
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ class ToolbarComponent extends React.Component {
|
|||||||
style.height = theme.toolbarHeight;
|
style.height = theme.toolbarHeight;
|
||||||
style.display = 'flex';
|
style.display = 'flex';
|
||||||
style.flexDirection = 'row';
|
style.flexDirection = 'row';
|
||||||
style.borderBottom = '1px solid ' + theme.dividerColor;
|
style.borderBottom = `1px solid ${theme.dividerColor}`;
|
||||||
style.boxSizing = 'border-box';
|
style.boxSizing = 'border-box';
|
||||||
|
|
||||||
const itemComps = [];
|
const itemComps = [];
|
||||||
@ -23,7 +23,7 @@ class ToolbarComponent extends React.Component {
|
|||||||
key += o.title ? o.title : '';
|
key += o.title ? o.title : '';
|
||||||
const itemType = !('type' in o) ? 'button' : o.type;
|
const itemType = !('type' in o) ? 'button' : o.type;
|
||||||
|
|
||||||
if (!key) key = o.type + '_' + i;
|
if (!key) key = `${o.type}_${i}`;
|
||||||
|
|
||||||
const props = Object.assign(
|
const props = Object.assign(
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@ class ToolbarButton extends React.Component {
|
|||||||
color: theme.color,
|
color: theme.color,
|
||||||
};
|
};
|
||||||
if (title) iconStyle.marginRight = 5;
|
if (title) iconStyle.marginRight = 5;
|
||||||
icon = <i style={iconStyle} className={'fa ' + this.props.iconName}></i>;
|
icon = <i style={iconStyle} className={`fa ${this.props.iconName}`}></i>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isEnabled = !('enabled' in this.props) || this.props.enabled === true;
|
const isEnabled = !('enabled' in this.props) || this.props.enabled === true;
|
||||||
|
@ -128,7 +128,7 @@ class NoteListUtils {
|
|||||||
if (noteIds.length === 1) {
|
if (noteIds.length === 1) {
|
||||||
exportMenu.append(
|
exportMenu.append(
|
||||||
new MenuItem({
|
new MenuItem({
|
||||||
label: 'PDF - ' + _('PDF File'),
|
label: `PDF - ${_('PDF File')}`,
|
||||||
click: () => {
|
click: () => {
|
||||||
props.dispatch({
|
props.dispatch({
|
||||||
type: 'WINDOW_COMMAND',
|
type: 'WINDOW_COMMAND',
|
||||||
|
@ -132,7 +132,7 @@ class Dialog extends React.PureComponent {
|
|||||||
const s = splitted[i].trim();
|
const s = splitted[i].trim();
|
||||||
if (!s) continue;
|
if (!s) continue;
|
||||||
|
|
||||||
output.push('title:' + s + '*');
|
output.push(`title:${s}*`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return output.join(' ');
|
return output.join(' ');
|
||||||
@ -153,11 +153,11 @@ class Dialog extends React.PureComponent {
|
|||||||
|
|
||||||
if (this.state.query.indexOf('#') === 0) { // TAGS
|
if (this.state.query.indexOf('#') === 0) { // TAGS
|
||||||
listType = BaseModel.TYPE_TAG;
|
listType = BaseModel.TYPE_TAG;
|
||||||
searchQuery = '*' + this.state.query.split(' ')[0].substr(1).trim() + '*';
|
searchQuery = `*${this.state.query.split(' ')[0].substr(1).trim()}*`;
|
||||||
results = await Tag.searchAllWithNotes({ titlePattern: searchQuery });
|
results = await Tag.searchAllWithNotes({ titlePattern: searchQuery });
|
||||||
} else if (this.state.query.indexOf('@') === 0) { // FOLDERS
|
} else if (this.state.query.indexOf('@') === 0) { // FOLDERS
|
||||||
listType = BaseModel.TYPE_FOLDER;
|
listType = BaseModel.TYPE_FOLDER;
|
||||||
searchQuery = '*' + this.state.query.split(' ')[0].substr(1).trim() + '*';
|
searchQuery = `*${this.state.query.split(' ')[0].substr(1).trim()}*`;
|
||||||
results = await Folder.search({ titlePattern: searchQuery });
|
results = await Folder.search({ titlePattern: searchQuery });
|
||||||
|
|
||||||
for (let i = 0; i < results.length; i++) {
|
for (let i = 0; i < results.length; i++) {
|
||||||
@ -246,7 +246,7 @@ class Dialog extends React.PureComponent {
|
|||||||
const theme = themeStyle(this.props.theme);
|
const theme = themeStyle(this.props.theme);
|
||||||
const style = this.style();
|
const style = this.style();
|
||||||
const rowStyle = item.id === this.state.selectedItemId ? style.rowSelected : style.row;
|
const rowStyle = item.id === this.state.selectedItemId ? style.rowSelected : style.row;
|
||||||
const titleHtml = surroundKeywords(this.state.keywords, item.title, '<span style="font-weight: bold; color: ' + theme.colorBright + ';">', '</span>');
|
const titleHtml = surroundKeywords(this.state.keywords, item.title, `<span style="font-weight: bold; color: ${theme.colorBright};">`, '</span>');
|
||||||
|
|
||||||
const pathComp = !item.path ? null : <div style={style.rowPath}>{item.path}</div>;
|
const pathComp = !item.path ? null : <div style={style.rowPath}>{item.path}</div>;
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ globalStyle.marginRight = globalStyle.margin;
|
|||||||
globalStyle.marginLeft = globalStyle.margin;
|
globalStyle.marginLeft = globalStyle.margin;
|
||||||
globalStyle.marginTop = globalStyle.margin;
|
globalStyle.marginTop = globalStyle.margin;
|
||||||
globalStyle.marginBottom = globalStyle.margin;
|
globalStyle.marginBottom = globalStyle.margin;
|
||||||
globalStyle.htmlMarginLeft = ((globalStyle.marginLeft / 10) * 0.6).toFixed(2) + 'em';
|
globalStyle.htmlMarginLeft = `${((globalStyle.marginLeft / 10) * 0.6).toFixed(2)}em`;
|
||||||
|
|
||||||
globalStyle.icon = {
|
globalStyle.icon = {
|
||||||
fontSize: 30,
|
fontSize: 30,
|
||||||
@ -348,7 +348,7 @@ function themeStyle(theme) {
|
|||||||
textAreaLineHeight: Math.round(globalStyle.textAreaLineHeight * editorFontSize / 12),
|
textAreaLineHeight: Math.round(globalStyle.textAreaLineHeight * editorFontSize / 12),
|
||||||
|
|
||||||
// For WebView - must correspond to the properties above
|
// For WebView - must correspond to the properties above
|
||||||
htmlFontSize: Math.round(15 * zoomRatio) + 'px',
|
htmlFontSize: `${Math.round(15 * zoomRatio)}px`,
|
||||||
htmlLineHeight: '1.6em', //Math.round(20 * zoomRatio) + 'px'
|
htmlLineHeight: '1.6em', //Math.round(20 * zoomRatio) + 'px'
|
||||||
|
|
||||||
htmlCodeFontSize: '.9em',
|
htmlCodeFontSize: '.9em',
|
||||||
|
@ -509,9 +509,9 @@ class BaseApplication {
|
|||||||
determineProfileDir(initArgs) {
|
determineProfileDir(initArgs) {
|
||||||
if (initArgs.profileDir) return initArgs.profileDir;
|
if (initArgs.profileDir) return initArgs.profileDir;
|
||||||
|
|
||||||
if (process && process.env && process.env.PORTABLE_EXECUTABLE_DIR) return process.env.PORTABLE_EXECUTABLE_DIR + '/JoplinProfile';
|
if (process && process.env && process.env.PORTABLE_EXECUTABLE_DIR) return `${process.env.PORTABLE_EXECUTABLE_DIR}/JoplinProfile`;
|
||||||
|
|
||||||
return os.homedir() + '/.config/' + Setting.value('appName');
|
return `${os.homedir()}/.config/${Setting.value('appName')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
async testing() {
|
async testing() {
|
||||||
@ -548,12 +548,12 @@ class BaseApplication {
|
|||||||
|
|
||||||
const profileDir = this.determineProfileDir(initArgs);
|
const profileDir = this.determineProfileDir(initArgs);
|
||||||
const resourceDirName = 'resources';
|
const resourceDirName = 'resources';
|
||||||
const resourceDir = profileDir + '/' + resourceDirName;
|
const resourceDir = `${profileDir}/${resourceDirName}`;
|
||||||
const tempDir = profileDir + '/tmp';
|
const tempDir = `${profileDir}/tmp`;
|
||||||
|
|
||||||
Setting.setConstant('env', initArgs.env);
|
Setting.setConstant('env', initArgs.env);
|
||||||
Setting.setConstant('profileDir', profileDir);
|
Setting.setConstant('profileDir', profileDir);
|
||||||
Setting.setConstant('templateDir', profileDir + '/templates');
|
Setting.setConstant('templateDir', `${profileDir}/templates`);
|
||||||
Setting.setConstant('resourceDirName', resourceDirName);
|
Setting.setConstant('resourceDirName', resourceDirName);
|
||||||
Setting.setConstant('resourceDir', resourceDir);
|
Setting.setConstant('resourceDir', resourceDir);
|
||||||
Setting.setConstant('tempDir', tempDir);
|
Setting.setConstant('tempDir', tempDir);
|
||||||
@ -567,29 +567,29 @@ class BaseApplication {
|
|||||||
// Clean up any remaining watched files (they start with "edit-")
|
// Clean up any remaining watched files (they start with "edit-")
|
||||||
await shim.fsDriver().removeAllThatStartWith(profileDir, 'edit-');
|
await shim.fsDriver().removeAllThatStartWith(profileDir, 'edit-');
|
||||||
|
|
||||||
const extraFlags = await this.readFlagsFromFile(profileDir + '/flags.txt');
|
const extraFlags = await this.readFlagsFromFile(`${profileDir}/flags.txt`);
|
||||||
initArgs = Object.assign(initArgs, extraFlags);
|
initArgs = Object.assign(initArgs, extraFlags);
|
||||||
|
|
||||||
this.logger_.addTarget('file', { path: profileDir + '/log.txt' });
|
this.logger_.addTarget('file', { path: `${profileDir}/log.txt` });
|
||||||
if (Setting.value('env') === 'dev') this.logger_.addTarget('console', { level: Logger.LEVEL_WARN });
|
if (Setting.value('env') === 'dev') this.logger_.addTarget('console', { level: Logger.LEVEL_WARN });
|
||||||
this.logger_.setLevel(initArgs.logLevel);
|
this.logger_.setLevel(initArgs.logLevel);
|
||||||
|
|
||||||
reg.setLogger(this.logger_);
|
reg.setLogger(this.logger_);
|
||||||
reg.dispatch = () => {};
|
reg.dispatch = () => {};
|
||||||
|
|
||||||
this.dbLogger_.addTarget('file', { path: profileDir + '/log-database.txt' });
|
this.dbLogger_.addTarget('file', { path: `${profileDir}/log-database.txt` });
|
||||||
this.dbLogger_.setLevel(initArgs.logLevel);
|
this.dbLogger_.setLevel(initArgs.logLevel);
|
||||||
|
|
||||||
if (Setting.value('env') === 'dev') {
|
if (Setting.value('env') === 'dev') {
|
||||||
this.dbLogger_.setLevel(Logger.LEVEL_INFO);
|
this.dbLogger_.setLevel(Logger.LEVEL_INFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger_.info('Profile directory: ' + profileDir);
|
this.logger_.info(`Profile directory: ${profileDir}`);
|
||||||
|
|
||||||
this.database_ = new JoplinDatabase(new DatabaseDriverNode());
|
this.database_ = new JoplinDatabase(new DatabaseDriverNode());
|
||||||
this.database_.setLogExcludedQueryTypes(['SELECT']);
|
this.database_.setLogExcludedQueryTypes(['SELECT']);
|
||||||
this.database_.setLogger(this.dbLogger_);
|
this.database_.setLogger(this.dbLogger_);
|
||||||
await this.database_.open({ name: profileDir + '/database.sqlite' });
|
await this.database_.open({ name: `${profileDir}/database.sqlite` });
|
||||||
|
|
||||||
// if (Setting.value('env') === 'dev') await this.database_.clearForTesting();
|
// if (Setting.value('env') === 'dev') await this.database_.clearForTesting();
|
||||||
|
|
||||||
@ -600,7 +600,7 @@ class BaseApplication {
|
|||||||
|
|
||||||
if (Setting.value('firstStart')) {
|
if (Setting.value('firstStart')) {
|
||||||
const locale = shim.detectAndSetLocale(Setting);
|
const locale = shim.detectAndSetLocale(Setting);
|
||||||
reg.logger().info('First start: detected locale as ' + locale);
|
reg.logger().info(`First start: detected locale as ${locale}`);
|
||||||
|
|
||||||
if (Setting.value('env') === 'dev') {
|
if (Setting.value('env') === 'dev') {
|
||||||
Setting.setValue('showTrayIcon', 0);
|
Setting.setValue('showTrayIcon', 0);
|
||||||
|
@ -74,7 +74,7 @@ class BaseModel {
|
|||||||
const e = BaseModel.typeEnum_[i];
|
const e = BaseModel.typeEnum_[i];
|
||||||
if (e[1] === type) return e[0].substr(5).toLowerCase();
|
if (e[1] === type) return e[0].substr(5).toLowerCase();
|
||||||
}
|
}
|
||||||
throw new Error('Unknown model type: ' + type);
|
throw new Error(`Unknown model type: ${type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static hasField(name) {
|
static hasField(name) {
|
||||||
@ -89,7 +89,7 @@ class BaseModel {
|
|||||||
let p = withPrefix === true ? this.tableName() : withPrefix;
|
let p = withPrefix === true ? this.tableName() : withPrefix;
|
||||||
let temp = [];
|
let temp = [];
|
||||||
for (let i = 0; i < output.length; i++) {
|
for (let i = 0; i < output.length; i++) {
|
||||||
temp.push(p + '.' + output[i]);
|
temp.push(`${p}.${output[i]}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return temp;
|
return temp;
|
||||||
@ -101,7 +101,7 @@ class BaseModel {
|
|||||||
if (fields[i].name == name) return fields[i].type;
|
if (fields[i].name == name) return fields[i].type;
|
||||||
}
|
}
|
||||||
if (defaultValue !== null) return defaultValue;
|
if (defaultValue !== null) return defaultValue;
|
||||||
throw new Error('Unknown field: ' + name);
|
throw new Error(`Unknown field: ${name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static fields() {
|
static fields() {
|
||||||
@ -141,8 +141,8 @@ class BaseModel {
|
|||||||
|
|
||||||
static count(options = null) {
|
static count(options = null) {
|
||||||
if (!options) options = {};
|
if (!options) options = {};
|
||||||
let sql = 'SELECT count(*) as total FROM `' + this.tableName() + '`';
|
let sql = `SELECT count(*) as total FROM \`${this.tableName()}\``;
|
||||||
if (options.where) sql += ' WHERE ' + options.where;
|
if (options.where) sql += ` WHERE ${options.where}`;
|
||||||
return this.db()
|
return this.db()
|
||||||
.selectOne(sql)
|
.selectOne(sql)
|
||||||
.then(r => {
|
.then(r => {
|
||||||
@ -159,7 +159,7 @@ class BaseModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static loadByPartialId(partialId) {
|
static loadByPartialId(partialId) {
|
||||||
return this.modelSelectAll('SELECT * FROM `' + this.tableName() + '` WHERE `id` LIKE ?', [partialId + '%']);
|
return this.modelSelectAll(`SELECT * FROM \`${this.tableName()}\` WHERE \`id\` LIKE ?`, [`${partialId}%`]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static applySqlOptions(options, sql, params = null) {
|
static applySqlOptions(options, sql, params = null) {
|
||||||
@ -171,19 +171,19 @@ class BaseModel {
|
|||||||
const o = options.order[i];
|
const o = options.order[i];
|
||||||
let item = o.by;
|
let item = o.by;
|
||||||
if (options.caseInsensitive === true) item += ' COLLATE NOCASE';
|
if (options.caseInsensitive === true) item += ' COLLATE NOCASE';
|
||||||
if (o.dir) item += ' ' + o.dir;
|
if (o.dir) item += ` ${o.dir}`;
|
||||||
items.push(item);
|
items.push(item);
|
||||||
}
|
}
|
||||||
sql += ' ORDER BY ' + items.join(', ');
|
sql += ` ORDER BY ${items.join(', ')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.limit) sql += ' LIMIT ' + options.limit;
|
if (options.limit) sql += ` LIMIT ${options.limit}`;
|
||||||
|
|
||||||
return { sql: sql, params: params };
|
return { sql: sql, params: params };
|
||||||
}
|
}
|
||||||
|
|
||||||
static async allIds(options = null) {
|
static async allIds(options = null) {
|
||||||
let q = this.applySqlOptions(options, 'SELECT id FROM `' + this.tableName() + '`');
|
let q = this.applySqlOptions(options, `SELECT id FROM \`${this.tableName()}\``);
|
||||||
const rows = await this.db().selectAll(q.sql, q.params);
|
const rows = await this.db().selectAll(q.sql, q.params);
|
||||||
return rows.map(r => r.id);
|
return rows.map(r => r.id);
|
||||||
}
|
}
|
||||||
@ -192,7 +192,7 @@ class BaseModel {
|
|||||||
if (!options) options = {};
|
if (!options) options = {};
|
||||||
if (!options.fields) options.fields = '*';
|
if (!options.fields) options.fields = '*';
|
||||||
|
|
||||||
let q = this.applySqlOptions(options, 'SELECT ' + this.db().escapeFields(options.fields) + ' FROM `' + this.tableName() + '`');
|
let q = this.applySqlOptions(options, `SELECT ${this.db().escapeFields(options.fields)} FROM \`${this.tableName()}\``);
|
||||||
return this.modelSelectAll(q.sql);
|
return this.modelSelectAll(q.sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,8 +201,8 @@ class BaseModel {
|
|||||||
if (!options) options = {};
|
if (!options) options = {};
|
||||||
if (!options.fields) options.fields = '*';
|
if (!options.fields) options.fields = '*';
|
||||||
|
|
||||||
let sql = 'SELECT ' + this.db().escapeFields(options.fields) + ' FROM `' + this.tableName() + '`';
|
let sql = `SELECT ${this.db().escapeFields(options.fields)} FROM \`${this.tableName()}\``;
|
||||||
sql += ' WHERE id IN ("' + ids.join('","') + '")';
|
sql += ` WHERE id IN ("${ids.join('","')}")`;
|
||||||
let q = this.applySqlOptions(options, sql);
|
let q = this.applySqlOptions(options, sql);
|
||||||
return this.modelSelectAll(q.sql);
|
return this.modelSelectAll(q.sql);
|
||||||
}
|
}
|
||||||
@ -222,8 +222,8 @@ class BaseModel {
|
|||||||
|
|
||||||
if ('limit' in options && options.limit <= 0) return [];
|
if ('limit' in options && options.limit <= 0) return [];
|
||||||
|
|
||||||
let sql = 'SELECT ' + this.db().escapeFields(options.fields) + ' FROM `' + this.tableName() + '`';
|
let sql = `SELECT ${this.db().escapeFields(options.fields)} FROM \`${this.tableName()}\``;
|
||||||
if (conditions.length) sql += ' WHERE ' + conditions.join(' AND ');
|
if (conditions.length) sql += ` WHERE ${conditions.join(' AND ')}`;
|
||||||
|
|
||||||
let query = this.applySqlOptions(options, sql, params);
|
let query = this.applySqlOptions(options, sql, params);
|
||||||
return this.modelSelectAll(query.sql, query.params);
|
return this.modelSelectAll(query.sql, query.params);
|
||||||
@ -250,13 +250,13 @@ class BaseModel {
|
|||||||
static loadByField(fieldName, fieldValue, options = null) {
|
static loadByField(fieldName, fieldValue, options = null) {
|
||||||
if (!options) options = {};
|
if (!options) options = {};
|
||||||
if (!('caseInsensitive' in options)) options.caseInsensitive = false;
|
if (!('caseInsensitive' in options)) options.caseInsensitive = false;
|
||||||
let sql = 'SELECT * FROM `' + this.tableName() + '` WHERE `' + fieldName + '` = ?';
|
let sql = `SELECT * FROM \`${this.tableName()}\` WHERE \`${fieldName}\` = ?`;
|
||||||
if (options.caseInsensitive) sql += ' COLLATE NOCASE';
|
if (options.caseInsensitive) sql += ' COLLATE NOCASE';
|
||||||
return this.modelSelectOne(sql, [fieldValue]);
|
return this.modelSelectOne(sql, [fieldValue]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static loadByTitle(fieldValue) {
|
static loadByTitle(fieldValue) {
|
||||||
return this.modelSelectOne('SELECT * FROM `' + this.tableName() + '` WHERE `title` = ?', [fieldValue]);
|
return this.modelSelectOne(`SELECT * FROM \`${this.tableName()}\` WHERE \`title\` = ?`, [fieldValue]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static diffObjects(oldModel, newModel) {
|
static diffObjects(oldModel, newModel) {
|
||||||
@ -514,14 +514,14 @@ class BaseModel {
|
|||||||
|
|
||||||
static delete(id) {
|
static delete(id) {
|
||||||
if (!id) throw new Error('Cannot delete object without an ID');
|
if (!id) throw new Error('Cannot delete object without an ID');
|
||||||
return this.db().exec('DELETE FROM ' + this.tableName() + ' WHERE id = ?', [id]);
|
return this.db().exec(`DELETE FROM ${this.tableName()} WHERE id = ?`, [id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static batchDelete(ids, options = null) {
|
static batchDelete(ids, options = null) {
|
||||||
if (!ids.length) return;
|
if (!ids.length) return;
|
||||||
options = this.modOptions(options);
|
options = this.modOptions(options);
|
||||||
const idFieldName = options.idFieldName ? options.idFieldName : 'id';
|
const idFieldName = options.idFieldName ? options.idFieldName : 'id';
|
||||||
const sql = 'DELETE FROM ' + this.tableName() + ' WHERE ' + idFieldName + ' IN ("' + ids.join('","') + '")';
|
const sql = `DELETE FROM ${this.tableName()} WHERE ${idFieldName} IN ("${ids.join('","')}")`;
|
||||||
return this.db().exec(sql);
|
return this.db().exec(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ class Cache {
|
|||||||
Cache.storage = async function() {
|
Cache.storage = async function() {
|
||||||
if (Cache.storage_) return Cache.storage_;
|
if (Cache.storage_) return Cache.storage_;
|
||||||
Cache.storage_ = require('node-persist');
|
Cache.storage_ = require('node-persist');
|
||||||
await Cache.storage_.init({ dir: require('os').tmpdir() + '/joplin-cache', ttl: 1000 * 60 });
|
await Cache.storage_.init({ dir: `${require('os').tmpdir()}/joplin-cache`, ttl: 1000 * 60 });
|
||||||
return Cache.storage_;
|
return Cache.storage_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ class ClipperServer {
|
|||||||
if (instance.type === 'attachment') {
|
if (instance.type === 'attachment') {
|
||||||
const filename = instance.attachmentFilename ? instance.attachmentFilename : 'file';
|
const filename = instance.attachmentFilename ? instance.attachmentFilename : 'file';
|
||||||
writeCorsHeaders(code, instance.contentType ? instance.contentType : 'application/octet-stream', {
|
writeCorsHeaders(code, instance.contentType ? instance.contentType : 'application/octet-stream', {
|
||||||
'Content-disposition': 'attachment; filename=' + filename,
|
'Content-disposition': `attachment; filename=${filename}`,
|
||||||
'Content-Length': instance.body.length,
|
'Content-Length': instance.body.length,
|
||||||
});
|
});
|
||||||
response.end(instance.body);
|
response.end(instance.body);
|
||||||
@ -148,7 +148,7 @@ class ClipperServer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.logger().info('Request: ' + request.method + ' ' + request.url);
|
this.logger().info(`Request: ${request.method} ${request.url}`);
|
||||||
|
|
||||||
const url = urlParser.parse(request.url, true);
|
const url = urlParser.parse(request.url, true);
|
||||||
|
|
||||||
@ -204,7 +204,7 @@ class ClipperServer {
|
|||||||
|
|
||||||
enableServerDestroy(this.server_);
|
enableServerDestroy(this.server_);
|
||||||
|
|
||||||
this.logger().info('Starting Clipper server on port ' + this.port_);
|
this.logger().info(`Starting Clipper server on port ${this.port_}`);
|
||||||
|
|
||||||
this.server_.listen(this.port_, '127.0.0.1');
|
this.server_.listen(this.port_, '127.0.0.1');
|
||||||
|
|
||||||
|
@ -42,25 +42,25 @@ class DropboxApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loginUrl() {
|
loginUrl() {
|
||||||
return 'https://www.dropbox.com/oauth2/authorize?response_type=code&client_id=' + this.clientId();
|
return `https://www.dropbox.com/oauth2/authorize?response_type=code&client_id=${this.clientId()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
baseUrl(endPointFormat) {
|
baseUrl(endPointFormat) {
|
||||||
if (['content', 'api'].indexOf(endPointFormat) < 0) throw new Error('Invalid end point format: ' + endPointFormat);
|
if (['content', 'api'].indexOf(endPointFormat) < 0) throw new Error(`Invalid end point format: ${endPointFormat}`);
|
||||||
return 'https://' + endPointFormat + '.dropboxapi.com/2';
|
return `https://${endPointFormat}.dropboxapi.com/2`;
|
||||||
}
|
}
|
||||||
|
|
||||||
requestToCurl_(url, options) {
|
requestToCurl_(url, options) {
|
||||||
let output = [];
|
let output = [];
|
||||||
output.push('curl');
|
output.push('curl');
|
||||||
if (options.method) output.push('-X ' + options.method);
|
if (options.method) output.push(`-X ${options.method}`);
|
||||||
if (options.headers) {
|
if (options.headers) {
|
||||||
for (let n in options.headers) {
|
for (let n in options.headers) {
|
||||||
if (!options.headers.hasOwnProperty(n)) continue;
|
if (!options.headers.hasOwnProperty(n)) continue;
|
||||||
output.push('-H ' + '\'' + n + ': ' + options.headers[n] + '\'');
|
output.push(`${'-H ' + '\''}${n}: ${options.headers[n]}'`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (options.body) output.push('--data ' + '"' + options.body + '"');
|
if (options.body) output.push(`${'--data ' + '"'}${options.body}"`);
|
||||||
output.push(url);
|
output.push(url);
|
||||||
|
|
||||||
return output.join(' ');
|
return output.join(' ');
|
||||||
@ -78,7 +78,7 @@ class DropboxApi {
|
|||||||
for (var property in postData) {
|
for (var property in postData) {
|
||||||
var encodedKey = encodeURIComponent(property);
|
var encodedKey = encodeURIComponent(property);
|
||||||
var encodedValue = encodeURIComponent(postData[property]);
|
var encodedValue = encodeURIComponent(postData[property]);
|
||||||
formBody.push(encodedKey + '=' + encodedValue);
|
formBody.push(`${encodedKey}=${encodedValue}`);
|
||||||
}
|
}
|
||||||
formBody = formBody.join('&');
|
formBody = formBody.join('&');
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ class DropboxApi {
|
|||||||
|
|
||||||
const authToken = this.authToken();
|
const authToken = this.authToken();
|
||||||
|
|
||||||
if (authToken) headers['Authorization'] = 'Bearer ' + authToken;
|
if (authToken) headers['Authorization'] = `Bearer ${authToken}`;
|
||||||
|
|
||||||
const endPointFormat = ['files/upload', 'files/download'].indexOf(path) >= 0 ? 'content' : 'api';
|
const endPointFormat = ['files/upload', 'files/download'].indexOf(path) >= 0 ? 'content' : 'api';
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ class DropboxApi {
|
|||||||
if (options.path) fetchOptions.path = options.path;
|
if (options.path) fetchOptions.path = options.path;
|
||||||
if (body) fetchOptions.body = body;
|
if (body) fetchOptions.body = body;
|
||||||
|
|
||||||
const url = path.indexOf('https://') === 0 ? path : this.baseUrl(endPointFormat) + '/' + path;
|
const url = path.indexOf('https://') === 0 ? path : `${this.baseUrl(endPointFormat)}/${path}`;
|
||||||
|
|
||||||
let tryCount = 0;
|
let tryCount = 0;
|
||||||
|
|
||||||
@ -174,8 +174,8 @@ class DropboxApi {
|
|||||||
|
|
||||||
// Gives a shorter response for error messages. Useful for cases where a full HTML page is accidentally loaded instead of
|
// Gives a shorter response for error messages. Useful for cases where a full HTML page is accidentally loaded instead of
|
||||||
// JSON. That way the error message will still show there's a problem but without filling up the log or screen.
|
// JSON. That way the error message will still show there's a problem but without filling up the log or screen.
|
||||||
const shortResponseText = (responseText + '').substr(0, 1024);
|
const shortResponseText = (`${responseText}`).substr(0, 1024);
|
||||||
const error = new JoplinError(method + ' ' + path + ': ' + message + ' (' + response.status + '): ' + shortResponseText, code);
|
const error = new JoplinError(`${method} ${path}: ${message} (${response.status}): ${shortResponseText}`, code);
|
||||||
error.httpStatus = response.status;
|
error.httpStatus = response.status;
|
||||||
return error;
|
return error;
|
||||||
};
|
};
|
||||||
@ -197,7 +197,7 @@ class DropboxApi {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
tryCount++;
|
tryCount++;
|
||||||
if (error && typeof error.code === 'string' && error.code.indexOf('too_many_write_operations') >= 0) {
|
if (error && typeof error.code === 'string' && error.code.indexOf('too_many_write_operations') >= 0) {
|
||||||
this.logger().warn('too_many_write_operations ' + tryCount);
|
this.logger().warn(`too_many_write_operations ${tryCount}`);
|
||||||
if (tryCount >= 3) {
|
if (tryCount >= 3) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
@ -52,10 +52,10 @@ class SyncTargetDropbox extends BaseSyncTarget {
|
|||||||
|
|
||||||
api.on('authRefreshed', auth => {
|
api.on('authRefreshed', auth => {
|
||||||
this.logger().info('Saving updated Dropbox auth.');
|
this.logger().info('Saving updated Dropbox auth.');
|
||||||
Setting.setValue('sync.' + SyncTargetDropbox.id() + '.auth', auth ? auth : null);
|
Setting.setValue(`sync.${SyncTargetDropbox.id()}.auth`, auth ? auth : null);
|
||||||
});
|
});
|
||||||
|
|
||||||
const authToken = Setting.value('sync.' + SyncTargetDropbox.id() + '.auth');
|
const authToken = Setting.value(`sync.${SyncTargetDropbox.id()}.auth`);
|
||||||
api.setAuthToken(authToken);
|
api.setAuthToken(authToken);
|
||||||
|
|
||||||
const appDir = '';
|
const appDir = '';
|
||||||
|
@ -51,10 +51,10 @@ class SyncTargetOneDrive extends BaseSyncTarget {
|
|||||||
|
|
||||||
this.api_.on('authRefreshed', a => {
|
this.api_.on('authRefreshed', a => {
|
||||||
this.logger().info('Saving updated OneDrive auth.');
|
this.logger().info('Saving updated OneDrive auth.');
|
||||||
Setting.setValue('sync.' + this.syncTargetId() + '.auth', a ? JSON.stringify(a) : null);
|
Setting.setValue(`sync.${this.syncTargetId()}.auth`, a ? JSON.stringify(a) : null);
|
||||||
});
|
});
|
||||||
|
|
||||||
let auth = Setting.value('sync.' + this.syncTargetId() + '.auth');
|
let auth = Setting.value(`sync.${this.syncTargetId()}.auth`);
|
||||||
if (auth) {
|
if (auth) {
|
||||||
try {
|
try {
|
||||||
auth = JSON.parse(auth);
|
auth = JSON.parse(auth);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
class SyncTargetRegistry {
|
class SyncTargetRegistry {
|
||||||
static classById(syncTargetId) {
|
static classById(syncTargetId) {
|
||||||
const info = SyncTargetRegistry.reg_[syncTargetId];
|
const info = SyncTargetRegistry.reg_[syncTargetId];
|
||||||
if (!info) throw new Error('Invalid id: ' + syncTargetId);
|
if (!info) throw new Error(`Invalid id: ${syncTargetId}`);
|
||||||
return info.classRef;
|
return info.classRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ class SyncTargetRegistry {
|
|||||||
if (!this.reg_.hasOwnProperty(n)) continue;
|
if (!this.reg_.hasOwnProperty(n)) continue;
|
||||||
if (this.reg_[n].name === name) return this.reg_[n].id;
|
if (this.reg_[n].name === name) return this.reg_[n].id;
|
||||||
}
|
}
|
||||||
throw new Error('Name not found: ' + name);
|
throw new Error(`Name not found: ${name}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static idToMetadata(id) {
|
static idToMetadata(id) {
|
||||||
@ -28,7 +28,7 @@ class SyncTargetRegistry {
|
|||||||
if (!this.reg_.hasOwnProperty(n)) continue;
|
if (!this.reg_.hasOwnProperty(n)) continue;
|
||||||
if (this.reg_[n].id === id) return this.reg_[n];
|
if (this.reg_[n].id === id) return this.reg_[n];
|
||||||
}
|
}
|
||||||
throw new Error('ID not found: ' + id);
|
throw new Error(`ID not found: ${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static idToName(id) {
|
static idToName(id) {
|
||||||
|
@ -52,11 +52,11 @@ class SyncTargetWebDAV extends BaseSyncTarget {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await fileApi.stat('');
|
const result = await fileApi.stat('');
|
||||||
if (!result) throw new Error('WebDAV directory not found: ' + options.path());
|
if (!result) throw new Error(`WebDAV directory not found: ${options.path()}`);
|
||||||
output.ok = true;
|
output.ok = true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
output.errorMessage = error.message;
|
output.errorMessage = error.message;
|
||||||
if (error.code) output.errorMessage += ' (Code ' + error.code + ')';
|
if (error.code) output.errorMessage += ` (Code ${error.code})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
@ -80,7 +80,7 @@ class TaskQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async waitForResult(taskId) {
|
async waitForResult(taskId) {
|
||||||
if (!this.isWaiting(taskId) && !this.isProcessing(taskId) && !this.isDone(taskId)) throw new Error('No such task: ' + taskId);
|
if (!this.isWaiting(taskId) && !this.isProcessing(taskId) && !this.isDone(taskId)) throw new Error(`No such task: ${taskId}`);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// if (this.stopping_) {
|
// if (this.stopping_) {
|
||||||
@ -99,7 +99,7 @@ class TaskQueue {
|
|||||||
async stop() {
|
async stop() {
|
||||||
this.stopping_ = true;
|
this.stopping_ = true;
|
||||||
|
|
||||||
this.logger_.info('TaskQueue.stop: ' + this.name_ + ': waiting for tasks to complete: ' + Object.keys(this.processingTasks_).length);
|
this.logger_.info(`TaskQueue.stop: ${this.name_}: waiting for tasks to complete: ${Object.keys(this.processingTasks_).length}`);
|
||||||
|
|
||||||
// In general it's not a big issue if some tasks are still running because
|
// In general it's not a big issue if some tasks are still running because
|
||||||
// it won't call anything unexpected in caller code, since the caller has
|
// it won't call anything unexpected in caller code, since the caller has
|
||||||
@ -108,12 +108,12 @@ class TaskQueue {
|
|||||||
while (Object.keys(this.processingTasks_).length) {
|
while (Object.keys(this.processingTasks_).length) {
|
||||||
await time.sleep(0.1);
|
await time.sleep(0.1);
|
||||||
if (Date.now() - startTime >= 30000) {
|
if (Date.now() - startTime >= 30000) {
|
||||||
this.logger_.warn('TaskQueue.stop: ' + this.name_ + ': timed out waiting for task to complete');
|
this.logger_.warn(`TaskQueue.stop: ${this.name_}: timed out waiting for task to complete`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger_.info('TaskQueue.stop: ' + this.name_ + ': Done, waited for ' + (Date.now() - startTime));
|
this.logger_.info(`TaskQueue.stop: ${this.name_}: Done, waited for ${Date.now() - startTime}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
isStopping() {
|
isStopping() {
|
||||||
|
@ -38,7 +38,7 @@ TemplateUtils.loadTemplates = async function(filePath) {
|
|||||||
files = await shim.fsDriver().readDirStats(filePath);
|
files = await shim.fsDriver().readDirStats(filePath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let msg = error.message ? error.message : '';
|
let msg = error.message ? error.message : '';
|
||||||
msg = 'Could not read template names from ' + filePath + '\n' + msg;
|
msg = `Could not read template names from ${filePath}\n${msg}`;
|
||||||
error.message = msg;
|
error.message = msg;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@ -50,11 +50,11 @@ TemplateUtils.loadTemplates = async function(filePath) {
|
|||||||
files.forEach(async file => {
|
files.forEach(async file => {
|
||||||
if (file.path.endsWith('.md')) {
|
if (file.path.endsWith('.md')) {
|
||||||
try {
|
try {
|
||||||
let fileString = await shim.fsDriver().readFile(filePath + '/' + file.path, 'utf-8');
|
let fileString = await shim.fsDriver().readFile(`${filePath}/${file.path}`, 'utf-8');
|
||||||
templates.push({ label: file.path, value: fileString });
|
templates.push({ label: file.path, value: fileString });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let msg = error.message ? error.message : '';
|
let msg = error.message ? error.message : '';
|
||||||
msg = 'Could not load template ' + file.path + '\n' + msg;
|
msg = `Could not load template ${file.path}\n${msg}`;
|
||||||
error.message = msg;
|
error.message = msg;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,9 @@ class WebDavApi {
|
|||||||
// Note: Non-ASCII passwords will throw an error about Latin1 characters - https://github.com/laurent22/joplin/issues/246
|
// Note: Non-ASCII passwords will throw an error about Latin1 characters - https://github.com/laurent22/joplin/issues/246
|
||||||
// Tried various things like the below, but it didn't work on React Native:
|
// Tried various things like the below, but it didn't work on React Native:
|
||||||
//return base64.encode(utf8.encode(this.options_.username() + ':' + this.options_.password()));
|
//return base64.encode(utf8.encode(this.options_.username() + ':' + this.options_.password()));
|
||||||
return base64.encode(this.options_.username() + ':' + this.options_.password());
|
return base64.encode(`${this.options_.username()}:${this.options_.password()}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
error.message = 'Cannot encode username/password: ' + error.message;
|
error.message = `Cannot encode username/password: ${error.message}`;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,7 +59,7 @@ class WebDavApi {
|
|||||||
if (p.length == 2) {
|
if (p.length == 2) {
|
||||||
const ns = p[0];
|
const ns = p[0];
|
||||||
if (davNamespaces.indexOf(ns) >= 0) {
|
if (davNamespaces.indexOf(ns) >= 0) {
|
||||||
name = 'd:' + p[1];
|
name = `d:${p[1]}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,7 +173,7 @@ class WebDavApi {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('Invalid output type: ' + outputType);
|
throw new Error(`Invalid output type: ${outputType}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async execPropFind(path, depth, fields = null, options = null) {
|
async execPropFind(path, depth, fields = null, options = null) {
|
||||||
@ -181,7 +181,7 @@ class WebDavApi {
|
|||||||
|
|
||||||
let fieldsXml = '';
|
let fieldsXml = '';
|
||||||
for (let i = 0; i < fields.length; i++) {
|
for (let i = 0; i < fields.length; i++) {
|
||||||
fieldsXml += '<' + fields[i] + '/>';
|
fieldsXml += `<${fields[i]}/>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// To find all available properties:
|
// To find all available properties:
|
||||||
@ -195,9 +195,9 @@ class WebDavApi {
|
|||||||
`<?xml version="1.0" encoding="UTF-8"?>
|
`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<d:propfind xmlns:d="DAV:">
|
<d:propfind xmlns:d="DAV:">
|
||||||
<d:prop xmlns:oc="http://owncloud.org/ns">
|
<d:prop xmlns:oc="http://owncloud.org/ns">
|
||||||
` +
|
${
|
||||||
fieldsXml +
|
fieldsXml
|
||||||
`
|
}
|
||||||
</d:prop>
|
</d:prop>
|
||||||
</d:propfind>`;
|
</d:propfind>`;
|
||||||
|
|
||||||
@ -208,14 +208,14 @@ class WebDavApi {
|
|||||||
let output = [];
|
let output = [];
|
||||||
output.push('curl');
|
output.push('curl');
|
||||||
output.push('-v');
|
output.push('-v');
|
||||||
if (options.method) output.push('-X ' + options.method);
|
if (options.method) output.push(`-X ${options.method}`);
|
||||||
if (options.headers) {
|
if (options.headers) {
|
||||||
for (let n in options.headers) {
|
for (let n in options.headers) {
|
||||||
if (!options.headers.hasOwnProperty(n)) continue;
|
if (!options.headers.hasOwnProperty(n)) continue;
|
||||||
output.push('-H ' + '"' + n + ': ' + options.headers[n] + '"');
|
output.push(`${'-H ' + '"'}${n}: ${options.headers[n]}"`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (options.body) output.push('--data ' + '\'' + options.body + '\'');
|
if (options.body) output.push(`${'--data ' + '\''}${options.body}'`);
|
||||||
output.push(url);
|
output.push(url);
|
||||||
|
|
||||||
return output.join(' ');
|
return output.join(' ');
|
||||||
@ -300,7 +300,7 @@ class WebDavApi {
|
|||||||
|
|
||||||
const authToken = this.authToken();
|
const authToken = this.authToken();
|
||||||
|
|
||||||
if (authToken) headers['Authorization'] = 'Basic ' + authToken;
|
if (authToken) headers['Authorization'] = `Basic ${authToken}`;
|
||||||
|
|
||||||
// On iOS, the network lib appends a If-None-Match header to PROPFIND calls, which is kind of correct because
|
// On iOS, the network lib appends a If-None-Match header to PROPFIND calls, which is kind of correct because
|
||||||
// the call is idempotent and thus could be cached. According to RFC-7232 though only GET and HEAD should have
|
// the call is idempotent and thus could be cached. According to RFC-7232 though only GET and HEAD should have
|
||||||
@ -311,7 +311,7 @@ class WebDavApi {
|
|||||||
// The "solution", an ugly one, is to send a purposely invalid string as eTag, which will bypass the If-None-Match check - Seafile
|
// The "solution", an ugly one, is to send a purposely invalid string as eTag, which will bypass the If-None-Match check - Seafile
|
||||||
// finds out that no resource has this ID and simply sends the requested data.
|
// finds out that no resource has this ID and simply sends the requested data.
|
||||||
// Also add a random value to make sure the eTag is unique for each call.
|
// Also add a random value to make sure the eTag is unique for each call.
|
||||||
if (['GET', 'HEAD'].indexOf(method) < 0) headers['If-None-Match'] = 'JoplinIgnore-' + Math.floor(Math.random() * 100000);
|
if (['GET', 'HEAD'].indexOf(method) < 0) headers['If-None-Match'] = `JoplinIgnore-${Math.floor(Math.random() * 100000)}`;
|
||||||
|
|
||||||
const fetchOptions = {};
|
const fetchOptions = {};
|
||||||
fetchOptions.headers = headers;
|
fetchOptions.headers = headers;
|
||||||
@ -319,7 +319,7 @@ class WebDavApi {
|
|||||||
if (options.path) fetchOptions.path = options.path;
|
if (options.path) fetchOptions.path = options.path;
|
||||||
if (body) fetchOptions.body = body;
|
if (body) fetchOptions.body = body;
|
||||||
|
|
||||||
const url = this.baseUrl() + '/' + path;
|
const url = `${this.baseUrl()}/${path}`;
|
||||||
|
|
||||||
let response = null;
|
let response = null;
|
||||||
|
|
||||||
@ -329,11 +329,11 @@ class WebDavApi {
|
|||||||
if (options.source == 'file' && (method == 'POST' || method == 'PUT')) {
|
if (options.source == 'file' && (method == 'POST' || method == 'PUT')) {
|
||||||
if (fetchOptions.path) {
|
if (fetchOptions.path) {
|
||||||
const fileStat = await shim.fsDriver().stat(fetchOptions.path);
|
const fileStat = await shim.fsDriver().stat(fetchOptions.path);
|
||||||
if (fileStat) fetchOptions.headers['Content-Length'] = fileStat.size + '';
|
if (fileStat) fetchOptions.headers['Content-Length'] = `${fileStat.size}`;
|
||||||
}
|
}
|
||||||
response = await shim.uploadBlob(url, fetchOptions);
|
response = await shim.uploadBlob(url, fetchOptions);
|
||||||
} else if (options.target == 'string') {
|
} else if (options.target == 'string') {
|
||||||
if (typeof body === 'string') fetchOptions.headers['Content-Length'] = shim.stringByteLength(body) + '';
|
if (typeof body === 'string') fetchOptions.headers['Content-Length'] = `${shim.stringByteLength(body)}`;
|
||||||
response = await shim.fetch(url, fetchOptions);
|
response = await shim.fetch(url, fetchOptions);
|
||||||
} else {
|
} else {
|
||||||
// file
|
// file
|
||||||
@ -348,8 +348,8 @@ class WebDavApi {
|
|||||||
const newError = (message, code = 0) => {
|
const newError = (message, code = 0) => {
|
||||||
// Gives a shorter response for error messages. Useful for cases where a full HTML page is accidentally loaded instead of
|
// Gives a shorter response for error messages. Useful for cases where a full HTML page is accidentally loaded instead of
|
||||||
// JSON. That way the error message will still show there's a problem but without filling up the log or screen.
|
// JSON. That way the error message will still show there's a problem but without filling up the log or screen.
|
||||||
const shortResponseText = (responseText + '').substr(0, 1024);
|
const shortResponseText = (`${responseText}`).substr(0, 1024);
|
||||||
return new JoplinError(method + ' ' + path + ': ' + message + ' (' + code + '): ' + shortResponseText, code);
|
return new JoplinError(`${method} ${path}: ${message} (${code}): ${shortResponseText}`, code);
|
||||||
};
|
};
|
||||||
|
|
||||||
let responseJson_ = null;
|
let responseJson_ = null;
|
||||||
@ -376,7 +376,7 @@ class WebDavApi {
|
|||||||
if (json && json['d:error']) {
|
if (json && json['d:error']) {
|
||||||
const code = json['d:error']['s:exception'] ? json['d:error']['s:exception'].join(' ') : response.status;
|
const code = json['d:error']['s:exception'] ? json['d:error']['s:exception'].join(' ') : response.status;
|
||||||
const message = json['d:error']['s:message'] ? json['d:error']['s:message'].join('\n') : 'Unknown error 1';
|
const message = json['d:error']['s:message'] ? json['d:error']['s:message'].join('\n') : 'Unknown error 1';
|
||||||
throw newError(message + ' (Exception ' + code + ')', response.status);
|
throw newError(`${message} (Exception ${code})`, response.status);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw newError('Unknown error 2', response.status);
|
throw newError('Unknown error 2', response.status);
|
||||||
|
@ -19,7 +19,7 @@ class WelcomeUtils {
|
|||||||
|
|
||||||
for (let i = 0; i < folderAssets.length; i++) {
|
for (let i = 0; i < folderAssets.length; i++) {
|
||||||
const folderAsset = folderAssets[i];
|
const folderAsset = folderAssets[i];
|
||||||
const folder = await Folder.save({ title: folderAsset.title + ' (' + Setting.appTypeToLabel(Setting.value('appType')) + ')' });
|
const folder = await Folder.save({ title: `${folderAsset.title} (${Setting.appTypeToLabel(Setting.value('appType'))})` });
|
||||||
if (!output.defaultFolderId) output.defaultFolderId = folder.id;
|
if (!output.defaultFolderId) output.defaultFolderId = folder.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,15 +34,15 @@ class WelcomeUtils {
|
|||||||
if (!noteAsset.resources.hasOwnProperty(resourceUrl)) continue;
|
if (!noteAsset.resources.hasOwnProperty(resourceUrl)) continue;
|
||||||
const resourceAsset = noteAsset.resources[resourceUrl];
|
const resourceAsset = noteAsset.resources[resourceUrl];
|
||||||
const ext = fileExtension(resourceUrl);
|
const ext = fileExtension(resourceUrl);
|
||||||
const tempFilePath = tempDir + '/' + uuid.create() + '.tmp.' + ext;
|
const tempFilePath = `${tempDir}/${uuid.create()}.tmp.${ext}`;
|
||||||
await shim.fsDriver().writeFile(tempFilePath, resourceAsset.body, 'base64');
|
await shim.fsDriver().writeFile(tempFilePath, resourceAsset.body, 'base64');
|
||||||
const resource = await shim.createResourceFromPath(tempFilePath, {
|
const resource = await shim.createResourceFromPath(tempFilePath, {
|
||||||
title: basename(resourceUrl),
|
title: basename(resourceUrl),
|
||||||
});
|
});
|
||||||
await shim.fsDriver().remove(tempFilePath);
|
await shim.fsDriver().remove(tempFilePath);
|
||||||
|
|
||||||
const regex = new RegExp(pregQuote('(' + resourceUrl + ')'), 'g');
|
const regex = new RegExp(pregQuote(`(${resourceUrl})`), 'g');
|
||||||
noteBody = noteBody.replace(regex, '(:/' + resource.id + ')');
|
noteBody = noteBody.replace(regex, `(:/${resource.id})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const note = await Note.save({
|
const note = await Note.save({
|
||||||
|
@ -80,7 +80,7 @@ class ActionButtonComponent extends React.Component {
|
|||||||
for (let i = 0; i < buttons.length; i++) {
|
for (let i = 0; i < buttons.length; i++) {
|
||||||
let button = buttons[i];
|
let button = buttons[i];
|
||||||
let buttonTitle = button.title ? button.title : '';
|
let buttonTitle = button.title ? button.title : '';
|
||||||
let key = buttonTitle.replace(/\s/g, '_') + '_' + button.icon;
|
let key = `${buttonTitle.replace(/\s/g, '_')}_${button.icon}`;
|
||||||
buttonComps.push(
|
buttonComps.push(
|
||||||
<ReactNativeActionButton.Item key={key} buttonColor={button.color} title={buttonTitle} onPress={button.onPress}>
|
<ReactNativeActionButton.Item key={key} buttonColor={button.color} title={buttonTitle} onPress={button.onPress}>
|
||||||
<Icon name={button.icon} style={styles.actionButtonIcon} />
|
<Icon name={button.icon} style={styles.actionButtonIcon} />
|
||||||
@ -97,7 +97,7 @@ class ActionButtonComponent extends React.Component {
|
|||||||
|
|
||||||
if (this.props.multiStates) {
|
if (this.props.multiStates) {
|
||||||
if (!this.props.buttons || !this.props.buttons.length) throw new Error('Multi-state button requires at least one state');
|
if (!this.props.buttons || !this.props.buttons.length) throw new Error('Multi-state button requires at least one state');
|
||||||
if (this.state.buttonIndex < 0 || this.state.buttonIndex >= this.props.buttons.length) throw new Error('Button index out of bounds: ' + this.state.buttonIndex + '/' + this.props.buttons.length);
|
if (this.state.buttonIndex < 0 || this.state.buttonIndex >= this.props.buttons.length) throw new Error(`Button index out of bounds: ${this.state.buttonIndex}/${this.props.buttons.length}`);
|
||||||
let button = this.props.buttons[this.state.buttonIndex];
|
let button = this.props.buttons[this.state.buttonIndex];
|
||||||
let mainIcon = <Icon name={button.icon} style={styles.actionButtonIcon} />;
|
let mainIcon = <Icon name={button.icon} style={styles.actionButtonIcon} />;
|
||||||
return (
|
return (
|
||||||
|
@ -45,7 +45,7 @@ globalStyle.marginRight = globalStyle.margin;
|
|||||||
globalStyle.marginLeft = globalStyle.margin;
|
globalStyle.marginLeft = globalStyle.margin;
|
||||||
globalStyle.marginTop = globalStyle.margin;
|
globalStyle.marginTop = globalStyle.margin;
|
||||||
globalStyle.marginBottom = globalStyle.margin;
|
globalStyle.marginBottom = globalStyle.margin;
|
||||||
globalStyle.htmlMarginLeft = ((globalStyle.marginLeft / 10) * 0.6).toFixed(2) + 'em';
|
globalStyle.htmlMarginLeft = `${((globalStyle.marginLeft / 10) * 0.6).toFixed(2)}em`;
|
||||||
|
|
||||||
let themeCache_ = {};
|
let themeCache_ = {};
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ class NoteBodyViewer extends Component {
|
|||||||
|
|
||||||
// If the length of the body has changed, then it's something other than a checkbox that has changed,
|
// If the length of the body has changed, then it's something other than a checkbox that has changed,
|
||||||
// for example a resource that has been attached to the note while in View mode. In that case, update.
|
// for example a resource that has been attached to the note while in View mode. In that case, update.
|
||||||
return (safeGetNoteProp(this.props, 'body') + '').length !== (safeGetNoteProp(nextProps, 'body') + '').length;
|
return (`${safeGetNoteProp(this.props, 'body')}`).length !== (`${safeGetNoteProp(nextProps, 'body')}`).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
rebuildMd() {
|
rebuildMd() {
|
||||||
@ -140,9 +140,9 @@ class NoteBodyViewer extends Component {
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
` +
|
${
|
||||||
html +
|
html
|
||||||
`
|
}
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
`;
|
`;
|
||||||
@ -176,7 +176,7 @@ class NoteBodyViewer extends Component {
|
|||||||
// `baseUrl` is where the images will be loaded from. So images must use a path relative to resourceDir.
|
// `baseUrl` is where the images will be loaded from. So images must use a path relative to resourceDir.
|
||||||
const source = {
|
const source = {
|
||||||
html: html,
|
html: html,
|
||||||
baseUrl: 'file://' + Setting.value('resourceDir') + '/',
|
baseUrl: `file://${Setting.value('resourceDir')}/`,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Note: useWebKit={false} is needed to go around this bug:
|
// Note: useWebKit={false} is needed to go around this bug:
|
||||||
|
@ -263,10 +263,10 @@ class ScreenHeaderComponent extends React.PureComponent {
|
|||||||
let o = this.props.menuOptions[i];
|
let o = this.props.menuOptions[i];
|
||||||
|
|
||||||
if (o.isDivider) {
|
if (o.isDivider) {
|
||||||
menuOptionComponents.push(<View key={'menuOption_' + key++} style={this.styles().divider} />);
|
menuOptionComponents.push(<View key={`menuOption_${key++}`} style={this.styles().divider} />);
|
||||||
} else {
|
} else {
|
||||||
menuOptionComponents.push(
|
menuOptionComponents.push(
|
||||||
<MenuOption value={o.onPress} key={'menuOption_' + key++} style={this.styles().contextMenuItem}>
|
<MenuOption value={o.onPress} key={`menuOption_${key++}`} style={this.styles().contextMenuItem}>
|
||||||
<Text style={this.styles().contextMenuItemText}>{o.title}</Text>
|
<Text style={this.styles().contextMenuItemText}>{o.title}</Text>
|
||||||
</MenuOption>
|
</MenuOption>
|
||||||
);
|
);
|
||||||
@ -274,7 +274,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (menuOptionComponents.length) {
|
if (menuOptionComponents.length) {
|
||||||
menuOptionComponents.push(<View key={'menuOption_' + key++} style={this.styles().divider} />);
|
menuOptionComponents.push(<View key={`menuOption_${key++}`} style={this.styles().divider} />);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
menuOptionComponents.push(
|
menuOptionComponents.push(
|
||||||
@ -299,7 +299,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
|||||||
|
|
||||||
for (let i = 0; i < folders.length; i++) {
|
for (let i = 0; i < folders.length; i++) {
|
||||||
const f = folders[i];
|
const f = folders[i];
|
||||||
pickerItems.push({ label: ' '.repeat(indent) + ' ' + Folder.displayTitle(f), value: f.id });
|
pickerItems.push({ label: `${' '.repeat(indent)} ${Folder.displayTitle(f)}`, value: f.id });
|
||||||
pickerItems = addFolderChildren(f.children, pickerItems, indent + 1);
|
pickerItems = addFolderChildren(f.children, pickerItems, indent + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,12 +68,12 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
|||||||
const logItemCsv = service.csvCreate(logItemRows);
|
const logItemCsv = service.csvCreate(logItemRows);
|
||||||
|
|
||||||
const itemListCsv = await service.basicItemList({ format: 'csv' });
|
const itemListCsv = await service.basicItemList({ format: 'csv' });
|
||||||
const filePath = RNFS.ExternalDirectoryPath + '/syncReport-' + new Date().getTime() + '.txt';
|
const filePath = `${RNFS.ExternalDirectoryPath}/syncReport-${new Date().getTime()}.txt`;
|
||||||
|
|
||||||
const finalText = [logItemCsv, itemListCsv].join('\n================================================================================\n');
|
const finalText = [logItemCsv, itemListCsv].join('\n================================================================================\n');
|
||||||
|
|
||||||
await RNFS.writeFile(filePath, finalText);
|
await RNFS.writeFile(filePath, finalText);
|
||||||
alert('Debug report exported to ' + filePath);
|
alert(`Debug report exported to ${filePath}`);
|
||||||
this.setState({ creatingReport: false });
|
this.setState({ creatingReport: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -454,7 +454,7 @@ class ConfigScreenComponent extends BaseScreenComponent {
|
|||||||
|
|
||||||
settingComps.push(
|
settingComps.push(
|
||||||
<View key="version_info_app" style={this.styles().settingContainer}>
|
<View key="version_info_app" style={this.styles().settingContainer}>
|
||||||
<Text style={this.styles().settingText}>{'Joplin ' + VersionInfo.appVersion}</Text>
|
<Text style={this.styles().settingText}>{`Joplin ${VersionInfo.appVersion}`}</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ class LogScreenComponent extends BaseScreenComponent {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={this.styles().row}>
|
<View style={this.styles().row}>
|
||||||
<Text style={textStyle}>{time.formatMsToLocal(item.timestamp, 'MM-DDTHH:mm:ss') + ': ' + item.message}</Text>
|
<Text style={textStyle}>{`${time.formatMsToLocal(item.timestamp, 'MM-DDTHH:mm:ss')}: ${item.message}`}</Text>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -409,12 +409,12 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
reg.logger().info('New dimensions ', dimensions);
|
reg.logger().info('New dimensions ', dimensions);
|
||||||
|
|
||||||
const format = mimeType == 'image/png' ? 'PNG' : 'JPEG';
|
const format = mimeType == 'image/png' ? 'PNG' : 'JPEG';
|
||||||
reg.logger().info('Resizing image ' + localFilePath);
|
reg.logger().info(`Resizing image ${localFilePath}`);
|
||||||
const resizedImage = await ImageResizer.createResizedImage(localFilePath, dimensions.width, dimensions.height, format, 85); //, 0, targetPath);
|
const resizedImage = await ImageResizer.createResizedImage(localFilePath, dimensions.width, dimensions.height, format, 85); //, 0, targetPath);
|
||||||
|
|
||||||
const resizedImagePath = resizedImage.uri;
|
const resizedImagePath = resizedImage.uri;
|
||||||
reg.logger().info('Resized image ', resizedImagePath);
|
reg.logger().info('Resized image ', resizedImagePath);
|
||||||
reg.logger().info('Moving ' + resizedImagePath + ' => ' + targetPath);
|
reg.logger().info(`Moving ${resizedImagePath} => ${targetPath}`);
|
||||||
|
|
||||||
await RNFS.copyFile(resizedImagePath, targetPath);
|
await RNFS.copyFile(resizedImagePath, targetPath);
|
||||||
|
|
||||||
@ -462,8 +462,8 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
mimeType = 'image/jpg';
|
mimeType = 'image/jpg';
|
||||||
}
|
}
|
||||||
|
|
||||||
reg.logger().info('Got file: ' + localFilePath);
|
reg.logger().info(`Got file: ${localFilePath}`);
|
||||||
reg.logger().info('Got type: ' + mimeType);
|
reg.logger().info(`Got type: ${mimeType}`);
|
||||||
|
|
||||||
let resource = Resource.new();
|
let resource = Resource.new();
|
||||||
resource.id = uuid.create();
|
resource.id = uuid.create();
|
||||||
@ -499,7 +499,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const itDoes = await shim.fsDriver().waitTillExists(targetPath);
|
const itDoes = await shim.fsDriver().waitTillExists(targetPath);
|
||||||
if (!itDoes) throw new Error('Resource file was not created: ' + targetPath);
|
if (!itDoes) throw new Error(`Resource file was not created: ${targetPath}`);
|
||||||
|
|
||||||
const fileStat = await shim.fsDriver().stat(targetPath);
|
const fileStat = await shim.fsDriver().stat(targetPath);
|
||||||
resource.size = fileStat.size;
|
resource.size = fileStat.size;
|
||||||
@ -509,7 +509,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
const resourceTag = Resource.markdownTag(resource);
|
const resourceTag = Resource.markdownTag(resource);
|
||||||
|
|
||||||
const newNote = Object.assign({}, this.state.note);
|
const newNote = Object.assign({}, this.state.note);
|
||||||
newNote.body += '\n' + resourceTag;
|
newNote.body += `\n${resourceTag}`;
|
||||||
this.setState({ note: newNote });
|
this.setState({ note: newNote });
|
||||||
|
|
||||||
this.refreshResource(resource);
|
this.refreshResource(resource);
|
||||||
@ -563,7 +563,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
|||||||
|
|
||||||
async share_onPress() {
|
async share_onPress() {
|
||||||
await Share.share({
|
await Share.share({
|
||||||
message: this.state.note.title + '\n\n' + this.state.note.body,
|
message: `${this.state.note.title}\n\n${this.state.note.body}`,
|
||||||
title: this.state.note.title,
|
title: this.state.note.title,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ class NotesScreenComponent extends BaseScreenComponent {
|
|||||||
|
|
||||||
const makeCheckboxText = function(selected, sign, label) {
|
const makeCheckboxText = function(selected, sign, label) {
|
||||||
const s = sign === 'tick' ? '✓' : '⬤';
|
const s = sign === 'tick' ? '✓' : '⬤';
|
||||||
return (selected ? s + ' ' : '') + label;
|
return (selected ? `${s} ` : '') + label;
|
||||||
};
|
};
|
||||||
|
|
||||||
for (let field in sortNoteOptions) {
|
for (let field in sortNoteOptions) {
|
||||||
@ -49,17 +49,17 @@ class NotesScreenComponent extends BaseScreenComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buttons.push({
|
buttons.push({
|
||||||
text: makeCheckboxText(Setting.value('notes.sortOrder.reverse'), 'tick', '[ ' + Setting.settingMetadata('notes.sortOrder.reverse').label() + ' ]'),
|
text: makeCheckboxText(Setting.value('notes.sortOrder.reverse'), 'tick', `[ ${Setting.settingMetadata('notes.sortOrder.reverse').label()} ]`),
|
||||||
id: { name: 'notes.sortOrder.reverse', value: !Setting.value('notes.sortOrder.reverse') },
|
id: { name: 'notes.sortOrder.reverse', value: !Setting.value('notes.sortOrder.reverse') },
|
||||||
});
|
});
|
||||||
|
|
||||||
buttons.push({
|
buttons.push({
|
||||||
text: makeCheckboxText(Setting.value('uncompletedTodosOnTop'), 'tick', '[ ' + Setting.settingMetadata('uncompletedTodosOnTop').label() + ' ]'),
|
text: makeCheckboxText(Setting.value('uncompletedTodosOnTop'), 'tick', `[ ${Setting.settingMetadata('uncompletedTodosOnTop').label()} ]`),
|
||||||
id: { name: 'uncompletedTodosOnTop', value: !Setting.value('uncompletedTodosOnTop') },
|
id: { name: 'uncompletedTodosOnTop', value: !Setting.value('uncompletedTodosOnTop') },
|
||||||
});
|
});
|
||||||
|
|
||||||
buttons.push({
|
buttons.push({
|
||||||
text: makeCheckboxText(Setting.value('showCompletedTodos'), 'tick', '[ ' + Setting.settingMetadata('showCompletedTodos').label() + ' ]'),
|
text: makeCheckboxText(Setting.value('showCompletedTodos'), 'tick', `[ ${Setting.settingMetadata('showCompletedTodos').label()} ]`),
|
||||||
id: { name: 'showCompletedTodos', value: !Setting.value('showCompletedTodos') },
|
id: { name: 'showCompletedTodos', value: !Setting.value('showCompletedTodos') },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ class OneDriveLoginScreenComponent extends BaseScreenComponent {
|
|||||||
this.props.dispatch({ type: 'NAV_BACK' });
|
this.props.dispatch({ type: 'NAV_BACK' });
|
||||||
reg.scheduleSync(0);
|
reg.scheduleSync(0);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
alert('Could not login to OneDrive. Please try again\n\n' + error.message + '\n\n' + url);
|
alert(`Could not login to OneDrive. Please try again\n\n${error.message}\n\n${url}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.authCode_ = null;
|
this.authCode_ = null;
|
||||||
|
@ -125,7 +125,7 @@ class SearchScreenComponent extends BaseScreenComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
notes = await Note.previews(null, {
|
notes = await Note.previews(null, {
|
||||||
anywherePattern: '*' + temp.join('*') + '*',
|
anywherePattern: `*${temp.join('*')}*`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ class StatusScreenComponent extends BaseScreenComponent {
|
|||||||
let style = Object.assign({}, baseStyle);
|
let style = Object.assign({}, baseStyle);
|
||||||
style.fontWeight = 'bold';
|
style.fontWeight = 'bold';
|
||||||
if (i > 0) style.paddingTop = 20;
|
if (i > 0) style.paddingTop = 20;
|
||||||
lines.push({ key: 'section_' + i, isSection: true, text: section.title });
|
lines.push({ key: `section_${i}`, isSection: true, text: section.title });
|
||||||
|
|
||||||
for (let n in section.body) {
|
for (let n in section.body) {
|
||||||
if (!section.body.hasOwnProperty(n)) continue;
|
if (!section.body.hasOwnProperty(n)) continue;
|
||||||
@ -82,10 +82,10 @@ class StatusScreenComponent extends BaseScreenComponent {
|
|||||||
text = item;
|
text = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.push({ key: 'item_' + i + '_' + n, text: text, retryHandler: retryHandler });
|
lines.push({ key: `item_${i}_${n}`, text: text, retryHandler: retryHandler });
|
||||||
}
|
}
|
||||||
|
|
||||||
lines.push({ key: 'divider2_' + i, isDivider: true });
|
lines.push({ key: `divider2_${i}`, isDivider: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -16,7 +16,7 @@ shared.init = function(comp) {
|
|||||||
shared.checkSyncConfig = async function(comp, settings) {
|
shared.checkSyncConfig = async function(comp, settings) {
|
||||||
const syncTargetId = settings['sync.target'];
|
const syncTargetId = settings['sync.target'];
|
||||||
const SyncTargetClass = SyncTargetRegistry.classById(syncTargetId);
|
const SyncTargetClass = SyncTargetRegistry.classById(syncTargetId);
|
||||||
const options = Setting.subValues('sync.' + syncTargetId, settings);
|
const options = Setting.subValues(`sync.${syncTargetId}`, settings);
|
||||||
comp.setState({ checkSyncConfigResult: 'checking' });
|
comp.setState({ checkSyncConfigResult: 'checking' });
|
||||||
const result = await SyncTargetClass.checkConfig(ObjectUtils.convertValuesToFunctions(options));
|
const result = await SyncTargetClass.checkConfig(ObjectUtils.convertValuesToFunctions(options));
|
||||||
comp.setState({ checkSyncConfigResult: result });
|
comp.setState({ checkSyncConfigResult: result });
|
||||||
|
@ -34,7 +34,7 @@ class Shared {
|
|||||||
try {
|
try {
|
||||||
const response = await api.execAuthToken(this.comp_.state.authCode);
|
const response = await api.execAuthToken(this.comp_.state.authCode);
|
||||||
|
|
||||||
Setting.setValue('sync.' + this.syncTargetId() + '.auth', response.access_token);
|
Setting.setValue(`sync.${this.syncTargetId()}.auth`, response.access_token);
|
||||||
api.setAuthToken(response.access_token);
|
api.setAuthToken(response.access_token);
|
||||||
await showInfoMessageBox(_('The application has been authorised!'));
|
await showInfoMessageBox(_('The application has been authorised!'));
|
||||||
this.comp_.props.dispatch({ type: 'NAV_BACK' });
|
this.comp_.props.dispatch({ type: 'NAV_BACK' });
|
||||||
|
@ -16,7 +16,7 @@ function folderIsVisible(folders, folderId, collapsedFolderIds) {
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
let folder = BaseModel.byId(folders, folderId);
|
let folder = BaseModel.byId(folders, folderId);
|
||||||
if (!folder) throw new Error('No folder with id ' + folder.id);
|
if (!folder) throw new Error(`No folder with id ${folder.id}`);
|
||||||
if (!folder.parent_id) return true;
|
if (!folder.parent_id) return true;
|
||||||
if (collapsedFolderIds.indexOf(folder.parent_id) >= 0) return false;
|
if (collapsedFolderIds.indexOf(folder.parent_id) >= 0) return false;
|
||||||
folderId = folder.parent_id;
|
folderId = folder.parent_id;
|
||||||
|
@ -76,7 +76,7 @@ class SideMenuContentNoteComponent extends Component {
|
|||||||
|
|
||||||
for (const option of options) {
|
for (const option of options) {
|
||||||
if (option.isDivider) {
|
if (option.isDivider) {
|
||||||
items.push(this.renderDivider('divider_' + dividerIndex++));
|
items.push(this.renderDivider(`divider_${dividerIndex++}`));
|
||||||
} else {
|
} else {
|
||||||
items.push(this.renderSideBarButton(option.title, option.title, null, option.onPress));
|
items.push(this.renderSideBarButton(option.title, option.title, null, option.onPress));
|
||||||
}
|
}
|
||||||
|
@ -42,10 +42,10 @@ class Database {
|
|||||||
escapeField(field) {
|
escapeField(field) {
|
||||||
if (field == '*') return '*';
|
if (field == '*') return '*';
|
||||||
let p = field.split('.');
|
let p = field.split('.');
|
||||||
if (p.length == 1) return '`' + field + '`';
|
if (p.length == 1) return `\`${field}\``;
|
||||||
if (p.length == 2) return p[0] + '.`' + p[1] + '`';
|
if (p.length == 2) return `${p[0]}.\`${p[1]}\``;
|
||||||
|
|
||||||
throw new Error('Invalid field format: ' + field);
|
throw new Error(`Invalid field format: ${field}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
escapeFields(fields) {
|
escapeFields(fields) {
|
||||||
@ -101,7 +101,7 @@ class Database {
|
|||||||
const output = [];
|
const output = [];
|
||||||
for (let i = 0; i < rows.length; i++) {
|
for (let i = 0; i < rows.length; i++) {
|
||||||
const v = rows[i][field];
|
const v = rows[i][field];
|
||||||
if (!v) throw new Error('No such field: ' + field + '. Query was: ' + sql);
|
if (!v) throw new Error(`No such field: ${field}. Query was: ${sql}`);
|
||||||
output.push(rows[i][field]);
|
output.push(rows[i][field]);
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
@ -148,15 +148,15 @@ class Database {
|
|||||||
if (type == 'fieldType') {
|
if (type == 'fieldType') {
|
||||||
if (s) s = s.toUpperCase();
|
if (s) s = s.toUpperCase();
|
||||||
if (s == 'INTEGER') s = 'INT';
|
if (s == 'INTEGER') s = 'INT';
|
||||||
if (!('TYPE_' + s in this)) throw new Error('Unkonwn fieldType: ' + s);
|
if (!(`TYPE_${s}` in this)) throw new Error(`Unkonwn fieldType: ${s}`);
|
||||||
return this['TYPE_' + s];
|
return this[`TYPE_${s}`];
|
||||||
}
|
}
|
||||||
if (type == 'syncTarget') {
|
if (type == 'syncTarget') {
|
||||||
if (s == 'memory') return 1;
|
if (s == 'memory') return 1;
|
||||||
if (s == 'filesystem') return 2;
|
if (s == 'filesystem') return 2;
|
||||||
if (s == 'onedrive') return 3;
|
if (s == 'onedrive') return 3;
|
||||||
}
|
}
|
||||||
throw new Error('Unknown enum type or value: ' + type + ', ' + s);
|
throw new Error(`Unknown enum type or value: ${type}, ${s}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enumName(type, id) {
|
static enumName(type, id) {
|
||||||
@ -165,7 +165,7 @@ class Database {
|
|||||||
if (id === Database.TYPE_INT) return 'int';
|
if (id === Database.TYPE_INT) return 'int';
|
||||||
if (id === Database.TYPE_TEXT) return 'text';
|
if (id === Database.TYPE_TEXT) return 'text';
|
||||||
if (id === Database.TYPE_NUMERIC) return 'numeric';
|
if (id === Database.TYPE_NUMERIC) return 'numeric';
|
||||||
throw new Error('Invalid type id: ' + id);
|
throw new Error(`Invalid type id: ${id}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +174,7 @@ class Database {
|
|||||||
if (type == this.TYPE_INT) return Number(value);
|
if (type == this.TYPE_INT) return Number(value);
|
||||||
if (type == this.TYPE_TEXT) return value;
|
if (type == this.TYPE_TEXT) return value;
|
||||||
if (type == this.TYPE_NUMERIC) return Number(value);
|
if (type == this.TYPE_NUMERIC) return Number(value);
|
||||||
throw new Error('Unknown type: ' + type);
|
throw new Error(`Unknown type: ${type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlStringToLines(sql) {
|
sqlStringToLines(sql) {
|
||||||
@ -218,12 +218,12 @@ class Database {
|
|||||||
if (key[key.length - 1] == '_') continue;
|
if (key[key.length - 1] == '_') continue;
|
||||||
if (keySql != '') keySql += ', ';
|
if (keySql != '') keySql += ', ';
|
||||||
if (valueSql != '') valueSql += ', ';
|
if (valueSql != '') valueSql += ', ';
|
||||||
keySql += '`' + key + '`';
|
keySql += `\`${key}\``;
|
||||||
valueSql += '?';
|
valueSql += '?';
|
||||||
params.push(data[key]);
|
params.push(data[key]);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
sql: 'INSERT INTO `' + tableName + '` (' + keySql + ') VALUES (' + valueSql + ')',
|
sql: `INSERT INTO \`${tableName}\` (${keySql}) VALUES (${valueSql})`,
|
||||||
params: params,
|
params: params,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -237,7 +237,7 @@ class Database {
|
|||||||
if (!data.hasOwnProperty(key)) continue;
|
if (!data.hasOwnProperty(key)) continue;
|
||||||
if (key[key.length - 1] == '_') continue;
|
if (key[key.length - 1] == '_') continue;
|
||||||
if (sql != '') sql += ', ';
|
if (sql != '') sql += ', ';
|
||||||
sql += '`' + key + '`=?';
|
sql += `\`${key}\`=?`;
|
||||||
params.push(data[key]);
|
params.push(data[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,13 +246,13 @@ class Database {
|
|||||||
for (let n in where) {
|
for (let n in where) {
|
||||||
if (!where.hasOwnProperty(n)) continue;
|
if (!where.hasOwnProperty(n)) continue;
|
||||||
params.push(where[n]);
|
params.push(where[n]);
|
||||||
s.push('`' + n + '`=?');
|
s.push(`\`${n}\`=?`);
|
||||||
}
|
}
|
||||||
where = s.join(' AND ');
|
where = s.join(' AND ');
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sql: 'UPDATE `' + tableName + '` SET ' + sql + ' WHERE ' + where,
|
sql: `UPDATE \`${tableName}\` SET ${sql} WHERE ${where}`,
|
||||||
params: params,
|
params: params,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -267,7 +267,7 @@ class Database {
|
|||||||
let fieldsWithType = [];
|
let fieldsWithType = [];
|
||||||
for (let n in fields) {
|
for (let n in fields) {
|
||||||
if (!fields.hasOwnProperty(n)) continue;
|
if (!fields.hasOwnProperty(n)) continue;
|
||||||
fieldsWithType.push(this.escapeField(n) + ' ' + fields[n]);
|
fieldsWithType.push(`${this.escapeField(n)} ${fields[n]}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let sql = `
|
let sql = `
|
||||||
@ -279,7 +279,7 @@ class Database {
|
|||||||
DROP TABLE _BACKUP_TABLE_NAME_;
|
DROP TABLE _BACKUP_TABLE_NAME_;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
sql = sql.replace(/_BACKUP_TABLE_NAME_/g, this.escapeField(tableName + '_backup'));
|
sql = sql.replace(/_BACKUP_TABLE_NAME_/g, this.escapeField(`${tableName}_backup`));
|
||||||
sql = sql.replace(/_TABLE_NAME_/g, this.escapeField(tableName));
|
sql = sql.replace(/_TABLE_NAME_/g, this.escapeField(tableName));
|
||||||
sql = sql.replace(/_FIELDS_NO_TYPE_/g, this.escapeFields(fieldsNoType).join(','));
|
sql = sql.replace(/_FIELDS_NO_TYPE_/g, this.escapeFields(fieldsNoType).join(','));
|
||||||
sql = sql.replace(/_FIELDS_TYPE_/g, fieldsWithType.join(','));
|
sql = sql.replace(/_FIELDS_TYPE_/g, fieldsWithType.join(','));
|
||||||
@ -296,7 +296,7 @@ class Database {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wrapQuery(sql, params = null) {
|
wrapQuery(sql, params = null) {
|
||||||
if (!sql) throw new Error('Cannot wrap empty string: ' + sql);
|
if (!sql) throw new Error(`Cannot wrap empty string: ${sql}`);
|
||||||
|
|
||||||
if (sql.constructor === Array) {
|
if (sql.constructor === Array) {
|
||||||
let output = {};
|
let output = {};
|
||||||
|
@ -17,7 +17,7 @@ class FileApiDriverDropbox {
|
|||||||
|
|
||||||
makePath_(path) {
|
makePath_(path) {
|
||||||
if (!path) return '';
|
if (!path) return '';
|
||||||
return '/' + path;
|
return `/${path}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasErrorCode_(error, errorCode) {
|
hasErrorCode_(error, errorCode) {
|
||||||
@ -224,7 +224,7 @@ class FileApiDriverDropbox {
|
|||||||
|
|
||||||
// It returns "failed" if it didn't work but anyway throw an error if it's anything other than complete or in_progress
|
// It returns "failed" if it didn't work but anyway throw an error if it's anything other than complete or in_progress
|
||||||
if (check['.tag'] !== 'in_progress') {
|
if (check['.tag'] !== 'in_progress') {
|
||||||
throw new Error('Batch delete failed? ' + JSON.stringify(check));
|
throw new Error(`Batch delete failed? ${JSON.stringify(check)}`);
|
||||||
}
|
}
|
||||||
await time.sleep(2);
|
await time.sleep(2);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ const { basicDelta } = require('lib/file-api');
|
|||||||
class FileApiDriverLocal {
|
class FileApiDriverLocal {
|
||||||
fsErrorToJsError_(error, path = null) {
|
fsErrorToJsError_(error, path = null) {
|
||||||
let msg = error.toString();
|
let msg = error.toString();
|
||||||
if (path !== null) msg += '. Path: ' + path;
|
if (path !== null) msg += `. Path: ${path}`;
|
||||||
let output = new Error(msg);
|
let output = new Error(msg);
|
||||||
if (error.code) output.code = error.code;
|
if (error.code) output.code = error.code;
|
||||||
return output;
|
return output;
|
||||||
|
@ -50,7 +50,7 @@ class FileApiDriverMemory {
|
|||||||
|
|
||||||
async setTimestamp(path, timestampMs) {
|
async setTimestamp(path, timestampMs) {
|
||||||
let item = this.itemByPath(path);
|
let item = this.itemByPath(path);
|
||||||
if (!item) return Promise.reject(new Error('File not found: ' + path));
|
if (!item) return Promise.reject(new Error(`File not found: ${path}`));
|
||||||
item.updated_time = timestampMs;
|
item.updated_time = timestampMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ class FileApiDriverMemory {
|
|||||||
for (let i = 0; i < this.items_.length; i++) {
|
for (let i = 0; i < this.items_.length; i++) {
|
||||||
let item = this.items_[i];
|
let item = this.items_[i];
|
||||||
if (item.path == path) continue;
|
if (item.path == path) continue;
|
||||||
if (item.path.indexOf(path + '/') === 0) {
|
if (item.path.indexOf(`${path}/`) === 0) {
|
||||||
let s = item.path.substr(path.length + 1);
|
let s = item.path.substr(path.length + 1);
|
||||||
if (s.split('/').length === 1) {
|
if (s.split('/').length === 1) {
|
||||||
let it = Object.assign({}, item);
|
let it = Object.assign({}, item);
|
||||||
@ -80,7 +80,7 @@ class FileApiDriverMemory {
|
|||||||
async get(path, options) {
|
async get(path, options) {
|
||||||
let item = this.itemByPath(path);
|
let item = this.itemByPath(path);
|
||||||
if (!item) return Promise.resolve(null);
|
if (!item) return Promise.resolve(null);
|
||||||
if (item.isDir) return Promise.reject(new Error(path + ' is a directory, not a file'));
|
if (item.isDir) return Promise.reject(new Error(`${path} is a directory, not a file`));
|
||||||
|
|
||||||
let output = null;
|
let output = null;
|
||||||
if (options.target === 'file') {
|
if (options.target === 'file') {
|
||||||
@ -128,7 +128,7 @@ class FileApiDriverMemory {
|
|||||||
|
|
||||||
async move(oldPath, newPath) {
|
async move(oldPath, newPath) {
|
||||||
let sourceItem = this.itemByPath(oldPath);
|
let sourceItem = this.itemByPath(oldPath);
|
||||||
if (!sourceItem) return Promise.reject(new Error('Path not found: ' + oldPath));
|
if (!sourceItem) return Promise.reject(new Error(`Path not found: ${oldPath}`));
|
||||||
this.delete(newPath); // Overwrite if newPath already exists
|
this.delete(newPath); // Overwrite if newPath already exists
|
||||||
sourceItem.path = newPath;
|
sourceItem.path = newPath;
|
||||||
}
|
}
|
||||||
|
@ -66,10 +66,10 @@ class FileApiDriverOneDrive {
|
|||||||
let body = {
|
let body = {
|
||||||
fileSystemInfo: {
|
fileSystemInfo: {
|
||||||
lastModifiedDateTime:
|
lastModifiedDateTime:
|
||||||
moment
|
`${moment
|
||||||
.unix(timestamp / 1000)
|
.unix(timestamp / 1000)
|
||||||
.utc()
|
.utc()
|
||||||
.format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z',
|
.format('YYYY-MM-DDTHH:mm:ss.SSS')}Z`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let item = await this.api_.execJson('PATCH', this.makePath_(path), null, body);
|
let item = await this.api_.execJson('PATCH', this.makePath_(path), null, body);
|
||||||
@ -78,7 +78,7 @@ class FileApiDriverOneDrive {
|
|||||||
|
|
||||||
async list(path, options = null) {
|
async list(path, options = null) {
|
||||||
let query = this.itemFilter_();
|
let query = this.itemFilter_();
|
||||||
let url = this.makePath_(path) + ':/children';
|
let url = `${this.makePath_(path)}:/children`;
|
||||||
|
|
||||||
if (options.context) {
|
if (options.context) {
|
||||||
query = null;
|
query = null;
|
||||||
@ -99,10 +99,10 @@ class FileApiDriverOneDrive {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (options.target == 'file') {
|
if (options.target == 'file') {
|
||||||
let response = await this.api_.exec('GET', this.makePath_(path) + ':/content', null, null, options);
|
let response = await this.api_.exec('GET', `${this.makePath_(path)}:/content`, null, null, options);
|
||||||
return response;
|
return response;
|
||||||
} else {
|
} else {
|
||||||
let content = await this.api_.execText('GET', this.makePath_(path) + ':/content');
|
let content = await this.api_.execText('GET', `${this.makePath_(path)}:/content`);
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -116,7 +116,7 @@ class FileApiDriverOneDrive {
|
|||||||
if (item) return item;
|
if (item) return item;
|
||||||
|
|
||||||
let parentPath = dirname(path);
|
let parentPath = dirname(path);
|
||||||
item = await this.api_.execJson('POST', this.makePath_(parentPath) + ':/children', this.itemFilter_(), {
|
item = await this.api_.execJson('POST', `${this.makePath_(parentPath)}:/children`, this.itemFilter_(), {
|
||||||
name: basename(path),
|
name: basename(path),
|
||||||
folder: {},
|
folder: {},
|
||||||
});
|
});
|
||||||
@ -131,10 +131,10 @@ class FileApiDriverOneDrive {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (options.source == 'file') {
|
if (options.source == 'file') {
|
||||||
response = await this.api_.exec('PUT', this.makePath_(path) + ':/content', null, null, options);
|
response = await this.api_.exec('PUT', `${this.makePath_(path)}:/content`, null, null, options);
|
||||||
} else {
|
} else {
|
||||||
options.headers = { 'Content-Type': 'text/plain' };
|
options.headers = { 'Content-Type': 'text/plain' };
|
||||||
response = await this.api_.exec('PUT', this.makePath_(path) + ':/content', null, content, options);
|
response = await this.api_.exec('PUT', `${this.makePath_(path)}:/content`, null, content, options);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error && error.code === 'BadRequest' && error.message === 'Maximum request length exceeded.') {
|
if (error && error.code === 'BadRequest' && error.message === 'Maximum request length exceeded.') {
|
||||||
@ -202,7 +202,7 @@ class FileApiDriverOneDrive {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const freshStartDelta = () => {
|
const freshStartDelta = () => {
|
||||||
const url = this.makePath_(path) + ':/delta';
|
const url = `${this.makePath_(path)}:/delta`;
|
||||||
const query = this.itemFilter_();
|
const query = this.itemFilter_();
|
||||||
query.select += ',deleted';
|
query.select += ',deleted';
|
||||||
return { url: url, query: query };
|
return { url: url, query: query };
|
||||||
@ -273,7 +273,7 @@ class FileApiDriverOneDrive {
|
|||||||
nextLink = response['@odata.nextLink'];
|
nextLink = response['@odata.nextLink'];
|
||||||
output.hasMore = true;
|
output.hasMore = true;
|
||||||
} else {
|
} else {
|
||||||
if (!response['@odata.deltaLink']) throw new Error('Delta link missing: ' + JSON.stringify(response));
|
if (!response['@odata.deltaLink']) throw new Error(`Delta link missing: ${JSON.stringify(response)}`);
|
||||||
nextLink = response['@odata.deltaLink'];
|
nextLink = response['@odata.deltaLink'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user