You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-13 22:12:50 +02:00
Merge branch 'master' of github.com:laurent22/joplin
This commit is contained in:
@@ -1,3 +1,40 @@
|
|||||||
*.min.js
|
*.min.js
|
||||||
|
.git/
|
||||||
|
.github/
|
||||||
|
_mydocs/
|
||||||
|
_releases/
|
||||||
|
Assets/
|
||||||
|
CliClient/build
|
||||||
|
CliClient/locales
|
||||||
|
CliClient/node_modules
|
||||||
|
CliClient/tests-build
|
||||||
|
CliClient/tests/enex_to_md
|
||||||
|
CliClient/tests/html_to_md
|
||||||
|
CliClient/tests/logs
|
||||||
|
CliClient/tests/support
|
||||||
|
CliClient/tests/sync
|
||||||
|
CliClient/tests/tmp
|
||||||
|
Clipper/joplin-webclipper/content_scripts/JSDOMParser.js
|
||||||
|
Clipper/joplin-webclipper/content_scripts/Readability-readerable.js
|
||||||
|
Clipper/joplin-webclipper/content_scripts/Readability.js
|
||||||
|
Clipper/joplin-webclipper/dist
|
||||||
|
Clipper/joplin-webclipper/icons
|
||||||
|
Clipper/joplin-webclipper/popup/build
|
||||||
|
Clipper/joplin-webclipper/popup/node_modules
|
||||||
|
docs/
|
||||||
|
ElectronClient/app/dist
|
||||||
|
ElectronClient/app/lib
|
||||||
|
ElectronClient/app/lib/vendor/sjcl-rn.js
|
||||||
|
ElectronClient/app/lib/vendor/sjcl.js
|
||||||
|
ElectronClient/app/locales
|
||||||
|
ElectronClient/app/node_modules
|
||||||
highlight.pack.js
|
highlight.pack.js
|
||||||
|
node_modules/
|
||||||
|
ReactNativeClient/android
|
||||||
|
ReactNativeClient/ios
|
||||||
ReactNativeClient/lib/vendor/
|
ReactNativeClient/lib/vendor/
|
||||||
|
ReactNativeClient/locales
|
||||||
|
ReactNativeClient/node_modules
|
||||||
|
readme/
|
||||||
|
Tools/node_modules
|
||||||
|
Tools/PortableAppsLauncher
|
31
.eslintrc.js
31
.eslintrc.js
@@ -4,10 +4,25 @@ module.exports = {
|
|||||||
'es6': true,
|
'es6': true,
|
||||||
'node': true,
|
'node': true,
|
||||||
},
|
},
|
||||||
'extends': ['eslint:recommended', 'prettier'],
|
'extends': ['eslint:recommended'],
|
||||||
'globals': {
|
'globals': {
|
||||||
'Atomics': 'readonly',
|
'Atomics': 'readonly',
|
||||||
'SharedArrayBuffer': 'readonly'
|
'SharedArrayBuffer': 'readonly',
|
||||||
|
|
||||||
|
// Jasmine variables
|
||||||
|
'expect': 'readonly',
|
||||||
|
'describe': 'readonly',
|
||||||
|
'it': 'readonly',
|
||||||
|
'beforeEach': 'readonly',
|
||||||
|
'jasmine': 'readonly',
|
||||||
|
|
||||||
|
// React Native variables
|
||||||
|
'__DEV__': 'readonly',
|
||||||
|
|
||||||
|
// Clipper variables
|
||||||
|
'browserSupportsPromises_': true,
|
||||||
|
'chrome': 'readonly',
|
||||||
|
'browser': 'readonly',
|
||||||
},
|
},
|
||||||
'parserOptions': {
|
'parserOptions': {
|
||||||
'ecmaVersion': 2018,
|
'ecmaVersion': 2018,
|
||||||
@@ -24,13 +39,15 @@ module.exports = {
|
|||||||
"no-unused-vars": ["error", { "argsIgnorePattern": ".*" }],
|
"no-unused-vars": ["error", { "argsIgnorePattern": ".*" }],
|
||||||
"no-constant-condition": 0,
|
"no-constant-condition": 0,
|
||||||
"no-prototype-builtins": 0,
|
"no-prototype-builtins": 0,
|
||||||
"prettier/prettier": "error",
|
"space-in-parens": ["error", "never"],
|
||||||
// Uncomment this to automatically remove unused requires:
|
"semi": ["error", "always"],
|
||||||
// "autofix/no-unused-vars": "error",
|
"eol-last": ["error", "always"],
|
||||||
|
"quotes": ["error", "single"],
|
||||||
|
"indent": ["error", "tab"],
|
||||||
|
"comma-dangle": ["error", "always-multiline"],
|
||||||
|
"no-trailing-spaces": "error",
|
||||||
},
|
},
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"react",
|
"react",
|
||||||
"prettier",
|
|
||||||
"autofix",
|
|
||||||
],
|
],
|
||||||
};
|
};
|
@@ -1,3 +0,0 @@
|
|||||||
*.min.js
|
|
||||||
highlight.pack.js
|
|
||||||
ReactNativeClient/lib/vendor/
|
|
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"useTabs": true,
|
|
||||||
"singleQuote": true,
|
|
||||||
"printWidth": 1000,
|
|
||||||
"semi": true,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"endOfLine": "auto"
|
|
||||||
}
|
|
@@ -40,10 +40,7 @@ Building the apps is relatively easy - please [see the build instructions](https
|
|||||||
|
|
||||||
## Coding style
|
## Coding style
|
||||||
|
|
||||||
There are only two rules, but not following them means the pull request will not be accepted (it can be accepted once the issues are fixed):
|
Coding style is enforced by a pre-commit hook that runs eslint. This hook is installed whenever running `npm install` on any of the application directory. If for some reason the pre-commit hook didn't get installed, you can manually install it by running `npm install` at the root of the repository.
|
||||||
|
|
||||||
- **Please use tabs, NOT spaces.**
|
|
||||||
- **Please do not add or remove optional characters, such as spaces or colons.** Please setup your editor so that it only changes what you are working on and is not making automated changes elsewhere. The reason for this is that small white space changes make diff hard to read and can cause needless conflicts.
|
|
||||||
|
|
||||||
## Unit tests
|
## Unit tests
|
||||||
|
|
||||||
|
@@ -1,14 +1,11 @@
|
|||||||
const { _ } = require('lib/locale.js');
|
|
||||||
const { Logger } = require('lib/logger.js');
|
const { Logger } = require('lib/logger.js');
|
||||||
const Resource = require('lib/models/Resource.js');
|
|
||||||
const { netUtils } = require('lib/net-utils.js');
|
const { netUtils } = require('lib/net-utils.js');
|
||||||
|
|
||||||
const http = require("http");
|
const http = require('http');
|
||||||
const urlParser = require("url");
|
const urlParser = require('url');
|
||||||
const enableServerDestroy = require('server-destroy');
|
const enableServerDestroy = require('server-destroy');
|
||||||
|
|
||||||
class ResourceServer {
|
class ResourceServer {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.server_ = null;
|
this.server_ = null;
|
||||||
this.logger_ = new Logger();
|
this.logger_ = new Logger();
|
||||||
@@ -48,11 +45,10 @@ class ResourceServer {
|
|||||||
this.server_ = http.createServer();
|
this.server_ = http.createServer();
|
||||||
|
|
||||||
this.server_.on('request', async (request, response) => {
|
this.server_.on('request', async (request, response) => {
|
||||||
|
const writeResponse = message => {
|
||||||
const writeResponse = (message) => {
|
|
||||||
response.write(message);
|
response.write(message);
|
||||||
response.end();
|
response.end();
|
||||||
}
|
};
|
||||||
|
|
||||||
const url = urlParser.parse(request.url, true);
|
const url = urlParser.parse(request.url, true);
|
||||||
let resourceId = url.pathname.split('/');
|
let resourceId = url.pathname.split('/');
|
||||||
@@ -69,6 +65,7 @@ class ResourceServer {
|
|||||||
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
|
||||||
response.statusCode = 400;
|
response.statusCode = 400;
|
||||||
response.write(error.message);
|
response.write(error.message);
|
||||||
}
|
}
|
||||||
@@ -76,7 +73,7 @@ class ResourceServer {
|
|||||||
response.end();
|
response.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.server_.on('error', (error) => {
|
this.server_.on('error', error => {
|
||||||
this.logger().error('Resource server:', error);
|
this.logger().error('Resource server:', error);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -91,7 +88,6 @@ class ResourceServer {
|
|||||||
if (this.server_) this.server_.destroy();
|
if (this.server_) this.server_.destroy();
|
||||||
this.server_ = null;
|
this.server_ = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ResourceServer;
|
module.exports = ResourceServer;
|
@@ -5,13 +5,12 @@ const Tag = require('lib/models/Tag.js');
|
|||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
const Resource = require('lib/models/Resource.js');
|
const Resource = require('lib/models/Resource.js');
|
||||||
const { cliUtils } = require('./cli-utils.js');
|
|
||||||
const { reducer, defaultState } = require('lib/reducer.js');
|
const { reducer, defaultState } = require('lib/reducer.js');
|
||||||
const { splitCommandString } = require('lib/string-utils.js');
|
const { splitCommandString } = require('lib/string-utils.js');
|
||||||
const { reg } = require('lib/registry.js');
|
const { reg } = require('lib/registry.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const Entities = require('html-entities').AllHtmlEntities;
|
const Entities = require('html-entities').AllHtmlEntities;
|
||||||
const htmlentities = (new Entities()).encode;
|
const htmlentities = new Entities().encode;
|
||||||
|
|
||||||
const chalk = require('chalk');
|
const chalk = require('chalk');
|
||||||
const tk = require('terminal-kit');
|
const tk = require('terminal-kit');
|
||||||
@@ -20,12 +19,10 @@ const Renderer = require('tkwidgets/framework/Renderer.js');
|
|||||||
const DecryptionWorker = require('lib/services/DecryptionWorker');
|
const DecryptionWorker = require('lib/services/DecryptionWorker');
|
||||||
|
|
||||||
const BaseWidget = require('tkwidgets/BaseWidget.js');
|
const BaseWidget = require('tkwidgets/BaseWidget.js');
|
||||||
const ListWidget = require('tkwidgets/ListWidget.js');
|
|
||||||
const TextWidget = require('tkwidgets/TextWidget.js');
|
const TextWidget = require('tkwidgets/TextWidget.js');
|
||||||
const HLayoutWidget = require('tkwidgets/HLayoutWidget.js');
|
const HLayoutWidget = require('tkwidgets/HLayoutWidget.js');
|
||||||
const VLayoutWidget = require('tkwidgets/VLayoutWidget.js');
|
const VLayoutWidget = require('tkwidgets/VLayoutWidget.js');
|
||||||
const ReduxRootWidget = require('tkwidgets/ReduxRootWidget.js');
|
const ReduxRootWidget = require('tkwidgets/ReduxRootWidget.js');
|
||||||
const RootWidget = require('tkwidgets/RootWidget.js');
|
|
||||||
const WindowWidget = require('tkwidgets/WindowWidget.js');
|
const WindowWidget = require('tkwidgets/WindowWidget.js');
|
||||||
|
|
||||||
const NoteWidget = require('./gui/NoteWidget.js');
|
const NoteWidget = require('./gui/NoteWidget.js');
|
||||||
@@ -37,7 +34,6 @@ const StatusBarWidget = require('./gui/StatusBarWidget.js');
|
|||||||
const ConsoleWidget = require('./gui/ConsoleWidget.js');
|
const ConsoleWidget = require('./gui/ConsoleWidget.js');
|
||||||
|
|
||||||
class AppGui {
|
class AppGui {
|
||||||
|
|
||||||
constructor(app, store, keymap) {
|
constructor(app, store, keymap) {
|
||||||
try {
|
try {
|
||||||
this.app_ = app;
|
this.app_ = app;
|
||||||
@@ -50,12 +46,12 @@ class AppGui {
|
|||||||
// Some keys are directly handled by the tkwidget framework
|
// Some keys are directly handled by the tkwidget framework
|
||||||
// so they need to be remapped in a different way.
|
// so they need to be remapped in a different way.
|
||||||
this.tkWidgetKeys_ = {
|
this.tkWidgetKeys_ = {
|
||||||
'focus_next': 'TAB',
|
focus_next: 'TAB',
|
||||||
'focus_previous': 'SHIFT_TAB',
|
focus_previous: 'SHIFT_TAB',
|
||||||
'move_up': 'UP',
|
move_up: 'UP',
|
||||||
'move_down': 'DOWN',
|
move_down: 'DOWN',
|
||||||
'page_down': 'PAGE_DOWN',
|
page_down: 'PAGE_DOWN',
|
||||||
'page_up': 'PAGE_UP',
|
page_up: 'PAGE_UP',
|
||||||
};
|
};
|
||||||
|
|
||||||
this.renderer_ = null;
|
this.renderer_ = null;
|
||||||
@@ -64,7 +60,7 @@ class AppGui {
|
|||||||
|
|
||||||
this.renderer_ = new Renderer(this.term(), this.rootWidget_);
|
this.renderer_ = new Renderer(this.term(), this.rootWidget_);
|
||||||
|
|
||||||
this.app_.on('modelAction', async (event) => {
|
this.app_.on('modelAction', async event => {
|
||||||
await this.handleModelAction(event.action);
|
await this.handleModelAction(event.action);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -134,7 +130,7 @@ class AppGui {
|
|||||||
};
|
};
|
||||||
folderList.name = 'folderList';
|
folderList.name = 'folderList';
|
||||||
folderList.vStretch = true;
|
folderList.vStretch = true;
|
||||||
folderList.on('currentItemChange', async (event) => {
|
folderList.on('currentItemChange', async event => {
|
||||||
const item = folderList.currentItem;
|
const item = folderList.currentItem;
|
||||||
|
|
||||||
if (item === '-') {
|
if (item === '-') {
|
||||||
@@ -169,7 +165,7 @@ class AppGui {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.rootWidget_.connect(folderList, (state) => {
|
this.rootWidget_.connect(folderList, state => {
|
||||||
return {
|
return {
|
||||||
selectedFolderId: state.selectedFolderId,
|
selectedFolderId: state.selectedFolderId,
|
||||||
selectedTagId: state.selectedTagId,
|
selectedTagId: state.selectedTagId,
|
||||||
@@ -196,7 +192,7 @@ class AppGui {
|
|||||||
id: note ? note.id : null,
|
id: note ? note.id : null,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this.rootWidget_.connect(noteList, (state) => {
|
this.rootWidget_.connect(noteList, state => {
|
||||||
return {
|
return {
|
||||||
selectedNoteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
|
selectedNoteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
|
||||||
items: state.notes,
|
items: state.notes,
|
||||||
@@ -210,7 +206,7 @@ class AppGui {
|
|||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderLeftWidth: 1,
|
borderLeftWidth: 1,
|
||||||
};
|
};
|
||||||
this.rootWidget_.connect(noteText, (state) => {
|
this.rootWidget_.connect(noteText, state => {
|
||||||
return {
|
return {
|
||||||
noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
|
noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
|
||||||
notes: state.notes,
|
notes: state.notes,
|
||||||
@@ -225,7 +221,7 @@ class AppGui {
|
|||||||
borderLeftWidth: 1,
|
borderLeftWidth: 1,
|
||||||
borderRightWidth: 1,
|
borderRightWidth: 1,
|
||||||
};
|
};
|
||||||
this.rootWidget_.connect(noteMetadata, (state) => {
|
this.rootWidget_.connect(noteMetadata, state => {
|
||||||
return { noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null };
|
return { noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null };
|
||||||
});
|
});
|
||||||
noteMetadata.hide();
|
noteMetadata.hide();
|
||||||
@@ -430,18 +426,14 @@ class AppGui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async processFunctionCommand(cmd) {
|
async processFunctionCommand(cmd) {
|
||||||
|
|
||||||
if (cmd === 'activate') {
|
if (cmd === 'activate') {
|
||||||
|
|
||||||
const w = this.widget('mainWindow').focusedWidget;
|
const w = this.widget('mainWindow').focusedWidget;
|
||||||
if (w.name === 'folderList') {
|
if (w.name === 'folderList') {
|
||||||
this.widget('noteList').focus();
|
this.widget('noteList').focus();
|
||||||
} else if (w.name === 'noteList' || w.name === 'noteText') {
|
} else if (w.name === 'noteList' || w.name === 'noteText') {
|
||||||
this.processPromptCommand('edit $n');
|
this.processPromptCommand('edit $n');
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (cmd === 'delete') {
|
} else if (cmd === 'delete') {
|
||||||
|
|
||||||
if (this.widget('folderList').hasFocus) {
|
if (this.widget('folderList').hasFocus) {
|
||||||
const item = this.widget('folderList').selectedJoplinItem;
|
const item = this.widget('folderList').selectedJoplinItem;
|
||||||
|
|
||||||
@@ -462,9 +454,7 @@ class AppGui {
|
|||||||
} else {
|
} else {
|
||||||
this.stdout(_('Please select the note or notebook to be deleted first.'));
|
this.stdout(_('Please select the note or notebook to be deleted first.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (cmd === 'toggle_console') {
|
} else if (cmd === 'toggle_console') {
|
||||||
|
|
||||||
if (!this.consoleIsShown()) {
|
if (!this.consoleIsShown()) {
|
||||||
this.showConsole();
|
this.showConsole();
|
||||||
this.minimizeConsole();
|
this.minimizeConsole();
|
||||||
@@ -475,22 +465,15 @@ class AppGui {
|
|||||||
this.maximizeConsole();
|
this.maximizeConsole();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (cmd === 'toggle_metadata') {
|
} else if (cmd === 'toggle_metadata') {
|
||||||
|
|
||||||
this.toggleNoteMetadata();
|
this.toggleNoteMetadata();
|
||||||
|
|
||||||
} else if (cmd === 'enter_command_line_mode') {
|
} else if (cmd === 'enter_command_line_mode') {
|
||||||
|
|
||||||
const cmd = await this.widget('statusBar').prompt();
|
const cmd = await this.widget('statusBar').prompt();
|
||||||
if (!cmd) return;
|
if (!cmd) return;
|
||||||
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);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,7 +586,7 @@ class AppGui {
|
|||||||
async setupResourceServer() {
|
async setupResourceServer() {
|
||||||
const linkStyle = chalk.blue.underline;
|
const linkStyle = chalk.blue.underline;
|
||||||
const noteTextWidget = this.widget('noteText');
|
const noteTextWidget = this.widget('noteText');
|
||||||
const resourceIdRegex = /^:\/[a-f0-9]+$/i
|
const resourceIdRegex = /^:\/[a-f0-9]+$/i;
|
||||||
const noteLinks = {};
|
const noteLinks = {};
|
||||||
|
|
||||||
const hasProtocol = function(s, protocols) {
|
const hasProtocol = function(s, protocols) {
|
||||||
@@ -613,7 +596,7 @@ class AppGui {
|
|||||||
if (s.indexOf(protocols[i] + '://') === 0) return true;
|
if (s.indexOf(protocols[i] + '://') === 0) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
};
|
||||||
|
|
||||||
// By default, before the server is started, only the regular
|
// By default, before the server is started, only the regular
|
||||||
// URLs appear in blue.
|
// URLs appear in blue.
|
||||||
@@ -637,7 +620,7 @@ class AppGui {
|
|||||||
const link = noteLinks[path];
|
const link = noteLinks[path];
|
||||||
|
|
||||||
if (link.type === 'url') {
|
if (link.type === 'url') {
|
||||||
response.writeHead(302, { 'Location': link.url });
|
response.writeHead(302, { Location: link.url });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,11 +633,13 @@ class AppGui {
|
|||||||
if (item.mime) response.setHeader('Content-Type', item.mime);
|
if (item.mime) response.setHeader('Content-Type', item.mime);
|
||||||
response.write(await Resource.content(item));
|
response.write(await Resource.content(item));
|
||||||
} else if (item.type_ === BaseModel.TYPE_NOTE) {
|
} else if (item.type_ === BaseModel.TYPE_NOTE) {
|
||||||
const html = [`
|
const html = [
|
||||||
|
`
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html class="client-nojs" lang="en" dir="ltr">
|
<html class="client-nojs" lang="en" dir="ltr">
|
||||||
<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(''));
|
||||||
@@ -711,7 +696,6 @@ class AppGui {
|
|||||||
term.grabInput();
|
term.grabInput();
|
||||||
|
|
||||||
term.on('key', async (name, matches, data) => {
|
term.on('key', async (name, matches, data) => {
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Handle special shortcuts
|
// Handle special shortcuts
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
@@ -729,13 +713,13 @@ class AppGui {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name === 'CTRL_C' ) {
|
if (name === 'CTRL_C') {
|
||||||
const cmd = this.app().currentCommand();
|
const cmd = this.app().currentCommand();
|
||||||
if (!cmd || !cmd.cancellable() || this.commandCancelCalled_) {
|
if (!cmd || !cmd.cancellable() || this.commandCancelCalled_) {
|
||||||
this.stdout(_('Press Ctrl+D or type "exit" to exit the application'));
|
this.stdout(_('Press Ctrl+D or type "exit" to exit the application'));
|
||||||
} else {
|
} else {
|
||||||
this.commandCancelCalled_ = true;
|
this.commandCancelCalled_ = true;
|
||||||
await cmd.cancel()
|
await cmd.cancel();
|
||||||
this.commandCancelCalled_ = false;
|
this.commandCancelCalled_ = false;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -745,7 +729,7 @@ class AppGui {
|
|||||||
// Build up current shortcut
|
// Build up current shortcut
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
const now = (new Date()).getTime();
|
const now = new Date().getTime();
|
||||||
|
|
||||||
if (now - this.lastShortcutKeyTime_ > 800 || this.isSpecialKey(name)) {
|
if (now - this.lastShortcutKeyTime_ > 800 || this.isSpecialKey(name)) {
|
||||||
this.currentShortcutKeys_ = [name];
|
this.currentShortcutKeys_ = [name];
|
||||||
@@ -813,7 +797,6 @@ class AppGui {
|
|||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AppGui.INPUT_MODE_NORMAL = 1;
|
AppGui.INPUT_MODE_NORMAL = 1;
|
||||||
|
@@ -1,10 +1,5 @@
|
|||||||
const { BaseApplication } = require('lib/BaseApplication');
|
const { BaseApplication } = require('lib/BaseApplication');
|
||||||
const { createStore, applyMiddleware } = require('redux');
|
|
||||||
const { reducer, defaultState } = require('lib/reducer.js');
|
|
||||||
const { JoplinDatabase } = require('lib/joplin-database.js');
|
|
||||||
const { Database } = require('lib/database.js');
|
|
||||||
const { FoldersScreenUtils } = require('lib/folders-screen-utils.js');
|
const { FoldersScreenUtils } = require('lib/folders-screen-utils.js');
|
||||||
const { DatabaseDriverNode } = require('lib/database-driver-node.js');
|
|
||||||
const ResourceService = require('lib/services/ResourceService');
|
const ResourceService = require('lib/services/ResourceService');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const Folder = require('lib/models/Folder.js');
|
const Folder = require('lib/models/Folder.js');
|
||||||
@@ -12,21 +7,15 @@ const BaseItem = require('lib/models/BaseItem.js');
|
|||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
const Tag = require('lib/models/Tag.js');
|
const Tag = require('lib/models/Tag.js');
|
||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
const { Logger } = require('lib/logger.js');
|
|
||||||
const { sprintf } = require('sprintf-js');
|
|
||||||
const { reg } = require('lib/registry.js');
|
const { reg } = require('lib/registry.js');
|
||||||
const { fileExtension } = require('lib/path-utils.js');
|
const { fileExtension } = require('lib/path-utils.js');
|
||||||
const { shim } = require('lib/shim.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const { _, setLocale, defaultLocale, closestSupportedLocale } = require('lib/locale.js');
|
|
||||||
const os = require('os');
|
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const { cliUtils } = require('./cli-utils.js');
|
const { cliUtils } = require('./cli-utils.js');
|
||||||
const Cache = require('lib/Cache');
|
const Cache = require('lib/Cache');
|
||||||
const WelcomeUtils = require('lib/WelcomeUtils');
|
|
||||||
const RevisionService = require('lib/services/RevisionService');
|
const RevisionService = require('lib/services/RevisionService');
|
||||||
|
|
||||||
class Application extends BaseApplication {
|
class Application extends BaseApplication {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -75,7 +64,7 @@ class Application extends BaseApplication {
|
|||||||
// const response = await cliUtils.promptMcq(msg, answers);
|
// const response = await cliUtils.promptMcq(msg, answers);
|
||||||
// if (!response) return null;
|
// if (!response) return null;
|
||||||
|
|
||||||
return output[response - 1];
|
// return output[response - 1];
|
||||||
} else {
|
} else {
|
||||||
return output.length ? output[0] : null;
|
return output.length ? output[0] : null;
|
||||||
}
|
}
|
||||||
@@ -97,10 +86,12 @@ class Application extends BaseApplication {
|
|||||||
const parent = options.parent ? options.parent : app().currentFolder();
|
const parent = options.parent ? options.parent : app().currentFolder();
|
||||||
const ItemClass = BaseItem.itemClass(type);
|
const ItemClass = BaseItem.itemClass(type);
|
||||||
|
|
||||||
if (type == BaseModel.TYPE_NOTE && pattern.indexOf('*') >= 0) { // Handle it as pattern
|
if (type == BaseModel.TYPE_NOTE && pattern.indexOf('*') >= 0) {
|
||||||
|
// Handle it as pattern
|
||||||
if (!parent) throw new Error(_('No notebook selected.'));
|
if (!parent) throw new Error(_('No notebook selected.'));
|
||||||
return await Note.previews(parent.id, { titlePattern: pattern });
|
return await Note.previews(parent.id, { titlePattern: pattern });
|
||||||
} else { // Single item
|
} else {
|
||||||
|
// Single item
|
||||||
let item = null;
|
let item = null;
|
||||||
if (type == BaseModel.TYPE_NOTE) {
|
if (type == BaseModel.TYPE_NOTE) {
|
||||||
if (!parent) throw new Error(_('No notebook has been specified.'));
|
if (!parent) throw new Error(_('No notebook has been specified.'));
|
||||||
@@ -126,15 +117,15 @@ class Application extends BaseApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setupCommand(cmd) {
|
setupCommand(cmd) {
|
||||||
cmd.setStdout((text) => {
|
cmd.setStdout(text => {
|
||||||
return this.stdout(text);
|
return this.stdout(text);
|
||||||
});
|
});
|
||||||
|
|
||||||
cmd.setDispatcher((action) => {
|
cmd.setDispatcher(action => {
|
||||||
if (this.store()) {
|
if (this.store()) {
|
||||||
return this.store().dispatch(action);
|
return this.store().dispatch(action);
|
||||||
} else {
|
} else {
|
||||||
return (action) => {};
|
return action => {};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -185,9 +176,9 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
commands(uiType = null) {
|
commands(uiType = null) {
|
||||||
if (!this.allCommandsLoaded_) {
|
if (!this.allCommandsLoaded_) {
|
||||||
fs.readdirSync(__dirname).forEach((path) => {
|
fs.readdirSync(__dirname).forEach(path => {
|
||||||
if (path.indexOf('command-') !== 0) return;
|
if (path.indexOf('command-') !== 0) return;
|
||||||
const ext = fileExtension(path)
|
const ext = fileExtension(path);
|
||||||
if (ext != 'js') return;
|
if (ext != 'js') return;
|
||||||
|
|
||||||
let CommandClass = require('./' + path);
|
let CommandClass = require('./' + path);
|
||||||
@@ -276,19 +267,27 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
dummyGui() {
|
dummyGui() {
|
||||||
return {
|
return {
|
||||||
isDummy: () => { return true; },
|
isDummy: () => {
|
||||||
prompt: (initialText = '', promptString = '', options = null) => { return cliUtils.prompt(initialText, promptString, options); },
|
return true;
|
||||||
|
},
|
||||||
|
prompt: (initialText = '', promptString = '', options = null) => {
|
||||||
|
return cliUtils.prompt(initialText, promptString, options);
|
||||||
|
},
|
||||||
showConsole: () => {},
|
showConsole: () => {},
|
||||||
maximizeConsole: () => {},
|
maximizeConsole: () => {},
|
||||||
stdout: (text) => { console.info(text); },
|
stdout: text => {
|
||||||
fullScreen: (b=true) => {},
|
console.info(text);
|
||||||
|
},
|
||||||
|
fullScreen: (b = true) => {},
|
||||||
exit: () => {},
|
exit: () => {},
|
||||||
showModalOverlay: (text) => {},
|
showModalOverlay: text => {},
|
||||||
hideModalOverlay: () => {},
|
hideModalOverlay: () => {},
|
||||||
stdoutMaxWidth: () => { return 100; },
|
stdoutMaxWidth: () => {
|
||||||
|
return 100;
|
||||||
|
},
|
||||||
forceRender: () => {},
|
forceRender: () => {},
|
||||||
termSaveState: () => {},
|
termSaveState: () => {},
|
||||||
termRestoreState: (state) => {},
|
termRestoreState: state => {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,24 +315,24 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
async loadKeymaps() {
|
async loadKeymaps() {
|
||||||
const defaultKeyMap = [
|
const defaultKeyMap = [
|
||||||
{ "keys": [":"], "type": "function", "command": "enter_command_line_mode" },
|
{ keys: [':'], type: 'function', command: 'enter_command_line_mode' },
|
||||||
{ "keys": ["TAB"], "type": "function", "command": "focus_next" },
|
{ keys: ['TAB'], type: 'function', command: 'focus_next' },
|
||||||
{ "keys": ["SHIFT_TAB"], "type": "function", "command": "focus_previous" },
|
{ keys: ['SHIFT_TAB'], type: 'function', command: 'focus_previous' },
|
||||||
{ "keys": ["UP"], "type": "function", "command": "move_up" },
|
{ keys: ['UP'], type: 'function', command: 'move_up' },
|
||||||
{ "keys": ["DOWN"], "type": "function", "command": "move_down" },
|
{ keys: ['DOWN'], type: 'function', command: 'move_down' },
|
||||||
{ "keys": ["PAGE_UP"], "type": "function", "command": "page_up" },
|
{ keys: ['PAGE_UP'], type: 'function', command: 'page_up' },
|
||||||
{ "keys": ["PAGE_DOWN"], "type": "function", "command": "page_down" },
|
{ keys: ['PAGE_DOWN'], type: 'function', command: 'page_down' },
|
||||||
{ "keys": ["ENTER"], "type": "function", "command": "activate" },
|
{ keys: ['ENTER'], type: 'function', command: 'activate' },
|
||||||
{ "keys": ["DELETE", "BACKSPACE"], "type": "function", "command": "delete" },
|
{ keys: ['DELETE', 'BACKSPACE'], type: 'function', command: 'delete' },
|
||||||
{ "keys": [" "], "command": "todo toggle $n" },
|
{ keys: [' '], command: 'todo toggle $n' },
|
||||||
{ "keys": ["tc"], "type": "function", "command": "toggle_console" },
|
{ keys: ['tc'], type: 'function', command: 'toggle_console' },
|
||||||
{ "keys": ["tm"], "type": "function", "command": "toggle_metadata" },
|
{ keys: ['tm'], type: 'function', command: 'toggle_metadata' },
|
||||||
{ "keys": ["/"], "type": "prompt", "command": "search \"\"", "cursorPosition": -2 },
|
{ keys: ['/'], type: 'prompt', command: 'search ""', cursorPosition: -2 },
|
||||||
{ "keys": ["mn"], "type": "prompt", "command": "mknote \"\"", "cursorPosition": -2 },
|
{ keys: ['mn'], type: 'prompt', command: 'mknote ""', cursorPosition: -2 },
|
||||||
{ "keys": ["mt"], "type": "prompt", "command": "mktodo \"\"", "cursorPosition": -2 },
|
{ keys: ['mt'], type: 'prompt', command: 'mktodo ""', cursorPosition: -2 },
|
||||||
{ "keys": ["mb"], "type": "prompt", "command": "mkbook \"\"", "cursorPosition": -2 },
|
{ keys: ['mb'], type: 'prompt', command: 'mkbook ""', cursorPosition: -2 },
|
||||||
{ "keys": ["yn"], "type": "prompt", "command": "cp $n \"\"", "cursorPosition": -2 },
|
{ keys: ['yn'], type: 'prompt', command: 'cp $n ""', cursorPosition: -2 },
|
||||||
{ "keys": ["dn"], "type": "prompt", "command": "mv $n \"\"", "cursorPosition": -2 }
|
{ keys: ['dn'], type: 'prompt', command: 'mv $n ""', cursorPosition: -2 },
|
||||||
];
|
];
|
||||||
|
|
||||||
// Filter the keymap item by command so that items in keymap.json can override
|
// Filter the keymap item by command so that items in keymap.json can override
|
||||||
@@ -341,7 +340,7 @@ class Application extends BaseApplication {
|
|||||||
const itemsByCommand = {};
|
const itemsByCommand = {};
|
||||||
|
|
||||||
for (let i = 0; i < defaultKeyMap.length; i++) {
|
for (let i = 0; i < defaultKeyMap.length; i++) {
|
||||||
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';
|
||||||
@@ -374,7 +373,7 @@ class Application extends BaseApplication {
|
|||||||
async start(argv) {
|
async start(argv) {
|
||||||
argv = await super.start(argv);
|
argv = await super.start(argv);
|
||||||
|
|
||||||
cliUtils.setStdout((object) => {
|
cliUtils.setStdout(object => {
|
||||||
return this.stdout(object);
|
return this.stdout(object);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -401,7 +400,8 @@ class Application extends BaseApplication {
|
|||||||
// Need to call exit() explicitely, otherwise Node wait for any timeout to complete
|
// Need to call exit() explicitely, otherwise Node wait for any timeout to complete
|
||||||
// https://stackoverflow.com/questions/18050095
|
// https://stackoverflow.com/questions/18050095
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
} else { // Otherwise open the GUI
|
} else {
|
||||||
|
// Otherwise open the GUI
|
||||||
this.initRedux();
|
this.initRedux();
|
||||||
|
|
||||||
const keymap = await this.loadKeymaps();
|
const keymap = await this.loadKeymaps();
|
||||||
@@ -435,7 +435,6 @@ class Application extends BaseApplication {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let application_ = null;
|
let application_ = null;
|
||||||
|
@@ -14,11 +14,11 @@ async function handleAutocompletionPromise(line) {
|
|||||||
//should look for commmands it could be
|
//should look for commmands it could be
|
||||||
if (words.length == 1) {
|
if (words.length == 1) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ async function handleAutocompletionPromise(line) {
|
|||||||
let next = words.length > 1 ? words[words.length - 1] : '';
|
let next = words.length > 1 ? words[words.length - 1] : '';
|
||||||
let l = [];
|
let l = [];
|
||||||
if (next[0] === '-') {
|
if (next[0] === '-') {
|
||||||
for (let i = 0; i<metadata.options.length; i++) {
|
for (let i = 0; i < metadata.options.length; i++) {
|
||||||
const options = metadata.options[i][0].split(' ');
|
const options = metadata.options[i][0].split(' ');
|
||||||
//if there are multiple options then they will be separated by comma and
|
//if there are multiple options then they will be separated by comma and
|
||||||
//space. The comma should be removed
|
//space. The comma should be removed
|
||||||
@@ -55,20 +55,19 @@ async function handleAutocompletionPromise(line) {
|
|||||||
if (l.length === 0) {
|
if (l.length === 0) {
|
||||||
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
|
||||||
//Determine the number of positional arguments by counting the number of
|
//Determine the number of positional arguments by counting the number of
|
||||||
//words that don't start with a - less one for the command name
|
//words that don't start with a - less one for the command name
|
||||||
const positionalArgs = words.filter((a)=>a.indexOf('-') !== 0).length - 1;
|
const positionalArgs = words.filter(a => a.indexOf('-') !== 0).length - 1;
|
||||||
|
|
||||||
let cmdUsage = yargParser(metadata.usage)['_'];
|
let cmdUsage = yargParser(metadata.usage)['_'];
|
||||||
cmdUsage.splice(0, 1);
|
cmdUsage.splice(0, 1);
|
||||||
|
|
||||||
if (cmdUsage.length >= positionalArgs) {
|
if (cmdUsage.length >= positionalArgs) {
|
||||||
|
|
||||||
let argName = cmdUsage[positionalArgs - 1];
|
let argName = cmdUsage[positionalArgs - 1];
|
||||||
argName = cliUtils.parseCommandArg(argName).name;
|
argName = cliUtils.parseCommandArg(argName).name;
|
||||||
|
|
||||||
@@ -76,23 +75,23 @@ async function handleAutocompletionPromise(line) {
|
|||||||
|
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argName == 'file') {
|
if (argName == 'file') {
|
||||||
@@ -113,12 +112,11 @@ async function handleAutocompletionPromise(line) {
|
|||||||
if (l.length === 1) {
|
if (l.length === 1) {
|
||||||
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;
|
||||||
|
|
||||||
}
|
}
|
||||||
function handleAutocompletion(str, callback) {
|
function handleAutocompletion(str, callback) {
|
||||||
handleAutocompletionPromise(str).then(function(res) {
|
handleAutocompletionPromise(str).then(function(res) {
|
||||||
@@ -127,19 +125,21 @@ function handleAutocompletion(str, callback) {
|
|||||||
}
|
}
|
||||||
function toCommandLine(args) {
|
function toCommandLine(args) {
|
||||||
if (Array.isArray(args)) {
|
if (Array.isArray(args)) {
|
||||||
return args.map(function(a) {
|
return args
|
||||||
if(a.indexOf('"') !== -1 || a.indexOf(' ') !== -1) {
|
.map(function(a) {
|
||||||
return "'" + a + "'";
|
if (a.indexOf('"') !== -1 || a.indexOf(' ') !== -1) {
|
||||||
} else if (a.indexOf("'") !== -1) {
|
return '\'' + a + '\'';
|
||||||
|
} else if (a.indexOf('\'') !== -1) {
|
||||||
return '"' + a + '"';
|
return '"' + a + '"';
|
||||||
} else {
|
} else {
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
}).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 + ' ';
|
||||||
@@ -151,9 +151,9 @@ function getArguments(line) {
|
|||||||
let inDoubleQuotes = false;
|
let inDoubleQuotes = false;
|
||||||
let currentWord = '';
|
let currentWord = '';
|
||||||
let parsed = [];
|
let parsed = [];
|
||||||
for(let i = 0; i<line.length; i++) {
|
for (let i = 0; i < line.length; i++) {
|
||||||
if(line[i] === '"') {
|
if (line[i] === '"') {
|
||||||
if(inDoubleQuotes) {
|
if (inDoubleQuotes) {
|
||||||
inDoubleQuotes = false;
|
inDoubleQuotes = false;
|
||||||
//maybe push word to parsed?
|
//maybe push word to parsed?
|
||||||
//currentWord += '"';
|
//currentWord += '"';
|
||||||
@@ -161,8 +161,8 @@ function getArguments(line) {
|
|||||||
inDoubleQuotes = true;
|
inDoubleQuotes = true;
|
||||||
//currentWord += '"';
|
//currentWord += '"';
|
||||||
}
|
}
|
||||||
} else if(line[i] === "'") {
|
} else if (line[i] === '\'') {
|
||||||
if(inSingleQuotes) {
|
if (inSingleQuotes) {
|
||||||
inSingleQuotes = false;
|
inSingleQuotes = false;
|
||||||
//maybe push word to parsed?
|
//maybe push word to parsed?
|
||||||
//currentWord += "'";
|
//currentWord += "'";
|
||||||
@@ -170,8 +170,7 @@ function getArguments(line) {
|
|||||||
inSingleQuotes = true;
|
inSingleQuotes = true;
|
||||||
//currentWord += "'";
|
//currentWord += "'";
|
||||||
}
|
}
|
||||||
} else if (/\s/.test(line[i]) &&
|
} else if (/\s/.test(line[i]) && !(inDoubleQuotes || inSingleQuotes)) {
|
||||||
!(inDoubleQuotes || inSingleQuotes)) {
|
|
||||||
if (currentWord !== '') {
|
if (currentWord !== '') {
|
||||||
parsed.push(currentWord);
|
parsed.push(currentWord);
|
||||||
currentWord = '';
|
currentWord = '';
|
||||||
|
@@ -2,7 +2,6 @@ const { _ } = require('lib/locale.js');
|
|||||||
const { reg } = require('lib/registry.js');
|
const { reg } = require('lib/registry.js');
|
||||||
|
|
||||||
class BaseCommand {
|
class BaseCommand {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.stdout_ = null;
|
this.stdout_ = null;
|
||||||
this.prompt_ = null;
|
this.prompt_ = null;
|
||||||
@@ -93,7 +92,6 @@ class BaseCommand {
|
|||||||
logger() {
|
logger() {
|
||||||
return reg.logger();
|
return reg.logger();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { BaseCommand };
|
module.exports = { BaseCommand };
|
@@ -1,7 +1,7 @@
|
|||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const { fileExtension, basename, dirname } = require('lib/path-utils.js');
|
const { fileExtension, dirname } = require('lib/path-utils.js');
|
||||||
const wrap_ = require('word-wrap');
|
const wrap_ = require('word-wrap');
|
||||||
const { _, setLocale, languageCode } = require('lib/locale.js');
|
const { languageCode } = require('lib/locale.js');
|
||||||
|
|
||||||
const rootDir = dirname(dirname(__dirname));
|
const rootDir = dirname(dirname(__dirname));
|
||||||
const MAX_WIDTH = 78;
|
const MAX_WIDTH = 78;
|
||||||
@@ -29,7 +29,7 @@ function renderOptions(options) {
|
|||||||
output.push(r);
|
output.push(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
return output.join("\n");
|
return output.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderCommand(cmd) {
|
function renderCommand(cmd) {
|
||||||
@@ -44,14 +44,14 @@ function renderCommand(cmd) {
|
|||||||
output.push('');
|
output.push('');
|
||||||
output.push(optionString);
|
output.push(optionString);
|
||||||
}
|
}
|
||||||
return output.join("\n");
|
return output.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCommands() {
|
function getCommands() {
|
||||||
let output = [];
|
let output = [];
|
||||||
fs.readdirSync(__dirname).forEach((path) => {
|
fs.readdirSync(__dirname).forEach(path => {
|
||||||
if (path.indexOf('command-') !== 0) return;
|
if (path.indexOf('command-') !== 0) return;
|
||||||
const ext = fileExtension(path)
|
const ext = fileExtension(path);
|
||||||
if (ext != 'js') return;
|
if (ext != 'js') return;
|
||||||
|
|
||||||
let CommandClass = require('./' + path);
|
let CommandClass = require('./' + path);
|
||||||
@@ -87,14 +87,14 @@ function getHeader() {
|
|||||||
let description = [];
|
let description = [];
|
||||||
description.push('Joplin is a note taking and to-do application, which can handle a large number of notes organised into notebooks.');
|
description.push('Joplin is a note taking and to-do application, which can handle a large number of notes organised into notebooks.');
|
||||||
description.push('The notes are searchable, can be copied, tagged and modified with your own text editor.');
|
description.push('The notes are searchable, can be copied, tagged and modified with your own text editor.');
|
||||||
description.push("\n\n");
|
description.push('\n\n');
|
||||||
description.push('The notes can be synchronised with various target including the file system (for example with a network directory) or with Microsoft OneDrive.');
|
description.push('The notes can be synchronised with various target including the file system (for example with a network directory) or with Microsoft OneDrive.');
|
||||||
description.push("\n\n");
|
description.push('\n\n');
|
||||||
description.push('Notes exported from Evenotes via .enex files can be imported into Joplin, including the formatted content, resources (images, attachments, etc.) and complete metadata (geolocation, updated time, created time, etc.).');
|
description.push('Notes exported from Evenotes via .enex files can be imported into Joplin, including the formatted content, resources (images, attachments, etc.) and complete metadata (geolocation, updated time, created time, etc.).');
|
||||||
|
|
||||||
output.push(wrap(description.join(''), INDENT));
|
output.push(wrap(description.join(''), INDENT));
|
||||||
|
|
||||||
return output.join("\n");
|
return output.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFooter() {
|
function getFooter() {
|
||||||
@@ -113,7 +113,7 @@ function getFooter() {
|
|||||||
const licenseText = fs.readFileSync(filePath, 'utf8');
|
const licenseText = fs.readFileSync(filePath, 'utf8');
|
||||||
output.push(wrap(licenseText, INDENT));
|
output.push(wrap(licenseText, INDENT));
|
||||||
|
|
||||||
return output.join("\n");
|
return output.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
@@ -128,12 +128,12 @@ async function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const headerText = getHeader();
|
const headerText = getHeader();
|
||||||
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 => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
});
|
});
|
@@ -1,4 +1,4 @@
|
|||||||
"use strict"
|
'use strict';
|
||||||
|
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const { Logger } = require('lib/logger.js');
|
const { Logger } = require('lib/logger.js');
|
||||||
@@ -10,7 +10,7 @@ const Folder = require('lib/models/Folder.js');
|
|||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
const { sprintf } = require('sprintf-js');
|
const { sprintf } = require('sprintf-js');
|
||||||
const exec = require('child_process').exec
|
const exec = require('child_process').exec;
|
||||||
|
|
||||||
process.on('unhandledRejection', (reason, p) => {
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
console.error('Unhandled promise rejection', p, 'reason:', reason);
|
console.error('Unhandled promise rejection', p, 'reason:', reason);
|
||||||
@@ -32,8 +32,8 @@ db.setLogger(dbLogger);
|
|||||||
|
|
||||||
function createClient(id) {
|
function createClient(id) {
|
||||||
return {
|
return {
|
||||||
'id': id,
|
id: id,
|
||||||
'profileDir': baseDir + '/client' + id,
|
profileDir: baseDir + '/client' + id,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,14 +72,7 @@ function assertEquals(expected, real) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function clearDatabase() {
|
async function clearDatabase() {
|
||||||
await db.transactionExecBatch([
|
await db.transactionExecBatch(['DELETE FROM folders', 'DELETE FROM notes', 'DELETE FROM tags', 'DELETE FROM note_tags', 'DELETE FROM resources', 'DELETE FROM deleted_items']);
|
||||||
'DELETE FROM folders',
|
|
||||||
'DELETE FROM notes',
|
|
||||||
'DELETE FROM tags',
|
|
||||||
'DELETE FROM note_tags',
|
|
||||||
'DELETE FROM resources',
|
|
||||||
'DELETE FROM deleted_items',
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const testUnits = {};
|
const testUnits = {};
|
||||||
@@ -101,7 +94,7 @@ testUnits.testFolders = async () => {
|
|||||||
|
|
||||||
folders = await Folder.all();
|
folders = await Folder.all();
|
||||||
assertEquals(0, folders.length);
|
assertEquals(0, folders.length);
|
||||||
}
|
};
|
||||||
|
|
||||||
testUnits.testNotes = async () => {
|
testUnits.testNotes = async () => {
|
||||||
await execCommand(client, 'mkbook nb1');
|
await execCommand(client, 'mkbook nb1');
|
||||||
@@ -121,16 +114,16 @@ testUnits.testNotes = async () => {
|
|||||||
notes = await Note.all();
|
notes = await Note.all();
|
||||||
assertEquals(2, notes.length);
|
assertEquals(2, notes.length);
|
||||||
|
|
||||||
await execCommand(client, "rm -f 'blabla*'");
|
await execCommand(client, 'rm -f \'blabla*\'');
|
||||||
|
|
||||||
notes = await Note.all();
|
notes = await Note.all();
|
||||||
assertEquals(2, notes.length);
|
assertEquals(2, notes.length);
|
||||||
|
|
||||||
await execCommand(client, "rm -f 'n*'");
|
await execCommand(client, 'rm -f \'n*\'');
|
||||||
|
|
||||||
notes = await Note.all();
|
notes = await Note.all();
|
||||||
assertEquals(0, notes.length);
|
assertEquals(0, notes.length);
|
||||||
}
|
};
|
||||||
|
|
||||||
testUnits.testCat = async () => {
|
testUnits.testCat = async () => {
|
||||||
await execCommand(client, 'mkbook nb1');
|
await execCommand(client, 'mkbook nb1');
|
||||||
@@ -145,7 +138,7 @@ testUnits.testCat = async () => {
|
|||||||
|
|
||||||
r = await execCommand(client, 'cat -v mynote');
|
r = await execCommand(client, 'cat -v mynote');
|
||||||
assertTrue(r.indexOf(note.id) >= 0);
|
assertTrue(r.indexOf(note.id) >= 0);
|
||||||
}
|
};
|
||||||
|
|
||||||
testUnits.testConfig = async () => {
|
testUnits.testConfig = async () => {
|
||||||
await execCommand(client, 'config editor vim');
|
await execCommand(client, 'config editor vim');
|
||||||
@@ -159,7 +152,7 @@ testUnits.testConfig = async () => {
|
|||||||
let r = await execCommand(client, 'config');
|
let r = await execCommand(client, 'config');
|
||||||
assertTrue(r.indexOf('editor') >= 0);
|
assertTrue(r.indexOf('editor') >= 0);
|
||||||
assertTrue(r.indexOf('subl') >= 0);
|
assertTrue(r.indexOf('subl') >= 0);
|
||||||
}
|
};
|
||||||
|
|
||||||
testUnits.testCp = async () => {
|
testUnits.testCp = async () => {
|
||||||
await execCommand(client, 'mkbook nb2');
|
await execCommand(client, 'mkbook nb2');
|
||||||
@@ -180,7 +173,7 @@ testUnits.testCp = async () => {
|
|||||||
notes = await Note.previews(f2.id);
|
notes = await Note.previews(f2.id);
|
||||||
assertEquals(1, notes.length);
|
assertEquals(1, notes.length);
|
||||||
assertEquals(notesF1[0].title, notes[0].title);
|
assertEquals(notesF1[0].title, notes[0].title);
|
||||||
}
|
};
|
||||||
|
|
||||||
testUnits.testLs = async () => {
|
testUnits.testLs = async () => {
|
||||||
await execCommand(client, 'mkbook nb1');
|
await execCommand(client, 'mkbook nb1');
|
||||||
@@ -190,7 +183,7 @@ testUnits.testLs = async () => {
|
|||||||
|
|
||||||
assertTrue(r.indexOf('note1') >= 0);
|
assertTrue(r.indexOf('note1') >= 0);
|
||||||
assertTrue(r.indexOf('note2') >= 0);
|
assertTrue(r.indexOf('note2') >= 0);
|
||||||
}
|
};
|
||||||
|
|
||||||
testUnits.testMv = async () => {
|
testUnits.testMv = async () => {
|
||||||
await execCommand(client, 'mkbook nb2');
|
await execCommand(client, 'mkbook nb2');
|
||||||
@@ -210,14 +203,14 @@ testUnits.testMv = async () => {
|
|||||||
await execCommand(client, 'mknote note2');
|
await execCommand(client, 'mknote note2');
|
||||||
await execCommand(client, 'mknote note3');
|
await execCommand(client, 'mknote note3');
|
||||||
await execCommand(client, 'mknote blabla');
|
await execCommand(client, 'mknote blabla');
|
||||||
await execCommand(client, "mv 'note*' nb2");
|
await execCommand(client, 'mv \'note*\' nb2');
|
||||||
|
|
||||||
notes1 = await Note.previews(f1.id);
|
notes1 = await Note.previews(f1.id);
|
||||||
notes2 = await Note.previews(f2.id);
|
notes2 = await Note.previews(f2.id);
|
||||||
|
|
||||||
assertEquals(1, notes1.length);
|
assertEquals(1, notes1.length);
|
||||||
assertEquals(4, notes2.length);
|
assertEquals(4, notes2.length);
|
||||||
}
|
};
|
||||||
|
|
||||||
async function main(argv) {
|
async function main(argv) {
|
||||||
await fs.remove(baseDir);
|
await fs.remove(baseDir);
|
||||||
@@ -243,7 +236,7 @@ async function main(argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main(process.argv).catch((error) => {
|
main(process.argv).catch(error => {
|
||||||
console.info('');
|
console.info('');
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
});
|
});
|
@@ -26,7 +26,6 @@ cliUtils.printArray = function(logFunction, rows, headers = null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let lines = [];
|
|
||||||
for (let row = 0; row < rows.length; row++) {
|
for (let row = 0; row < rows.length; row++) {
|
||||||
let line = [];
|
let line = [];
|
||||||
for (let col = 0; col < colWidths.length; col++) {
|
for (let col = 0; col < colWidths.length; col++) {
|
||||||
@@ -37,7 +36,7 @@ cliUtils.printArray = function(logFunction, rows, headers = null) {
|
|||||||
}
|
}
|
||||||
logFunction(line.join(' '));
|
logFunction(line.join(' '));
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
cliUtils.parseFlags = function(flags) {
|
cliUtils.parseFlags = function(flags) {
|
||||||
let output = {};
|
let output = {};
|
||||||
@@ -56,7 +55,7 @@ cliUtils.parseFlags = function(flags) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
};
|
||||||
|
|
||||||
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);
|
||||||
@@ -72,7 +71,7 @@ cliUtils.parseCommandArg = function(arg) {
|
|||||||
} else {
|
} else {
|
||||||
throw new Error('Invalid command arg: ' + arg);
|
throw new Error('Invalid command arg: ' + arg);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
cliUtils.makeCommandArgs = function(cmd, argv) {
|
cliUtils.makeCommandArgs = function(cmd, argv) {
|
||||||
let cmdUsage = cmd.usage();
|
let cmdUsage = cmd.usage();
|
||||||
@@ -85,7 +84,6 @@ cliUtils.makeCommandArgs = function(cmd, argv) {
|
|||||||
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];
|
||||||
let text = options[i][1];
|
|
||||||
|
|
||||||
flags = cliUtils.parseFlags(flags);
|
flags = cliUtils.parseFlags(flags);
|
||||||
|
|
||||||
@@ -125,27 +123,27 @@ cliUtils.makeCommandArgs = function(cmd, argv) {
|
|||||||
output.options = argOptions;
|
output.options = argOptions;
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
};
|
||||||
|
|
||||||
cliUtils.promptMcq = function(message, answers) {
|
cliUtils.promptMcq = function(message, answers) {
|
||||||
const readline = require('readline');
|
const readline = require('readline');
|
||||||
|
|
||||||
const rl = readline.createInterface({
|
const rl = readline.createInterface({
|
||||||
input: process.stdin,
|
input: process.stdin,
|
||||||
output: process.stdout
|
output: process.stdout,
|
||||||
});
|
});
|
||||||
|
|
||||||
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';
|
||||||
message += _('Your choice: ');
|
message += _('Your choice: ');
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
rl.question(message, (answer) => {
|
rl.question(message, answer => {
|
||||||
rl.close();
|
rl.close();
|
||||||
|
|
||||||
if (!(answer in answers)) {
|
if (!(answer in answers)) {
|
||||||
@@ -156,7 +154,7 @@ cliUtils.promptMcq = function(message, answers) {
|
|||||||
resolve(answer);
|
resolve(answer);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
cliUtils.promptConfirm = function(message, answers = null) {
|
cliUtils.promptConfirm = function(message, answers = null) {
|
||||||
if (!answers) answers = [_('Y'), _('n')];
|
if (!answers) answers = [_('Y'), _('n')];
|
||||||
@@ -164,19 +162,19 @@ cliUtils.promptConfirm = function(message, answers = null) {
|
|||||||
|
|
||||||
const rl = readline.createInterface({
|
const rl = readline.createInterface({
|
||||||
input: process.stdin,
|
input: process.stdin,
|
||||||
output: process.stdout
|
output: process.stdout,
|
||||||
});
|
});
|
||||||
|
|
||||||
message += ' (' + answers.join('/') + ')';
|
message += ' (' + answers.join('/') + ')';
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// Note: initialText is there to have the same signature as statusBar.prompt() so that
|
// Note: initialText is there to have the same signature as statusBar.prompt() so that
|
||||||
// it can be a drop-in replacement, however initialText is not used (and cannot be
|
// it can be a drop-in replacement, however initialText is not used (and cannot be
|
||||||
@@ -189,10 +187,9 @@ cliUtils.prompt = function(initialText = '', promptString = ':', options = null)
|
|||||||
|
|
||||||
const mutableStdout = new Writable({
|
const mutableStdout = new Writable({
|
||||||
write: function(chunk, encoding, callback) {
|
write: function(chunk, encoding, callback) {
|
||||||
if (!this.muted)
|
if (!this.muted) process.stdout.write(chunk, encoding);
|
||||||
process.stdout.write(chunk, encoding);
|
|
||||||
callback();
|
callback();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const rl = readline.createInterface({
|
const rl = readline.createInterface({
|
||||||
@@ -204,15 +201,15 @@ cliUtils.prompt = function(initialText = '', promptString = ':', options = null)
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
mutableStdout.muted = false;
|
mutableStdout.muted = false;
|
||||||
|
|
||||||
rl.question(promptString, (answer) => {
|
rl.question(promptString, answer => {
|
||||||
rl.close();
|
rl.close();
|
||||||
if (!!options.secure) this.stdout_('');
|
if (options.secure) this.stdout_('');
|
||||||
resolve(answer);
|
resolve(answer);
|
||||||
});
|
});
|
||||||
|
|
||||||
mutableStdout.muted = !!options.secure;
|
mutableStdout.muted = !!options.secure;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
let redrawStarted_ = false;
|
let redrawStarted_ = false;
|
||||||
let redrawLastLog_ = null;
|
let redrawLastLog_ = null;
|
||||||
@@ -220,7 +217,7 @@ let redrawLastUpdateTime_ = 0;
|
|||||||
|
|
||||||
cliUtils.setStdout = function(v) {
|
cliUtils.setStdout = function(v) {
|
||||||
this.stdout_ = v;
|
this.stdout_ = v;
|
||||||
}
|
};
|
||||||
|
|
||||||
cliUtils.redraw = function(s) {
|
cliUtils.redraw = function(s) {
|
||||||
const now = time.unixMs();
|
const now = time.unixMs();
|
||||||
@@ -234,7 +231,7 @@ cliUtils.redraw = function(s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
redrawStarted_ = true;
|
redrawStarted_ = true;
|
||||||
}
|
};
|
||||||
|
|
||||||
cliUtils.redrawDone = function() {
|
cliUtils.redrawDone = function() {
|
||||||
if (!redrawStarted_) return;
|
if (!redrawStarted_) return;
|
||||||
@@ -245,6 +242,6 @@ cliUtils.redrawDone = function() {
|
|||||||
|
|
||||||
redrawLastLog_ = null;
|
redrawLastLog_ = null;
|
||||||
redrawStarted_ = false;
|
redrawStarted_ = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = { cliUtils };
|
module.exports = { cliUtils };
|
@@ -1,19 +1,12 @@
|
|||||||
const { BaseCommand } = require('./base-command.js');
|
const { BaseCommand } = require('./base-command.js');
|
||||||
const { _ } = require('lib/locale.js');
|
|
||||||
const { cliUtils } = require('./cli-utils.js');
|
|
||||||
const EncryptionService = require('lib/services/EncryptionService');
|
|
||||||
const DecryptionWorker = require('lib/services/DecryptionWorker');
|
|
||||||
const MasterKey = require('lib/models/MasterKey');
|
|
||||||
const BaseItem = require('lib/models/BaseItem');
|
const BaseItem = require('lib/models/BaseItem');
|
||||||
const BaseModel = require('lib/BaseModel');
|
const BaseModel = require('lib/BaseModel');
|
||||||
const Setting = require('lib/models/Setting.js');
|
|
||||||
const { toTitleCase } = require('lib/string-utils.js');
|
const { toTitleCase } = require('lib/string-utils.js');
|
||||||
const { reg } = require('lib/registry.js');
|
const { reg } = require('lib/registry.js');
|
||||||
const markdownUtils = require('lib/markdownUtils');
|
const markdownUtils = require('lib/markdownUtils');
|
||||||
const { Database } = require('lib/database.js');
|
const { Database } = require('lib/database.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'apidoc';
|
return 'apidoc';
|
||||||
}
|
}
|
||||||
@@ -25,9 +18,13 @@ class Command extends BaseCommand {
|
|||||||
createPropertiesTable(tableFields) {
|
createPropertiesTable(tableFields) {
|
||||||
const headers = [
|
const headers = [
|
||||||
{ name: 'name', label: 'Name' },
|
{ name: 'name', label: 'Name' },
|
||||||
{ name: 'type', label: 'Type', filter: (value) => {
|
{
|
||||||
|
name: 'type',
|
||||||
|
label: 'Type',
|
||||||
|
filter: value => {
|
||||||
return Database.enumName('fieldType', value);
|
return Database.enumName('fieldType', value);
|
||||||
}},
|
},
|
||||||
|
},
|
||||||
{ name: 'description', label: 'Description' },
|
{ name: 'description', label: 'Description' },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -71,7 +68,7 @@ class Command extends BaseCommand {
|
|||||||
lines.push('```');
|
lines.push('```');
|
||||||
lines.push('');
|
lines.push('');
|
||||||
|
|
||||||
lines.push('# Authorisation')
|
lines.push('# Authorisation');
|
||||||
lines.push('');
|
lines.push('');
|
||||||
lines.push('To prevent unauthorised applications from accessing the API, the calls must be authentified. To do so, you must provide a token as a query parameter for each API call. You can get this token from the Joplin desktop application, on the Web Clipper Options screen.');
|
lines.push('To prevent unauthorised applications from accessing the API, the calls must be authentified. To do so, you must provide a token as a query parameter for each API call. You can get this token from the Joplin desktop application, on the Web Clipper Options screen.');
|
||||||
lines.push('');
|
lines.push('');
|
||||||
@@ -293,7 +290,6 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
this.stdout(lines.join('\n'));
|
this.stdout(lines.join('\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
||||||
|
@@ -3,10 +3,8 @@ const { app } = require('./app.js');
|
|||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const { shim } = require('lib/shim.js');
|
const { shim } = require('lib/shim.js');
|
||||||
const fs = require('fs-extra');
|
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'attach <note> <file>';
|
return 'attach <note> <file>';
|
||||||
}
|
}
|
||||||
@@ -26,7 +24,6 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
await shim.attachFileToNote(note, localFilePath);
|
await shim.attachFileToNote(note, localFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -2,11 +2,9 @@ const { BaseCommand } = require('./base-command.js');
|
|||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const Folder = require('lib/models/Folder.js');
|
|
||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'cat <note>';
|
return 'cat <note>';
|
||||||
}
|
}
|
||||||
@@ -16,9 +14,7 @@ class Command extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
options() {
|
options() {
|
||||||
return [
|
return [['-v, --verbose', _('Displays the complete information about note.')]];
|
||||||
['-v, --verbose', _('Displays the complete information about note.')],
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async action(args) {
|
async action(args) {
|
||||||
@@ -30,10 +26,13 @@ class Command extends BaseCommand {
|
|||||||
const content = args.options.verbose ? await Note.serialize(item) : await Note.serializeForEdit(item);
|
const content = args.options.verbose ? await Note.serialize(item) : await Note.serializeForEdit(item);
|
||||||
this.stdout(content);
|
this.stdout(content);
|
||||||
|
|
||||||
app().gui().showConsole();
|
app()
|
||||||
app().gui().maximizeConsole();
|
.gui()
|
||||||
|
.showConsole();
|
||||||
|
app()
|
||||||
|
.gui()
|
||||||
|
.maximizeConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -4,25 +4,22 @@ const { app } = require('./app.js');
|
|||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'config [name] [value]';
|
return 'config [name] [value]';
|
||||||
}
|
}
|
||||||
|
|
||||||
description() {
|
description() {
|
||||||
return _("Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.");
|
return _('Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.');
|
||||||
}
|
}
|
||||||
|
|
||||||
options() {
|
options() {
|
||||||
return [
|
return [['-v, --verbose', _('Also displays unset and hidden config variables.')]];
|
||||||
['-v, --verbose', _('Also displays unset and hidden config variables.')],
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async action(args) {
|
async action(args) {
|
||||||
const verbose = args.options.verbose;
|
const verbose = args.options.verbose;
|
||||||
|
|
||||||
const renderKeyValue = (name) => {
|
const renderKeyValue = name => {
|
||||||
const md = Setting.settingMetadata(name);
|
const md = Setting.settingMetadata(name);
|
||||||
let value = Setting.value(name);
|
let value = Setting.value(name);
|
||||||
if (typeof value === 'object' || Array.isArray(value)) value = JSON.stringify(value);
|
if (typeof value === 'object' || Array.isArray(value)) value = JSON.stringify(value);
|
||||||
@@ -33,7 +30,7 @@ class Command extends BaseCommand {
|
|||||||
} else {
|
} else {
|
||||||
return _('%s = %s', name, value);
|
return _('%s = %s', name, value);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
if (!args.name && !args.value) {
|
if (!args.name && !args.value) {
|
||||||
let keys = Setting.keys(!verbose, 'cli');
|
let keys = Setting.keys(!verbose, 'cli');
|
||||||
@@ -43,15 +40,23 @@ class Command extends BaseCommand {
|
|||||||
if (!verbose && !value) continue;
|
if (!verbose && !value) continue;
|
||||||
this.stdout(renderKeyValue(keys[i]));
|
this.stdout(renderKeyValue(keys[i]));
|
||||||
}
|
}
|
||||||
app().gui().showConsole();
|
app()
|
||||||
app().gui().maximizeConsole();
|
.gui()
|
||||||
|
.showConsole();
|
||||||
|
app()
|
||||||
|
.gui()
|
||||||
|
.maximizeConsole();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.name && !args.value) {
|
if (args.name && !args.value) {
|
||||||
this.stdout(renderKeyValue(args.name));
|
this.stdout(renderKeyValue(args.name));
|
||||||
app().gui().showConsole();
|
app()
|
||||||
app().gui().maximizeConsole();
|
.gui()
|
||||||
|
.showConsole();
|
||||||
|
app()
|
||||||
|
.gui()
|
||||||
|
.maximizeConsole();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +69,6 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
await Setting.saveAll();
|
await Setting.saveAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -2,11 +2,9 @@ const { BaseCommand } = require('./base-command.js');
|
|||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const Folder = require('lib/models/Folder.js');
|
|
||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'cp <note> [notebook]';
|
return 'cp <note> [notebook]';
|
||||||
}
|
}
|
||||||
@@ -33,7 +31,6 @@ class Command extends BaseCommand {
|
|||||||
Note.updateGeolocation(newNote.id);
|
Note.updateGeolocation(newNote.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -2,12 +2,10 @@ const { BaseCommand } = require('./base-command.js');
|
|||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const Folder = require('lib/models/Folder.js');
|
|
||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'done <note>';
|
return 'done <note>';
|
||||||
}
|
}
|
||||||
@@ -35,7 +33,6 @@ class Command extends BaseCommand {
|
|||||||
async action(args) {
|
async action(args) {
|
||||||
await Command.handleAction(this, args, true);
|
await Command.handleAction(this, args, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -1,12 +1,9 @@
|
|||||||
const { BaseCommand } = require('./base-command.js');
|
const { BaseCommand } = require('./base-command.js');
|
||||||
const { app } = require('./app.js');
|
|
||||||
const { _ } = require('lib/locale.js');
|
|
||||||
const Folder = require('lib/models/Folder.js');
|
const Folder = require('lib/models/Folder.js');
|
||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
const Tag = require('lib/models/Tag.js');
|
const Tag = require('lib/models/Tag.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'dump';
|
return 'dump';
|
||||||
}
|
}
|
||||||
@@ -38,7 +35,6 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
this.stdout(JSON.stringify(items));
|
this.stdout(JSON.stringify(items));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -1,9 +1,7 @@
|
|||||||
const { BaseCommand } = require('./base-command.js');
|
const { BaseCommand } = require('./base-command.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const { cliUtils } = require('./cli-utils.js');
|
|
||||||
const EncryptionService = require('lib/services/EncryptionService');
|
const EncryptionService = require('lib/services/EncryptionService');
|
||||||
const DecryptionWorker = require('lib/services/DecryptionWorker');
|
const DecryptionWorker = require('lib/services/DecryptionWorker');
|
||||||
const MasterKey = require('lib/models/MasterKey');
|
|
||||||
const BaseItem = require('lib/models/BaseItem');
|
const BaseItem = require('lib/models/BaseItem');
|
||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
const { shim } = require('lib/shim');
|
const { shim } = require('lib/shim');
|
||||||
@@ -12,7 +10,6 @@ const imageType = require('image-type');
|
|||||||
const readChunk = require('read-chunk');
|
const readChunk = require('read-chunk');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'e2ee <command> [path]';
|
return 'e2ee <command> [path]';
|
||||||
}
|
}
|
||||||
@@ -35,7 +32,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
const options = args.options;
|
const options = args.options;
|
||||||
|
|
||||||
const askForMasterKey = async (error) => {
|
const askForMasterKey = async error => {
|
||||||
const masterKeyId = error.masterKeyId;
|
const masterKeyId = error.masterKeyId;
|
||||||
const password = await this.prompt(_('Enter master password:'), { type: 'string', secure: true });
|
const password = await this.prompt(_('Enter master password:'), { type: 'string', secure: true });
|
||||||
if (!password) {
|
if (!password) {
|
||||||
@@ -45,7 +42,7 @@ class Command extends BaseCommand {
|
|||||||
Setting.setObjectKey('encryption.passwordCache', masterKeyId, password);
|
Setting.setObjectKey('encryption.passwordCache', masterKeyId, password);
|
||||||
await EncryptionService.instance().loadMasterKeysFromSettings();
|
await EncryptionService.instance().loadMasterKeysFromSettings();
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
|
|
||||||
if (args.command === 'enable') {
|
if (args.command === 'enable') {
|
||||||
const password = options.password ? options.password.toString() : await this.prompt(_('Enter master password:'), { type: 'string', secure: true });
|
const password = options.password ? options.password.toString() : await this.prompt(_('Enter master password:'), { type: 'string', secure: true });
|
||||||
@@ -128,19 +125,17 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
if (args.command === 'target-status') {
|
if (args.command === 'target-status') {
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const pathUtils = require('lib/path-utils.js');
|
|
||||||
const fsDriver = new (require('lib/fs-driver-node.js').FsDriverNode)();
|
|
||||||
|
|
||||||
const targetPath = args.path;
|
const targetPath = args.path;
|
||||||
if (!targetPath) throw new Error('Please specify the sync target path.');
|
if (!targetPath) throw new Error('Please specify the sync target path.');
|
||||||
|
|
||||||
const dirPaths = function(targetPath) {
|
const dirPaths = function(targetPath) {
|
||||||
let paths = [];
|
let paths = [];
|
||||||
fs.readdirSync(targetPath).forEach((path) => {
|
fs.readdirSync(targetPath).forEach(path => {
|
||||||
paths.push(path);
|
paths.push(path);
|
||||||
});
|
});
|
||||||
return paths;
|
return paths;
|
||||||
}
|
};
|
||||||
|
|
||||||
let itemCount = 0;
|
let itemCount = 0;
|
||||||
let resourceCount = 0;
|
let resourceCount = 0;
|
||||||
@@ -224,7 +219,6 @@ class Command extends BaseCommand {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -3,15 +3,11 @@ const { BaseCommand } = require('./base-command.js');
|
|||||||
const { uuid } = require('lib/uuid.js');
|
const { uuid } = require('lib/uuid.js');
|
||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const Folder = require('lib/models/Folder.js');
|
|
||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const { cliUtils } = require('./cli-utils.js');
|
|
||||||
const { time } = require('lib/time-utils.js');
|
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'edit <note>';
|
return 'edit <note>';
|
||||||
}
|
}
|
||||||
@@ -21,18 +17,17 @@ class Command extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async action(args) {
|
async action(args) {
|
||||||
let watcher = null;
|
|
||||||
let tempFilePath = null;
|
let tempFilePath = null;
|
||||||
|
|
||||||
const onFinishedEditing = async () => {
|
const onFinishedEditing = async () => {
|
||||||
if (tempFilePath) fs.removeSync(tempFilePath);
|
if (tempFilePath) fs.removeSync(tempFilePath);
|
||||||
}
|
};
|
||||||
|
|
||||||
const textEditorPath = () => {
|
const textEditorPath = () => {
|
||||||
if (Setting.value('editor')) return Setting.value('editor');
|
if (Setting.value('editor')) return Setting.value('editor');
|
||||||
if (process.env.EDITOR) return process.env.EDITOR;
|
if (process.env.EDITOR) return process.env.EDITOR;
|
||||||
throw new Error(_('No text editor is defined. Please set it using `config editor <editor-path>`'));
|
throw new Error(_('No text editor is defined. Please set it using `config editor <editor-path>`'));
|
||||||
}
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
@@ -76,18 +71,30 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
this.logger().info('Disabling fullscreen...');
|
this.logger().info('Disabling fullscreen...');
|
||||||
|
|
||||||
app().gui().showModalOverlay(_('Starting to edit note. Close the editor to get back to the prompt.'));
|
app()
|
||||||
await app().gui().forceRender();
|
.gui()
|
||||||
const termState = app().gui().termSaveState();
|
.showModalOverlay(_('Starting to edit note. Close the editor to get back to the prompt.'));
|
||||||
|
await app()
|
||||||
|
.gui()
|
||||||
|
.forceRender();
|
||||||
|
const termState = app()
|
||||||
|
.gui()
|
||||||
|
.termSaveState();
|
||||||
|
|
||||||
const spawnSync = require('child_process').spawnSync;
|
const spawnSync = require('child_process').spawnSync;
|
||||||
const result = spawnSync(editorPath, editorArgs, { stdio: 'inherit' });
|
const result = spawnSync(editorPath, editorArgs, { stdio: 'inherit' });
|
||||||
|
|
||||||
if (result.error) this.stdout(_('Error opening note in editor: %s', result.error.message));
|
if (result.error) this.stdout(_('Error opening note in editor: %s', result.error.message));
|
||||||
|
|
||||||
app().gui().termRestoreState(termState);
|
app()
|
||||||
app().gui().hideModalOverlay();
|
.gui()
|
||||||
app().gui().forceRender();
|
.termRestoreState(termState);
|
||||||
|
app()
|
||||||
|
.gui()
|
||||||
|
.hideModalOverlay();
|
||||||
|
app()
|
||||||
|
.gui()
|
||||||
|
.forceRender();
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Save the note and clean up
|
// Save the note and clean up
|
||||||
@@ -107,13 +114,11 @@ class Command extends BaseCommand {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await onFinishedEditing();
|
await onFinishedEditing();
|
||||||
|
} catch (error) {
|
||||||
} catch(error) {
|
|
||||||
await onFinishedEditing();
|
await onFinishedEditing();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -3,7 +3,6 @@ const { app } = require('./app.js');
|
|||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'exit';
|
return 'exit';
|
||||||
}
|
}
|
||||||
@@ -19,7 +18,6 @@ class Command extends BaseCommand {
|
|||||||
async action(args) {
|
async action(args) {
|
||||||
await app().exit();
|
await app().exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -1,13 +1,10 @@
|
|||||||
const { BaseCommand } = require('./base-command.js');
|
const { BaseCommand } = require('./base-command.js');
|
||||||
const { Database } = require('lib/database.js');
|
|
||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
const { _ } = require('lib/locale.js');
|
|
||||||
const { ReportService } = require('lib/services/report.js');
|
const { ReportService } = require('lib/services/report.js');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'export-sync-status';
|
return 'export-sync-status';
|
||||||
}
|
}
|
||||||
@@ -23,14 +20,17 @@ class Command extends BaseCommand {
|
|||||||
async action(args) {
|
async action(args) {
|
||||||
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().gui().showConsole();
|
app()
|
||||||
app().gui().maximizeConsole();
|
.gui()
|
||||||
|
.showConsole();
|
||||||
|
app()
|
||||||
|
.gui()
|
||||||
|
.maximizeConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -1,14 +1,10 @@
|
|||||||
const { BaseCommand } = require('./base-command.js');
|
const { BaseCommand } = require('./base-command.js');
|
||||||
const InteropService = require('lib/services/InteropService.js');
|
const InteropService = require('lib/services/InteropService.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const Note = require('lib/models/Note.js');
|
|
||||||
const { reg } = require('lib/registry.js');
|
|
||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const fs = require('fs-extra');
|
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'export <path>';
|
return 'export <path>';
|
||||||
}
|
}
|
||||||
@@ -19,15 +15,12 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
options() {
|
options() {
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
const formats = service.modules()
|
const formats = service
|
||||||
|
.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 [
|
return [['--format <format>', _('Destination format: %s', formats.join(', '))], ['--note <note>', _('Exports only the given note.')], ['--notebook <notebook>', _('Exports only the given notebook.')]];
|
||||||
['--format <format>', _('Destination format: %s', formats.join(', '))],
|
|
||||||
['--note <note>', _('Exports only the given note.')],
|
|
||||||
['--notebook <notebook>', _('Exports only the given notebook.')],
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async action(args) {
|
async action(args) {
|
||||||
@@ -37,25 +30,20 @@ class Command extends BaseCommand {
|
|||||||
exportOptions.format = args.options.format ? args.options.format : 'jex';
|
exportOptions.format = args.options.format ? args.options.format : 'jex';
|
||||||
|
|
||||||
if (args.options.note) {
|
if (args.options.note) {
|
||||||
|
|
||||||
const notes = await app().loadItems(BaseModel.TYPE_NOTE, args.options.note, { parent: app().currentFolder() });
|
const notes = await app().loadItems(BaseModel.TYPE_NOTE, args.options.note, { parent: app().currentFolder() });
|
||||||
if (!notes.length) throw new Error(_('Cannot find "%s".', args.options.note));
|
if (!notes.length) throw new Error(_('Cannot find "%s".', args.options.note));
|
||||||
exportOptions.sourceNoteIds = notes.map((n) => n.id);
|
exportOptions.sourceNoteIds = notes.map(n => n.id);
|
||||||
|
|
||||||
} else if (args.options.notebook) {
|
} else if (args.options.notebook) {
|
||||||
|
|
||||||
const folders = await app().loadItems(BaseModel.TYPE_FOLDER, args.options.notebook);
|
const folders = await app().loadItems(BaseModel.TYPE_FOLDER, args.options.notebook);
|
||||||
if (!folders.length) throw new Error(_('Cannot find "%s".', args.options.notebook));
|
if (!folders.length) throw new Error(_('Cannot find "%s".', args.options.notebook));
|
||||||
exportOptions.sourceFolderIds = folders.map((n) => n.id);
|
exportOptions.sourceFolderIds = folders.map(n => n.id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
const result = await service.export(exportOptions);
|
const result = await service.export(exportOptions);
|
||||||
|
|
||||||
result.warnings.map((w) => this.stdout(w));
|
result.warnings.map(w => this.stdout(w));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -2,11 +2,9 @@ const { BaseCommand } = require('./base-command.js');
|
|||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const Folder = require('lib/models/Folder.js');
|
|
||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'geoloc <note>';
|
return 'geoloc <note>';
|
||||||
}
|
}
|
||||||
@@ -23,9 +21,10 @@ class Command extends BaseCommand {
|
|||||||
const url = Note.geolocationUrl(item);
|
const url = Note.geolocationUrl(item);
|
||||||
this.stdout(url);
|
this.stdout(url);
|
||||||
|
|
||||||
app().gui().showConsole();
|
app()
|
||||||
|
.gui()
|
||||||
|
.showConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -1,14 +1,10 @@
|
|||||||
const { BaseCommand } = require('./base-command.js');
|
const { BaseCommand } = require('./base-command.js');
|
||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { renderCommandHelp } = require('./help-utils.js');
|
const { renderCommandHelp } = require('./help-utils.js');
|
||||||
const { Database } = require('lib/database.js');
|
|
||||||
const Setting = require('lib/models/Setting.js');
|
|
||||||
const { wrap } = require('lib/string-utils.js');
|
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const { cliUtils } = require('./cli-utils.js');
|
const { cliUtils } = require('./cli-utils.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'help [command]';
|
return 'help [command]';
|
||||||
}
|
}
|
||||||
@@ -28,7 +24,7 @@ class Command extends BaseCommand {
|
|||||||
output.push(command);
|
output.push(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
output.sort((a, b) => a.name() < b.name() ? -1 : +1);
|
output.sort((a, b) => (a.name() < b.name() ? -1 : +1));
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@@ -40,31 +36,37 @@ class Command extends BaseCommand {
|
|||||||
this.stdout(_('For information on how to customise the shortcuts please visit %s', 'https://joplinapp.org/terminal/#shortcuts'));
|
this.stdout(_('For information on how to customise the shortcuts please visit %s', 'https://joplinapp.org/terminal/#shortcuts'));
|
||||||
this.stdout('');
|
this.stdout('');
|
||||||
|
|
||||||
if (app().gui().isDummy()) {
|
if (
|
||||||
|
app()
|
||||||
|
.gui()
|
||||||
|
.isDummy()
|
||||||
|
) {
|
||||||
throw new Error(_('Shortcuts are not available in CLI mode.'));
|
throw new Error(_('Shortcuts are not available in CLI mode.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
const keymap = app().gui().keymap();
|
const keymap = app()
|
||||||
|
.gui()
|
||||||
|
.keymap();
|
||||||
|
|
||||||
let rows = [];
|
let rows = [];
|
||||||
|
|
||||||
for (let i = 0; i < keymap.length; i++) {
|
for (let i = 0; i < keymap.length; i++) {
|
||||||
const item = keymap[i];
|
const item = keymap[i];
|
||||||
const keys = item.keys.map((k) => k === ' ' ? '(SPACE)' : k);
|
const keys = item.keys.map(k => (k === ' ' ? '(SPACE)' : k));
|
||||||
rows.push([keys.join(', '), item.command]);
|
rows.push([keys.join(', '), item.command]);
|
||||||
}
|
}
|
||||||
|
|
||||||
cliUtils.printArray(this.stdout.bind(this), rows);
|
cliUtils.printArray(this.stdout.bind(this), rows);
|
||||||
} else if (args.command === 'all') {
|
} else if (args.command === 'all') {
|
||||||
const commands = this.allCommands();
|
const commands = this.allCommands();
|
||||||
const output = commands.map((c) => renderCommandHelp(c));
|
const output = commands.map(c => renderCommandHelp(c));
|
||||||
this.stdout(output.join('\n\n'));
|
this.stdout(output.join('\n\n'));
|
||||||
} else if (args.command) {
|
} else if (args.command) {
|
||||||
const command = app().findCommandByName(args['command']);
|
const command = app().findCommandByName(args['command']);
|
||||||
if (!command) throw new Error(_('Cannot find "%s".', args.command));
|
if (!command) throw new Error(_('Cannot find "%s".', args.command));
|
||||||
this.stdout(renderCommandHelp(command, stdoutWidth));
|
this.stdout(renderCommandHelp(command, stdoutWidth));
|
||||||
} else {
|
} else {
|
||||||
const commandNames = this.allCommands().map((a) => a.name());
|
const commandNames = this.allCommands().map(a => a.name());
|
||||||
|
|
||||||
this.stdout(_('Type `help [command]` for more information about a command; or type `help all` for the complete usage information.'));
|
this.stdout(_('Type `help [command]` for more information about a command; or type `help all` for the complete usage information.'));
|
||||||
this.stdout('');
|
this.stdout('');
|
||||||
@@ -82,10 +84,13 @@ class Command extends BaseCommand {
|
|||||||
this.stdout(_('For the list of keyboard shortcuts and config options, type `help keymap`'));
|
this.stdout(_('For the list of keyboard shortcuts and config options, type `help keymap`'));
|
||||||
}
|
}
|
||||||
|
|
||||||
app().gui().showConsole();
|
app()
|
||||||
app().gui().maximizeConsole();
|
.gui()
|
||||||
|
.showConsole();
|
||||||
|
app()
|
||||||
|
.gui()
|
||||||
|
.maximizeConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -1,17 +1,11 @@
|
|||||||
const { BaseCommand } = require('./base-command.js');
|
const { BaseCommand } = require('./base-command.js');
|
||||||
const InteropService = require('lib/services/InteropService.js');
|
const InteropService = require('lib/services/InteropService.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const Note = require('lib/models/Note.js');
|
|
||||||
const { filename, basename, fileExtension } = require('lib/path-utils.js');
|
|
||||||
const { importEnex } = require('lib/import-enex');
|
|
||||||
const { cliUtils } = require('./cli-utils.js');
|
const { cliUtils } = require('./cli-utils.js');
|
||||||
const { reg } = require('lib/registry.js');
|
|
||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const fs = require('fs-extra');
|
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'import <path> [notebook]';
|
return 'import <path> [notebook]';
|
||||||
}
|
}
|
||||||
@@ -22,12 +16,12 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
options() {
|
options() {
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
const formats = service.modules().filter(m => m.type === 'importer').map(m => m.format);
|
const formats = service
|
||||||
|
.modules()
|
||||||
|
.filter(m => m.type === 'importer')
|
||||||
|
.map(m => m.format);
|
||||||
|
|
||||||
return [
|
return [['--format <format>', _('Source format: %s', ['auto'].concat(formats).join(', '))], ['-f, --force', _('Do not ask for confirmation.')]];
|
||||||
['--format <format>', _('Source format: %s', (['auto'].concat(formats)).join(', '))],
|
|
||||||
['-f, --force', _('Do not ask for confirmation.')],
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async action(args) {
|
async action(args) {
|
||||||
@@ -44,7 +38,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
// onProgress/onError supported by Enex import only
|
// onProgress/onError supported by Enex import only
|
||||||
|
|
||||||
importOptions.onProgress = (progressState) => {
|
importOptions.onProgress = progressState => {
|
||||||
let line = [];
|
let line = [];
|
||||||
line.push(_('Found: %d.', progressState.loaded));
|
line.push(_('Found: %d.', progressState.loaded));
|
||||||
line.push(_('Created: %d.', progressState.created));
|
line.push(_('Created: %d.', progressState.created));
|
||||||
@@ -56,20 +50,21 @@ class Command extends BaseCommand {
|
|||||||
cliUtils.redraw(lastProgress);
|
cliUtils.redraw(lastProgress);
|
||||||
};
|
};
|
||||||
|
|
||||||
importOptions.onError = (error) => {
|
importOptions.onError = error => {
|
||||||
let s = error.trace ? error.trace : error.toString();
|
let s = error.trace ? error.trace : error.toString();
|
||||||
this.stdout(s);
|
this.stdout(s);
|
||||||
};
|
};
|
||||||
|
|
||||||
app().gui().showConsole();
|
app()
|
||||||
|
.gui()
|
||||||
|
.showConsole();
|
||||||
this.stdout(_('Importing notes...'));
|
this.stdout(_('Importing notes...'));
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
const result = await service.import(importOptions);
|
const result = await service.import(importOptions);
|
||||||
result.warnings.map((w) => this.stdout(w));
|
result.warnings.map(w => this.stdout(w));
|
||||||
cliUtils.redrawDone();
|
cliUtils.redrawDone();
|
||||||
if (lastProgress) this.stdout(_('The notes have been imported: %s', lastProgress));
|
if (lastProgress) this.stdout(_('The notes have been imported: %s', lastProgress));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -10,7 +10,6 @@ const { time } = require('lib/time-utils.js');
|
|||||||
const { cliUtils } = require('./cli-utils.js');
|
const { cliUtils } = require('./cli-utils.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'ls [note-pattern]';
|
return 'ls [note-pattern]';
|
||||||
}
|
}
|
||||||
@@ -24,14 +23,7 @@ class Command extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
options() {
|
options() {
|
||||||
return [
|
return [['-n, --limit <num>', _('Displays only the first top <num> notes.')], ['-s, --sort <field>', _('Sorts the item by <field> (eg. title, updated_time, created_time).')], ['-r, --reverse', _('Reverses the sorting order.')], ['-t, --type <type>', _('Displays only the items of the specific type(s). Can be `n` for notes, `t` for to-dos, or `nt` for notes and to-dos (eg. `-tt` would display only the to-dos, while `-ttd` would display notes and to-dos.')], ['-f, --format <format>', _('Either "text" or "json"')], ['-l, --long', _('Use long list format. Format is ID, NOTE_COUNT (for notebook), DATE, TODO_CHECKED (for to-dos), TITLE')]];
|
||||||
['-n, --limit <num>', _('Displays only the first top <num> notes.')],
|
|
||||||
['-s, --sort <field>', _('Sorts the item by <field> (eg. title, updated_time, created_time).')],
|
|
||||||
['-r, --reverse', _('Reverses the sorting order.')],
|
|
||||||
['-t, --type <type>', _('Displays only the items of the specific type(s). Can be `n` for notes, `t` for to-dos, or `nt` for notes and to-dos (eg. `-tt` would display only the to-dos, while `-ttd` would display notes and to-dos.')],
|
|
||||||
['-f, --format <format>', _('Either "text" or "json"')],
|
|
||||||
['-l, --long', _('Use long list format. Format is ID, NOTE_COUNT (for notebook), DATE, TODO_CHECKED (for to-dos), TITLE')],
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async action(args) {
|
async action(args) {
|
||||||
@@ -105,7 +97,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
if (hasTodos) {
|
if (hasTodos) {
|
||||||
if (item.is_todo) {
|
if (item.is_todo) {
|
||||||
row.push(sprintf('[%s]', !!item.todo_completed ? 'X' : ' '));
|
row.push(sprintf('[%s]', item.todo_completed ? 'X' : ' '));
|
||||||
} else {
|
} else {
|
||||||
row.push(' ');
|
row.push(' ');
|
||||||
}
|
}
|
||||||
@@ -118,9 +110,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
cliUtils.printArray(this.stdout.bind(this), rows);
|
cliUtils.printArray(this.stdout.bind(this), rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
||||||
|
@@ -2,10 +2,8 @@ const { BaseCommand } = require('./base-command.js');
|
|||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const Folder = require('lib/models/Folder.js');
|
const Folder = require('lib/models/Folder.js');
|
||||||
const { reg } = require('lib/registry.js');
|
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'mkbook <new-notebook>';
|
return 'mkbook <new-notebook>';
|
||||||
}
|
}
|
||||||
@@ -18,7 +16,6 @@ class Command extends BaseCommand {
|
|||||||
let folder = await Folder.save({ title: args['new-notebook'] }, { userSideValidation: true });
|
let folder = await Folder.save({ title: args['new-notebook'] }, { userSideValidation: true });
|
||||||
app().switchCurrentFolder(folder);
|
app().switchCurrentFolder(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -4,7 +4,6 @@ const { _ } = require('lib/locale.js');
|
|||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'mknote <new-note>';
|
return 'mknote <new-note>';
|
||||||
}
|
}
|
||||||
@@ -26,7 +25,6 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
app().switchCurrentFolder(app().currentFolder());
|
app().switchCurrentFolder(app().currentFolder());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -4,7 +4,6 @@ const { _ } = require('lib/locale.js');
|
|||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'mktodo <new-todo>';
|
return 'mktodo <new-todo>';
|
||||||
}
|
}
|
||||||
@@ -27,7 +26,6 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
app().switchCurrentFolder(app().currentFolder());
|
app().switchCurrentFolder(app().currentFolder());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -6,7 +6,6 @@ const Folder = require('lib/models/Folder.js');
|
|||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'mv <note> [notebook]';
|
return 'mv <note> [notebook]';
|
||||||
}
|
}
|
||||||
@@ -29,7 +28,6 @@ class Command extends BaseCommand {
|
|||||||
await Note.moveToFolder(notes[i].id, folder.id);
|
await Note.moveToFolder(notes[i].id, folder.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -6,7 +6,6 @@ const Folder = require('lib/models/Folder.js');
|
|||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'ren <item> <name>';
|
return 'ren <item> <name>';
|
||||||
}
|
}
|
||||||
@@ -35,7 +34,6 @@ class Command extends BaseCommand {
|
|||||||
await Note.save(newItem);
|
await Note.save(newItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -1,14 +1,10 @@
|
|||||||
const { BaseCommand } = require('./base-command.js');
|
const { BaseCommand } = require('./base-command.js');
|
||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const BaseItem = require('lib/models/BaseItem.js');
|
|
||||||
const Folder = require('lib/models/Folder.js');
|
const Folder = require('lib/models/Folder.js');
|
||||||
const Note = require('lib/models/Note.js');
|
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const { cliUtils } = require('./cli-utils.js');
|
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'rmbook <notebook>';
|
return 'rmbook <notebook>';
|
||||||
}
|
}
|
||||||
@@ -18,9 +14,7 @@ class Command extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
options() {
|
options() {
|
||||||
return [
|
return [['-f, --force', _('Deletes the notebook without asking for confirmation.')]];
|
||||||
['-f, --force', _('Deletes the notebook without asking for confirmation.')],
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async action(args) {
|
async action(args) {
|
||||||
@@ -34,7 +28,6 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
await Folder.delete(folder.id);
|
await Folder.delete(folder.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -1,14 +1,10 @@
|
|||||||
const { BaseCommand } = require('./base-command.js');
|
const { BaseCommand } = require('./base-command.js');
|
||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const BaseItem = require('lib/models/BaseItem.js');
|
|
||||||
const Folder = require('lib/models/Folder.js');
|
|
||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const { cliUtils } = require('./cli-utils.js');
|
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'rmnote <note-pattern>';
|
return 'rmnote <note-pattern>';
|
||||||
}
|
}
|
||||||
@@ -18,9 +14,7 @@ class Command extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
options() {
|
options() {
|
||||||
return [
|
return [['-f, --force', _('Deletes the notes without asking for confirmation.')]];
|
||||||
['-f, --force', _('Deletes the notes without asking for confirmation.')],
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async action(args) {
|
async action(args) {
|
||||||
@@ -32,10 +26,9 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
const ok = force ? true : await this.prompt(notes.length > 1 ? _('%d notes match this pattern. Delete them?', notes.length) : _('Delete note?'), { booleanAnswerDefault: 'n' });
|
const ok = force ? true : await this.prompt(notes.length > 1 ? _('%d notes match this pattern. Delete them?', notes.length) : _('Delete note?'), { booleanAnswerDefault: 'n' });
|
||||||
if (!ok) return;
|
if (!ok) return;
|
||||||
let ids = notes.map((n) => n.id);
|
let ids = notes.map(n => n.id);
|
||||||
await Note.batchDelete(ids);
|
await Note.batchDelete(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -1,15 +1,10 @@
|
|||||||
const { BaseCommand } = require('./base-command.js');
|
const { BaseCommand } = require('./base-command.js');
|
||||||
const { app } = require('./app.js');
|
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const Folder = require('lib/models/Folder.js');
|
const Folder = require('lib/models/Folder.js');
|
||||||
const Note = require('lib/models/Note.js');
|
|
||||||
const { sprintf } = require('sprintf-js');
|
|
||||||
const { time } = require('lib/time-utils.js');
|
|
||||||
const { uuid } = require('lib/uuid.js');
|
const { uuid } = require('lib/uuid.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'search <pattern> [notebook]';
|
return 'search <pattern> [notebook]';
|
||||||
}
|
}
|
||||||
@@ -50,7 +45,6 @@ class Command extends BaseCommand {
|
|||||||
id: searchId,
|
id: searchId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -3,12 +3,9 @@ const { app } = require('./app.js');
|
|||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const { Database } = require('lib/database.js');
|
const { Database } = require('lib/database.js');
|
||||||
const Folder = require('lib/models/Folder.js');
|
|
||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
const BaseItem = require('lib/models/BaseItem.js');
|
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'set <note> <name> [value]';
|
return 'set <note> <name> [value]';
|
||||||
}
|
}
|
||||||
@@ -45,7 +42,6 @@ class Command extends BaseCommand {
|
|||||||
await Note.save(newNote);
|
await Note.save(newNote);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -1,12 +1,10 @@
|
|||||||
const { BaseCommand } = require('./base-command.js');
|
const { BaseCommand } = require('./base-command.js');
|
||||||
const { Database } = require('lib/database.js');
|
|
||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const { ReportService } = require('lib/services/report.js');
|
const { ReportService } = require('lib/services/report.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'status';
|
return 'status';
|
||||||
}
|
}
|
||||||
@@ -34,10 +32,13 @@ class Command extends BaseCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app().gui().showConsole();
|
app()
|
||||||
app().gui().maximizeConsole();
|
.gui()
|
||||||
|
.showConsole();
|
||||||
|
app()
|
||||||
|
.gui()
|
||||||
|
.maximizeConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -3,7 +3,6 @@ const { app } = require('./app.js');
|
|||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const { OneDriveApiNodeUtils } = require('./onedrive-api-node-utils.js');
|
const { OneDriveApiNodeUtils } = require('./onedrive-api-node-utils.js');
|
||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
const BaseItem = require('lib/models/BaseItem.js');
|
|
||||||
const ResourceFetcher = require('lib/services/ResourceFetcher');
|
const ResourceFetcher = require('lib/services/ResourceFetcher');
|
||||||
const { Synchronizer } = require('lib/synchronizer.js');
|
const { Synchronizer } = require('lib/synchronizer.js');
|
||||||
const { reg } = require('lib/registry.js');
|
const { reg } = require('lib/registry.js');
|
||||||
@@ -14,7 +13,6 @@ const fs = require('fs-extra');
|
|||||||
const SyncTargetRegistry = require('lib/SyncTargetRegistry');
|
const SyncTargetRegistry = require('lib/SyncTargetRegistry');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.syncTargetId_ = null;
|
this.syncTargetId_ = null;
|
||||||
@@ -31,9 +29,7 @@ class Command extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
options() {
|
options() {
|
||||||
return [
|
return [['--target <target>', _('Sync to provided target (defaults to sync.target config value)')]];
|
||||||
['--target <target>', _('Sync to provided target (defaults to sync.target config value)')],
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static lockFile(filePath) {
|
static lockFile(filePath) {
|
||||||
@@ -66,10 +62,13 @@ class Command extends BaseCommand {
|
|||||||
const syncTarget = reg.syncTarget(this.syncTargetId_);
|
const syncTarget = reg.syncTarget(this.syncTargetId_);
|
||||||
const syncTargetMd = SyncTargetRegistry.idToMetadata(this.syncTargetId_);
|
const syncTargetMd = SyncTargetRegistry.idToMetadata(this.syncTargetId_);
|
||||||
|
|
||||||
if (this.syncTargetId_ === 3 || this.syncTargetId_ === 4) { // OneDrive
|
if (this.syncTargetId_ === 3 || this.syncTargetId_ === 4) {
|
||||||
|
// OneDrive
|
||||||
this.oneDriveApiUtils_ = new OneDriveApiNodeUtils(syncTarget.api());
|
this.oneDriveApiUtils_ = new OneDriveApiNodeUtils(syncTarget.api());
|
||||||
const auth = await this.oneDriveApiUtils_.oauthDance({
|
const auth = await this.oneDriveApiUtils_.oauthDance({
|
||||||
log: (...s) => { return this.stdout(...s); }
|
log: (...s) => {
|
||||||
|
return this.stdout(...s);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
this.oneDriveApiUtils_ = null;
|
this.oneDriveApiUtils_ = null;
|
||||||
|
|
||||||
@@ -80,7 +79,8 @@ class Command extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (syncTargetMd.name === 'dropbox') { // Dropbox
|
} else if (syncTargetMd.name === 'dropbox') {
|
||||||
|
// Dropbox
|
||||||
const api = await syncTarget.api();
|
const api = await syncTarget.api();
|
||||||
const loginUrl = api.loginUrl();
|
const loginUrl = api.loginUrl();
|
||||||
this.stdout(_('To allow Joplin to synchronise with Dropbox, please follow the steps below:'));
|
this.stdout(_('To allow Joplin to synchronise with Dropbox, please follow the steps below:'));
|
||||||
@@ -118,7 +118,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
// 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 {
|
||||||
if (await Command.isLocked(lockFilePath)) throw new Error(_('Synchronisation is already in progress.'));
|
if (await Command.isLocked(lockFilePath)) throw new Error(_('Synchronisation is already in progress.'));
|
||||||
@@ -147,9 +147,13 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
const syncTarget = reg.syncTarget(this.syncTargetId_);
|
const syncTarget = reg.syncTarget(this.syncTargetId_);
|
||||||
|
|
||||||
if (!await syncTarget.isAuthenticated()) {
|
if (!(await syncTarget.isAuthenticated())) {
|
||||||
app().gui().showConsole();
|
app()
|
||||||
app().gui().maximizeConsole();
|
.gui()
|
||||||
|
.showConsole();
|
||||||
|
app()
|
||||||
|
.gui()
|
||||||
|
.maximizeConsole();
|
||||||
|
|
||||||
const authDone = await this.doAuth();
|
const authDone = await this.doAuth();
|
||||||
if (!authDone) return cleanUp();
|
if (!authDone) return cleanUp();
|
||||||
@@ -158,11 +162,11 @@ class Command extends BaseCommand {
|
|||||||
const sync = await syncTarget.synchronizer();
|
const sync = await syncTarget.synchronizer();
|
||||||
|
|
||||||
let options = {
|
let options = {
|
||||||
onProgress: (report) => {
|
onProgress: report => {
|
||||||
let lines = Synchronizer.reportToLines(report);
|
let lines = Synchronizer.reportToLines(report);
|
||||||
if (lines.length) cliUtils.redraw(lines.join(' '));
|
if (lines.length) cliUtils.redraw(lines.join(' '));
|
||||||
},
|
},
|
||||||
onMessage: (msg) => {
|
onMessage: msg => {
|
||||||
cliUtils.redrawDone();
|
cliUtils.redrawDone();
|
||||||
this.stdout(msg);
|
this.stdout(msg);
|
||||||
},
|
},
|
||||||
@@ -237,7 +241,6 @@ class Command extends BaseCommand {
|
|||||||
cancellable() {
|
cancellable() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -6,7 +6,6 @@ const BaseModel = require('lib/BaseModel.js');
|
|||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'tag <tag-command> [tag] [note]';
|
return 'tag <tag-command> [tag] [note]';
|
||||||
}
|
}
|
||||||
@@ -16,9 +15,7 @@ class Command extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
options() {
|
options() {
|
||||||
return [
|
return [['-l, --long', _('Use long list format. Format is ID, NOTE_COUNT (for notebook), DATE, TODO_CHECKED (for to-dos), TITLE')]];
|
||||||
['-l, --long', _('Use long list format. Format is ID, NOTE_COUNT (for notebook), DATE, TODO_CHECKED (for to-dos), TITLE')],
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async action(args) {
|
async action(args) {
|
||||||
@@ -50,7 +47,7 @@ class Command extends BaseCommand {
|
|||||||
} else if (command == 'list') {
|
} else if (command == 'list') {
|
||||||
if (tag) {
|
if (tag) {
|
||||||
let notes = await Tag.notes(tag.id);
|
let notes = await Tag.notes(tag.id);
|
||||||
notes.map((note) => {
|
notes.map(note => {
|
||||||
let line = '';
|
let line = '';
|
||||||
if (options.long) {
|
if (options.long) {
|
||||||
line += BaseModel.shortId(note.id);
|
line += BaseModel.shortId(note.id);
|
||||||
@@ -74,13 +71,14 @@ class Command extends BaseCommand {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let tags = await Tag.all();
|
let tags = await Tag.all();
|
||||||
tags.map((tag) => { this.stdout(tag.title); });
|
tags.map(tag => {
|
||||||
|
this.stdout(tag.title);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Error(_('Invalid command: "%s"', command));
|
throw new Error(_('Invalid command: "%s"', command));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -2,12 +2,10 @@ const { BaseCommand } = require('./base-command.js');
|
|||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const Folder = require('lib/models/Folder.js');
|
|
||||||
const Note = require('lib/models/Note.js');
|
const Note = require('lib/models/Note.js');
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'todo <todo-command> <note-pattern>';
|
return 'todo <todo-command> <note-pattern>';
|
||||||
}
|
}
|
||||||
@@ -44,7 +42,6 @@ class Command extends BaseCommand {
|
|||||||
await Note.save(toSave);
|
await Note.save(toSave);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -1,15 +1,9 @@
|
|||||||
const { BaseCommand } = require('./base-command.js');
|
const { BaseCommand } = require('./base-command.js');
|
||||||
const { app } = require('./app.js');
|
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
|
||||||
const Folder = require('lib/models/Folder.js');
|
|
||||||
const Note = require('lib/models/Note.js');
|
|
||||||
const { time } = require('lib/time-utils.js');
|
|
||||||
|
|
||||||
const CommandDone = require('./command-done.js');
|
const CommandDone = require('./command-done.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'undone <note>';
|
return 'undone <note>';
|
||||||
}
|
}
|
||||||
@@ -21,7 +15,6 @@ class Command extends BaseCommand {
|
|||||||
async action(args) {
|
async action(args) {
|
||||||
await CommandDone.handleAction(this, args, false);
|
await CommandDone.handleAction(this, args, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -2,10 +2,8 @@ const { BaseCommand } = require('./base-command.js');
|
|||||||
const { app } = require('./app.js');
|
const { app } = require('./app.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
const BaseModel = require('lib/BaseModel.js');
|
||||||
const Folder = require('lib/models/Folder.js');
|
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'use <notebook>';
|
return 'use <notebook>';
|
||||||
}
|
}
|
||||||
@@ -14,10 +12,6 @@ class Command extends BaseCommand {
|
|||||||
return _('Switches to [notebook] - all further operations will happen within this notebook.');
|
return _('Switches to [notebook] - all further operations will happen within this notebook.');
|
||||||
}
|
}
|
||||||
|
|
||||||
autocomplete() {
|
|
||||||
return { data: autocompleteFolders };
|
|
||||||
}
|
|
||||||
|
|
||||||
compatibleUis() {
|
compatibleUis() {
|
||||||
return ['cli'];
|
return ['cli'];
|
||||||
}
|
}
|
||||||
@@ -27,7 +21,6 @@ class Command extends BaseCommand {
|
|||||||
if (!folder) throw new Error(_('Cannot find "%s".', args['notebook']));
|
if (!folder) throw new Error(_('Cannot find "%s".', args['notebook']));
|
||||||
app().switchCurrentFolder(folder);
|
app().switchCurrentFolder(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
@@ -3,7 +3,6 @@ const Setting = require('lib/models/Setting.js');
|
|||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
return 'version';
|
return 'version';
|
||||||
}
|
}
|
||||||
@@ -16,7 +15,6 @@ class Command extends BaseCommand {
|
|||||||
const p = require('./package.json');
|
const p = require('./package.json');
|
||||||
this.stdout(_('%s %s (%s)', p.name, p.version, Setting.value('env')));
|
this.stdout(_('%s %s (%s)', p.name, p.version, Setting.value('env')));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Command;
|
module.exports = Command;
|
File diff suppressed because one or more lines are too long
@@ -1,7 +1,6 @@
|
|||||||
const TextWidget = require('tkwidgets/TextWidget.js');
|
const TextWidget = require('tkwidgets/TextWidget.js');
|
||||||
|
|
||||||
class ConsoleWidget extends TextWidget {
|
class ConsoleWidget extends TextWidget {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.lines_ = [];
|
this.lines_ = [];
|
||||||
@@ -16,7 +15,7 @@ class ConsoleWidget extends TextWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get lastLine() {
|
get lastLine() {
|
||||||
return this.lines_.length ? this.lines_[this.lines_.length-1] : '';
|
return this.lines_.length ? this.lines_[this.lines_.length - 1] : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
addLine(line) {
|
addLine(line) {
|
||||||
@@ -40,13 +39,12 @@ class ConsoleWidget extends TextWidget {
|
|||||||
if (this.lines_.length > this.maxLines_) {
|
if (this.lines_.length > this.maxLines_) {
|
||||||
this.lines_.splice(0, this.lines_.length - this.maxLines_);
|
this.lines_.splice(0, this.lines_.length - this.maxLines_);
|
||||||
}
|
}
|
||||||
this.text = this.lines_.join("\n");
|
this.text = this.lines_.join('\n');
|
||||||
this.updateText_ = false;
|
this.updateText_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
super.render();
|
super.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ConsoleWidget;
|
module.exports = ConsoleWidget;
|
@@ -5,7 +5,6 @@ const ListWidget = require('tkwidgets/ListWidget.js');
|
|||||||
const _ = require('lib/locale.js')._;
|
const _ = require('lib/locale.js')._;
|
||||||
|
|
||||||
class FolderListWidget extends ListWidget {
|
class FolderListWidget extends ListWidget {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -20,7 +19,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
this.updateItems_ = false;
|
this.updateItems_ = false;
|
||||||
this.trimItemTitle = false;
|
this.trimItemTitle = false;
|
||||||
|
|
||||||
this.itemRenderer = (item) => {
|
this.itemRenderer = item => {
|
||||||
let output = [];
|
let output = [];
|
||||||
if (item === '-') {
|
if (item === '-') {
|
||||||
output.push('-'.repeat(this.innerWidth));
|
output.push('-'.repeat(this.innerWidth));
|
||||||
@@ -45,7 +44,6 @@ class FolderListWidget extends ListWidget {
|
|||||||
output++;
|
output++;
|
||||||
folderId = folder.parent_id;
|
folderId = folder.parent_id;
|
||||||
}
|
}
|
||||||
throw new Error('unreachable');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get selectedFolderId() {
|
get selectedFolderId() {
|
||||||
@@ -54,7 +52,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
|
|
||||||
set selectedFolderId(v) {
|
set selectedFolderId(v) {
|
||||||
this.selectedFolderId_ = v;
|
this.selectedFolderId_ = v;
|
||||||
this.updateIndexFromSelectedItemId()
|
this.updateIndexFromSelectedItemId();
|
||||||
this.invalidate();
|
this.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +62,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
|
|
||||||
set selectedSearchId(v) {
|
set selectedSearchId(v) {
|
||||||
this.selectedSearchId_ = v;
|
this.selectedSearchId_ = v;
|
||||||
this.updateIndexFromSelectedItemId()
|
this.updateIndexFromSelectedItemId();
|
||||||
this.invalidate();
|
this.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +72,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
|
|
||||||
set selectedTagId(v) {
|
set selectedTagId(v) {
|
||||||
this.selectedTagId_ = v;
|
this.selectedTagId_ = v;
|
||||||
this.updateIndexFromSelectedItemId()
|
this.updateIndexFromSelectedItemId();
|
||||||
this.invalidate();
|
this.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +82,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
|
|
||||||
set notesParentType(v) {
|
set notesParentType(v) {
|
||||||
this.notesParentType_ = v;
|
this.notesParentType_ = v;
|
||||||
this.updateIndexFromSelectedItemId()
|
this.updateIndexFromSelectedItemId();
|
||||||
this.invalidate();
|
this.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +93,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
set searches(v) {
|
set searches(v) {
|
||||||
this.searches_ = v;
|
this.searches_ = v;
|
||||||
this.updateItems_ = true;
|
this.updateItems_ = true;
|
||||||
this.updateIndexFromSelectedItemId()
|
this.updateIndexFromSelectedItemId();
|
||||||
this.invalidate();
|
this.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +104,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
set tags(v) {
|
set tags(v) {
|
||||||
this.tags_ = v;
|
this.tags_ = v;
|
||||||
this.updateItems_ = true;
|
this.updateItems_ = true;
|
||||||
this.updateIndexFromSelectedItemId()
|
this.updateIndexFromSelectedItemId();
|
||||||
this.invalidate();
|
this.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +115,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
set folders(v) {
|
set folders(v) {
|
||||||
this.folders_ = v;
|
this.folders_ = v;
|
||||||
this.updateItems_ = true;
|
this.updateItems_ = true;
|
||||||
this.updateIndexFromSelectedItemId()
|
this.updateIndexFromSelectedItemId();
|
||||||
this.invalidate();
|
this.invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +134,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
const previousParentType = this.notesParentType;
|
const previousParentType = this.notesParentType;
|
||||||
|
|
||||||
let newItems = [];
|
let newItems = [];
|
||||||
const orderFolders = (parentId) => {
|
const orderFolders = parentId => {
|
||||||
for (let i = 0; i < this.folders.length; i++) {
|
for (let i = 0; i < this.folders.length; i++) {
|
||||||
const f = this.folders[i];
|
const f = this.folders[i];
|
||||||
const folderParentId = f.parent_id ? f.parent_id : '';
|
const folderParentId = f.parent_id ? f.parent_id : '';
|
||||||
@@ -145,7 +143,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
if (this.folderHasChildren_(this.folders, f.id)) orderFolders(f.id);
|
if (this.folderHasChildren_(this.folders, f.id)) orderFolders(f.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
orderFolders('');
|
orderFolders('');
|
||||||
|
|
||||||
@@ -162,7 +160,7 @@ class FolderListWidget extends ListWidget {
|
|||||||
this.items = newItems;
|
this.items = newItems;
|
||||||
|
|
||||||
this.notesParentType = previousParentType;
|
this.notesParentType = previousParentType;
|
||||||
this.updateIndexFromSelectedItemId(wasSelectedItemId)
|
this.updateIndexFromSelectedItemId(wasSelectedItemId);
|
||||||
this.updateItems_ = false;
|
this.updateItems_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +186,6 @@ class FolderListWidget extends ListWidget {
|
|||||||
const index = this.itemIndexByKey('id', itemId);
|
const index = this.itemIndexByKey('id', itemId);
|
||||||
this.currentIndex = index >= 0 ? index : 0;
|
this.currentIndex = index >= 0 ? index : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = FolderListWidget;
|
module.exports = FolderListWidget;
|
@@ -2,14 +2,13 @@ const Note = require('lib/models/Note.js');
|
|||||||
const ListWidget = require('tkwidgets/ListWidget.js');
|
const ListWidget = require('tkwidgets/ListWidget.js');
|
||||||
|
|
||||||
class NoteListWidget extends ListWidget {
|
class NoteListWidget extends ListWidget {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.selectedNoteId_ = 0;
|
this.selectedNoteId_ = 0;
|
||||||
|
|
||||||
this.updateIndexFromSelectedNoteId_ = false;
|
this.updateIndexFromSelectedNoteId_ = false;
|
||||||
|
|
||||||
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;
|
||||||
@@ -32,7 +31,6 @@ class NoteListWidget extends ListWidget {
|
|||||||
|
|
||||||
super.render();
|
super.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = NoteListWidget;
|
module.exports = NoteListWidget;
|
@@ -2,7 +2,6 @@ const Note = require('lib/models/Note.js');
|
|||||||
const TextWidget = require('tkwidgets/TextWidget.js');
|
const TextWidget = require('tkwidgets/TextWidget.js');
|
||||||
|
|
||||||
class NoteMetadataWidget extends TextWidget {
|
class NoteMetadataWidget extends TextWidget {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.noteId_ = 0;
|
this.noteId_ = 0;
|
||||||
@@ -30,7 +29,6 @@ class NoteMetadataWidget extends TextWidget {
|
|||||||
this.text = this.note_ ? await Note.minimalSerializeForDisplay(this.note_) : '';
|
this.text = this.note_ ? await Note.minimalSerializeForDisplay(this.note_) : '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = NoteMetadataWidget;
|
module.exports = NoteMetadataWidget;
|
@@ -3,7 +3,6 @@ const TextWidget = require('tkwidgets/TextWidget.js');
|
|||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
|
|
||||||
class NoteWidget extends TextWidget {
|
class NoteWidget extends TextWidget {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.noteId_ = 0;
|
this.noteId_ = 0;
|
||||||
@@ -48,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;
|
||||||
@@ -59,7 +58,6 @@ class NoteWidget extends TextWidget {
|
|||||||
this.scrollTop = 0;
|
this.scrollTop = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = NoteWidget;
|
module.exports = NoteWidget;
|
@@ -5,7 +5,6 @@ const stripAnsi = require('strip-ansi');
|
|||||||
const { handleAutocompletion } = require('../autocompletion.js');
|
const { handleAutocompletion } = require('../autocompletion.js');
|
||||||
|
|
||||||
class StatusBarWidget extends BaseWidget {
|
class StatusBarWidget extends BaseWidget {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@@ -87,14 +86,13 @@ class StatusBarWidget extends BaseWidget {
|
|||||||
|
|
||||||
//const textStyle = this.promptActive ? (s) => s : chalk.bgBlueBright.white;
|
//const textStyle = this.promptActive ? (s) => s : chalk.bgBlueBright.white;
|
||||||
//const textStyle = (s) => s;
|
//const textStyle = (s) => s;
|
||||||
const textStyle = this.promptActive ? (s) => s : chalk.gray;
|
const textStyle = this.promptActive ? s => s : chalk.gray;
|
||||||
|
|
||||||
this.term.drawHLine(this.absoluteInnerX, this.absoluteInnerY, this.innerWidth, textStyle(' '));
|
this.term.drawHLine(this.absoluteInnerX, this.absoluteInnerY, this.innerWidth, textStyle(' '));
|
||||||
|
|
||||||
this.term.moveTo(this.absoluteInnerX, this.absoluteInnerY);
|
this.term.moveTo(this.absoluteInnerX, this.absoluteInnerY);
|
||||||
|
|
||||||
if (this.promptActive) {
|
if (this.promptActive) {
|
||||||
|
|
||||||
this.term.write(textStyle(this.promptState_.promptString));
|
this.term.write(textStyle(this.promptState_.promptString));
|
||||||
|
|
||||||
if (this.inputEventEmitter_) {
|
if (this.inputEventEmitter_) {
|
||||||
@@ -113,8 +111,8 @@ class StatusBarWidget extends BaseWidget {
|
|||||||
history: this.history,
|
history: this.history,
|
||||||
default: this.promptState_.initialText,
|
default: this.promptState_.initialText,
|
||||||
autoComplete: handleAutocompletion,
|
autoComplete: handleAutocompletion,
|
||||||
autoCompleteHint : true,
|
autoCompleteHint: true,
|
||||||
autoCompleteMenu : true,
|
autoCompleteMenu: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
if ('cursorPosition' in this.promptState_) options.cursorPosition = this.promptState_.cursorPosition;
|
if ('cursorPosition' in this.promptState_) options.cursorPosition = this.promptState_.cursorPosition;
|
||||||
@@ -153,19 +151,15 @@ class StatusBarWidget extends BaseWidget {
|
|||||||
// Only callback once everything has been cleaned up and reset
|
// Only callback once everything has been cleaned up and reset
|
||||||
resolveFn(resolveResult);
|
resolveFn(resolveResult);
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
for (let i = 0; i < this.items_.length; i++) {
|
for (let i = 0; i < this.items_.length; i++) {
|
||||||
const s = this.items_[i].substr(0, this.innerWidth - 1);
|
const s = this.items_[i].substr(0, this.innerWidth - 1);
|
||||||
this.term.write(textStyle(s));
|
this.term.write(textStyle(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doSaveCursor) this.term.restoreCursor();
|
if (doSaveCursor) this.term.restoreCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = StatusBarWidget;
|
module.exports = StatusBarWidget;
|
||||||
|
@@ -1,10 +1,7 @@
|
|||||||
const fs = require('fs-extra');
|
|
||||||
const { wrap } = require('lib/string-utils.js');
|
const { wrap } = require('lib/string-utils.js');
|
||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
const { fileExtension, basename, dirname } = require('lib/path-utils.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const { _, setLocale, languageCode } = require('lib/locale.js');
|
|
||||||
|
|
||||||
const rootDir = dirname(dirname(__dirname));
|
|
||||||
const MAX_WIDTH = 78;
|
const MAX_WIDTH = 78;
|
||||||
const INDENT = ' ';
|
const INDENT = ' ';
|
||||||
|
|
||||||
@@ -23,7 +20,7 @@ function renderTwoColumnData(options, baseIndent, width) {
|
|||||||
output.push(r);
|
output.push(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
return output.join("\n");
|
return output.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderCommandHelp(cmd, width = null) {
|
function renderCommandHelp(cmd, width = null) {
|
||||||
@@ -44,7 +41,7 @@ function renderCommandHelp(cmd, width = null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cmd.name() === 'config') {
|
if (cmd.name() === 'config') {
|
||||||
const renderMetadata = (md) => {
|
const renderMetadata = md => {
|
||||||
let desc = [];
|
let desc = [];
|
||||||
|
|
||||||
if (md.label) {
|
if (md.label) {
|
||||||
@@ -67,13 +64,13 @@ function renderCommandHelp(cmd, width = 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) {
|
||||||
defaultString = (md.value === true ? 'true' : 'false');
|
defaultString = md.value === true ? 'true' : 'false';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultString !== null) desc.push(_('Default: %s', defaultString));
|
if (defaultString !== null) desc.push(_('Default: %s', defaultString));
|
||||||
|
|
||||||
return [md.key, desc.join("\n")];
|
return [md.key, desc.join('\n')];
|
||||||
};
|
};
|
||||||
|
|
||||||
output.push('');
|
output.push('');
|
||||||
@@ -83,7 +80,7 @@ function renderCommandHelp(cmd, width = null) {
|
|||||||
let keysValues = [];
|
let keysValues = [];
|
||||||
const keys = Setting.keys(true, 'cli');
|
const keys = Setting.keys(true, 'cli');
|
||||||
for (let i = 0; i < keys.length; i++) {
|
for (let i = 0; i < keys.length; i++) {
|
||||||
if (keysValues.length) keysValues.push(['','']);
|
if (keysValues.length) keysValues.push(['', '']);
|
||||||
const md = Setting.settingMetadata(keys[i]);
|
const md = Setting.settingMetadata(keys[i]);
|
||||||
if (!md.label) continue;
|
if (!md.label) continue;
|
||||||
keysValues.push(renderMetadata(md));
|
keysValues.push(renderMetadata(md));
|
||||||
@@ -92,7 +89,7 @@ function renderCommandHelp(cmd, width = null) {
|
|||||||
output.push(renderTwoColumnData(keysValues, baseIndent, width));
|
output.push(renderTwoColumnData(keysValues, baseIndent, width));
|
||||||
}
|
}
|
||||||
|
|
||||||
return output.join("\n");
|
return output.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOptionColWidth(options) {
|
function getOptionColWidth(options) {
|
||||||
|
@@ -53,25 +53,25 @@ shimInit();
|
|||||||
|
|
||||||
const application = app();
|
const application = app();
|
||||||
|
|
||||||
if (process.platform === "win32") {
|
if (process.platform === 'win32') {
|
||||||
var rl = require("readline").createInterface({
|
var rl = require('readline').createInterface({
|
||||||
input: process.stdin,
|
input: process.stdin,
|
||||||
output: process.stdout
|
output: process.stdout,
|
||||||
});
|
});
|
||||||
|
|
||||||
rl.on("SIGINT", function () {
|
rl.on('SIGINT', function() {
|
||||||
process.emit("SIGINT");
|
process.emit('SIGINT');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
process.stdout.on('error', function( err ) {
|
process.stdout.on('error', function(err) {
|
||||||
// https://stackoverflow.com/questions/12329816/error-write-epipe-when-piping-node-output-to-head#15884508
|
// https://stackoverflow.com/questions/12329816/error-write-epipe-when-piping-node-output-to-head#15884508
|
||||||
if (err.code == "EPIPE") {
|
if (err.code == 'EPIPE') {
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
application.start(process.argv).catch((error) => {
|
application.start(process.argv).catch(error => {
|
||||||
if (error.code == 'flagError') {
|
if (error.code == 'flagError') {
|
||||||
console.error(error.message);
|
console.error(error.message);
|
||||||
console.error(_('Type `joplin help` for usage information.'));
|
console.error(_('Type `joplin help` for usage information.'));
|
||||||
|
@@ -1,13 +1,11 @@
|
|||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
const { netUtils } = require('lib/net-utils.js');
|
const { netUtils } = require('lib/net-utils.js');
|
||||||
|
|
||||||
const http = require("http");
|
const http = require('http');
|
||||||
const urlParser = require("url");
|
const urlParser = require('url');
|
||||||
const FormData = require('form-data');
|
|
||||||
const enableServerDestroy = require('server-destroy');
|
const enableServerDestroy = require('server-destroy');
|
||||||
|
|
||||||
class OneDriveApiNodeUtils {
|
class OneDriveApiNodeUtils {
|
||||||
|
|
||||||
constructor(api) {
|
constructor(api) {
|
||||||
this.api_ = api;
|
this.api_ = api;
|
||||||
this.oauthServer_ = null;
|
this.oauthServer_ = null;
|
||||||
@@ -56,7 +54,7 @@ class OneDriveApiNodeUtils {
|
|||||||
const url = urlParser.parse(request.url, true);
|
const url = urlParser.parse(request.url, true);
|
||||||
|
|
||||||
if (url.pathname === '/auth') {
|
if (url.pathname === '/auth') {
|
||||||
response.writeHead(302, { 'Location': authCodeUrl });
|
response.writeHead(302, { Location: authCodeUrl });
|
||||||
response.end();
|
response.end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -64,10 +62,10 @@ class OneDriveApiNodeUtils {
|
|||||||
const query = url.query;
|
const query = url.query;
|
||||||
|
|
||||||
const writeResponse = (code, message) => {
|
const writeResponse = (code, message) => {
|
||||||
response.writeHead(code, {"Content-Type": "text/html"});
|
response.writeHead(code, { 'Content-Type': 'text/html' });
|
||||||
response.write(this.makePage(message));
|
response.write(this.makePage(message));
|
||||||
response.end();
|
response.end();
|
||||||
}
|
};
|
||||||
|
|
||||||
// After the response has been received, don't destroy the server right
|
// After the response has been received, don't destroy the server right
|
||||||
// away or the browser might display a connection reset error (even
|
// away or the browser might display a connection reset error (even
|
||||||
@@ -77,16 +75,19 @@ class OneDriveApiNodeUtils {
|
|||||||
this.oauthServer_.destroy();
|
this.oauthServer_.destroy();
|
||||||
this.oauthServer_ = null;
|
this.oauthServer_ = null;
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
};
|
||||||
|
|
||||||
if (!query.code) return writeResponse(400, '"code" query parameter is missing');
|
if (!query.code) return writeResponse(400, '"code" query parameter is missing');
|
||||||
|
|
||||||
this.api().execTokenRequest(query.code, 'http://localhost:' + port.toString()).then(() => {
|
this.api()
|
||||||
|
.execTokenRequest(query.code, 'http://localhost:' + port.toString())
|
||||||
|
.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('');
|
||||||
targetConsole.log(_('The application has been successfully authorised.'));
|
targetConsole.log(_('The application has been successfully authorised.'));
|
||||||
waitAndDestroy();
|
waitAndDestroy();
|
||||||
}).catch((error) => {
|
})
|
||||||
|
.catch(error => {
|
||||||
writeResponse(400, error.message);
|
writeResponse(400, error.message);
|
||||||
targetConsole.log('');
|
targetConsole.log('');
|
||||||
targetConsole.log(error.message);
|
targetConsole.log(error.message);
|
||||||
@@ -116,7 +117,6 @@ class OneDriveApiNodeUtils {
|
|||||||
targetConsole.log('http://127.0.0.1:' + port + '/auth');
|
targetConsole.log('http://127.0.0.1:' + port + '/auth');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { OneDriveApiNodeUtils };
|
module.exports = { OneDriveApiNodeUtils };
|
@@ -82,6 +82,7 @@
|
|||||||
"jasmine": "^2.6.0"
|
"jasmine": "^2.6.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "jasmine"
|
"test": "jasmine",
|
||||||
|
"postinstall": "cd .. && npm i"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
@@ -43,8 +45,8 @@ describe('EnexToMd', function() {
|
|||||||
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');
|
||||||
actualMd = actualMd.replace(/\r\n/g, '\n')
|
actualMd = actualMd.replace(/\r\n/g, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actualMd !== expectedMd) {
|
if (actualMd !== expectedMd) {
|
||||||
@@ -60,7 +62,7 @@ describe('EnexToMd', function() {
|
|||||||
expect(false).toBe(true);
|
expect(false).toBe(true);
|
||||||
// return;
|
// return;
|
||||||
} else {
|
} else {
|
||||||
expect(true).toBe(true)
|
expect(true).toBe(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
@@ -39,14 +41,14 @@ describe('HtmlToMd', function() {
|
|||||||
|
|
||||||
// if (htmlFilename !== 'mathjax_block.html') continue;
|
// if (htmlFilename !== 'mathjax_block.html') continue;
|
||||||
|
|
||||||
const htmlToMdOptions = {}
|
const htmlToMdOptions = {};
|
||||||
|
|
||||||
if (htmlFilename === 'anchor_local.html') {
|
if (htmlFilename === 'anchor_local.html') {
|
||||||
// Normally the list of anchor names in the document are retrieved from the HTML code
|
// Normally the list of anchor names in the document are retrieved from the HTML code
|
||||||
// This is straightforward when the document is still in DOM format, as with the clipper,
|
// This is straightforward when the document is still in DOM format, as with the clipper,
|
||||||
// but otherwise it would need to be somehow parsed out from the HTML. Here we just
|
// but otherwise it would need to be somehow parsed out from the HTML. Here we just
|
||||||
// hard code the anchors that we know are in the file.
|
// hard code the anchors that we know are in the file.
|
||||||
htmlToMdOptions.anchorNames = ['first', 'second']
|
htmlToMdOptions.anchorNames = ['first', 'second'];
|
||||||
}
|
}
|
||||||
|
|
||||||
const html = await shim.fsDriver().readFile(htmlPath);
|
const html = await shim.fsDriver().readFile(htmlPath);
|
||||||
@@ -55,8 +57,8 @@ describe('HtmlToMd', function() {
|
|||||||
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');
|
||||||
actualMd = actualMd.replace(/\r\n/g, '\n')
|
actualMd = actualMd.replace(/\r\n/g, '\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actualMd !== expectedMd) {
|
if (actualMd !== expectedMd) {
|
||||||
@@ -74,7 +76,7 @@ describe('HtmlToMd', function() {
|
|||||||
expect(false).toBe(true);
|
expect(false).toBe(true);
|
||||||
// return;
|
// return;
|
||||||
} else {
|
} else {
|
||||||
expect(true).toBe(true)
|
expect(true).toBe(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { asyncTest, fileContentEqual, setupDatabase, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
|
const { asyncTest, fileContentEqual, setupDatabase, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -116,7 +118,7 @@ describe('Encryption', function() {
|
|||||||
await service.loadMasterKey(masterKey, '123456', true);
|
await service.loadMasterKey(masterKey, '123456', true);
|
||||||
|
|
||||||
let cipherText = await service.encryptString('some secret');
|
let cipherText = await service.encryptString('some secret');
|
||||||
cipherText += "ABCDEFGHIJ";
|
cipherText += 'ABCDEFGHIJ';
|
||||||
|
|
||||||
let hasThrown = await checkThrowAsync(async () => await service.decryptString(cipherText));
|
let hasThrown = await checkThrowAsync(async () => await service.decryptString(cipherText));
|
||||||
|
|
||||||
@@ -147,8 +149,8 @@ describe('Encryption', function() {
|
|||||||
// Check that encrypted data is there
|
// Check that encrypted data is there
|
||||||
expect(!!deserialized.encryption_cipher_text).toBe(true);
|
expect(!!deserialized.encryption_cipher_text).toBe(true);
|
||||||
|
|
||||||
encryptedNote = await Note.save(deserialized);
|
const encryptedNote = await Note.save(deserialized);
|
||||||
decryptedNote = await Note.decrypt(encryptedNote);
|
const decryptedNote = await Note.decrypt(encryptedNote);
|
||||||
|
|
||||||
expect(decryptedNote.title).toBe(note.title);
|
expect(decryptedNote.title).toBe(note.title);
|
||||||
expect(decryptedNote.body).toBe(note.body);
|
expect(decryptedNote.body).toBe(note.body);
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -46,8 +48,8 @@ describe('htmlUtils', function() {
|
|||||||
return function(src) {
|
return function(src) {
|
||||||
i++;
|
i++;
|
||||||
return urls[i];
|
return urls[i];
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
for (let i = 0; i < testCases.length; i++) {
|
for (let i = 0; i < testCases.length; i++) {
|
||||||
const md = testCases[i][0];
|
const md = testCases[i][0];
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -38,10 +40,10 @@ describe('models_BaseItem', function() {
|
|||||||
// This is to handle the case where a property is removed from a BaseItem table - in that case files in
|
// This is to handle the case where a property is removed from a BaseItem table - in that case files in
|
||||||
// the sync target will still have the old property but we don't need it locally.
|
// the sync target will still have the old property but we don't need it locally.
|
||||||
it('should ignore properties that are present in sync file but not in database when serialising', asyncTest(async () => {
|
it('should ignore properties that are present in sync file but not in database when serialising', asyncTest(async () => {
|
||||||
let folder = await Folder.save({ title: "folder1" });
|
let folder = await Folder.save({ title: 'folder1' });
|
||||||
|
|
||||||
let serialized = await Folder.serialize(folder);
|
let serialized = await Folder.serialize(folder);
|
||||||
serialized += "\nignore_me: true"
|
serialized += '\nignore_me: true';
|
||||||
|
|
||||||
let unserialized = await Folder.unserialize(serialized);
|
let unserialized = await Folder.unserialize(serialized);
|
||||||
|
|
||||||
@@ -49,8 +51,8 @@ describe('models_BaseItem', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not modify title when unserializing', asyncTest(async () => {
|
it('should not modify title when unserializing', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "" });
|
let folder1 = await Folder.save({ title: '' });
|
||||||
let folder2 = await Folder.save({ title: "folder1" });
|
let folder2 = await Folder.save({ title: 'folder1' });
|
||||||
|
|
||||||
let serialized1 = await Folder.serialize(folder1);
|
let serialized1 = await Folder.serialize(folder1);
|
||||||
let unserialized1 = await Folder.unserialize(serialized1);
|
let unserialized1 = await Folder.unserialize(serialized1);
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -26,10 +28,10 @@ describe('models_Folder', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should tell if a notebook can be nested under another one', asyncTest(async () => {
|
it('should tell if a notebook can be nested under another one', asyncTest(async () => {
|
||||||
let f1 = await Folder.save({ title: "folder1" });
|
let f1 = await Folder.save({ title: 'folder1' });
|
||||||
let f2 = await Folder.save({ title: "folder2", parent_id: f1.id });
|
let f2 = await Folder.save({ title: 'folder2', parent_id: f1.id });
|
||||||
let f3 = await Folder.save({ title: "folder3", parent_id: f2.id });
|
let f3 = await Folder.save({ title: 'folder3', parent_id: f2.id });
|
||||||
let f4 = await Folder.save({ title: "folder4" });
|
let f4 = await Folder.save({ title: 'folder4' });
|
||||||
|
|
||||||
expect(await Folder.canNestUnder(f1.id, f2.id)).toBe(false);
|
expect(await Folder.canNestUnder(f1.id, f2.id)).toBe(false);
|
||||||
expect(await Folder.canNestUnder(f2.id, f2.id)).toBe(false);
|
expect(await Folder.canNestUnder(f2.id, f2.id)).toBe(false);
|
||||||
@@ -42,8 +44,8 @@ describe('models_Folder', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should recursively delete notes and sub-notebooks', asyncTest(async () => {
|
it('should recursively delete notes and sub-notebooks', asyncTest(async () => {
|
||||||
let f1 = await Folder.save({ title: "folder1" });
|
let f1 = await Folder.save({ title: 'folder1' });
|
||||||
let f2 = await Folder.save({ title: "folder2", parent_id: f1.id });
|
let f2 = await Folder.save({ title: 'folder2', parent_id: f1.id });
|
||||||
let n1 = await Note.save({ title: 'note1', parent_id: f2.id });
|
let n1 = await Note.save({ title: 'note1', parent_id: f2.id });
|
||||||
|
|
||||||
await Folder.delete(f1.id);
|
await Folder.delete(f1.id);
|
||||||
@@ -55,9 +57,9 @@ describe('models_Folder', function() {
|
|||||||
it('should sort by last modified, based on content', asyncTest(async () => {
|
it('should sort by last modified, based on content', asyncTest(async () => {
|
||||||
let folders;
|
let folders;
|
||||||
|
|
||||||
let f1 = await Folder.save({ title: "folder1" }); await sleep(0.1);
|
let f1 = await Folder.save({ title: 'folder1' }); await sleep(0.1);
|
||||||
let f2 = await Folder.save({ title: "folder2" }); await sleep(0.1);
|
let f2 = await Folder.save({ title: 'folder2' }); await sleep(0.1);
|
||||||
let f3 = await Folder.save({ title: "folder3" }); await sleep(0.1);
|
let f3 = await Folder.save({ title: 'folder3' }); await sleep(0.1);
|
||||||
let n1 = await Note.save({ title: 'note1', parent_id: f2.id });
|
let n1 = await Note.save({ title: 'note1', parent_id: f2.id });
|
||||||
|
|
||||||
folders = await Folder.orderByLastModified(await Folder.all(), 'desc');
|
folders = await Folder.orderByLastModified(await Folder.all(), 'desc');
|
||||||
@@ -89,9 +91,9 @@ describe('models_Folder', function() {
|
|||||||
it('should sort by last modified, based on content (sub-folders too)', asyncTest(async () => {
|
it('should sort by last modified, based on content (sub-folders too)', asyncTest(async () => {
|
||||||
let folders;
|
let folders;
|
||||||
|
|
||||||
let f1 = await Folder.save({ title: "folder1" }); await sleep(0.1);
|
let f1 = await Folder.save({ title: 'folder1' }); await sleep(0.1);
|
||||||
let f2 = await Folder.save({ title: "folder2" }); await sleep(0.1);
|
let f2 = await Folder.save({ title: 'folder2' }); await sleep(0.1);
|
||||||
let f3 = await Folder.save({ title: "folder3", parent_id: f1.id }); await sleep(0.1);
|
let f3 = await Folder.save({ title: 'folder3', parent_id: f1.id }); await sleep(0.1);
|
||||||
let n1 = await Note.save({ title: 'note1', parent_id: f3.id });
|
let n1 = await Note.save({ title: 'note1', parent_id: f3.id });
|
||||||
|
|
||||||
folders = await Folder.orderByLastModified(await Folder.all(), 'desc');
|
folders = await Folder.orderByLastModified(await Folder.all(), 'desc');
|
||||||
@@ -100,7 +102,7 @@ describe('models_Folder', function() {
|
|||||||
expect(folders[1].id).toBe(f3.id);
|
expect(folders[1].id).toBe(f3.id);
|
||||||
expect(folders[2].id).toBe(f2.id);
|
expect(folders[2].id).toBe(f2.id);
|
||||||
|
|
||||||
let n2 = await Note.save({ title: 'note2', parent_id: f2.id });
|
let n2 = await Note.save({ title: 'note2', parent_id: f2.id });
|
||||||
folders = await Folder.orderByLastModified(await Folder.all(), 'desc');
|
folders = await Folder.orderByLastModified(await Folder.all(), 'desc');
|
||||||
|
|
||||||
expect(folders[0].id).toBe(f2.id);
|
expect(folders[0].id).toBe(f2.id);
|
||||||
@@ -114,7 +116,7 @@ describe('models_Folder', function() {
|
|||||||
expect(folders[1].id).toBe(f3.id);
|
expect(folders[1].id).toBe(f3.id);
|
||||||
expect(folders[2].id).toBe(f2.id);
|
expect(folders[2].id).toBe(f2.id);
|
||||||
|
|
||||||
let f4 = await Folder.save({ title: "folder4", parent_id: f1.id }); await sleep(0.1);
|
let f4 = await Folder.save({ title: 'folder4', parent_id: f1.id }); await sleep(0.1);
|
||||||
let n3 = await Note.save({ title: 'note3', parent_id: f4.id });
|
let n3 = await Note.save({ title: 'note3', parent_id: f4.id });
|
||||||
|
|
||||||
folders = await Folder.orderByLastModified(await Folder.all(), 'desc');
|
folders = await Folder.orderByLastModified(await Folder.all(), 'desc');
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -25,7 +27,7 @@ describe('models_ItemChange', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should delete old changes that have been processed', asyncTest(async () => {
|
it('should delete old changes that have been processed', asyncTest(async () => {
|
||||||
const n1 = await Note.save({ title: "abcd efgh" }); // 3
|
const n1 = await Note.save({ title: 'abcd efgh' }); // 3
|
||||||
|
|
||||||
await ItemChange.waitForAllSaved();
|
await ItemChange.waitForAllSaved();
|
||||||
|
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -21,7 +23,7 @@ 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 });
|
||||||
|
|
||||||
@@ -67,7 +69,7 @@ describe('models_Note', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should change the type of notes', asyncTest(async () => {
|
it('should change the type of notes', 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 });
|
||||||
note1 = await Note.load(note1.id);
|
note1 = await Note.load(note1.id);
|
||||||
|
|
||||||
@@ -88,7 +90,7 @@ describe('models_Note', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should serialize and unserialize without modifying data', asyncTest(async () => {
|
it('should serialize and unserialize without modifying data', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1"});
|
let folder1 = await Folder.save({ title: 'folder1'});
|
||||||
const testCases = [
|
const testCases = [
|
||||||
[ {title: '', body:'Body and no title\nSecond line\nThird Line', parent_id: folder1.id},
|
[ {title: '', body:'Body and no title\nSecond line\nThird Line', parent_id: folder1.id},
|
||||||
'', 'Body and no title\nSecond line\nThird Line'],
|
'', 'Body and no title\nSecond line\nThird Line'],
|
||||||
@@ -96,7 +98,7 @@ describe('models_Note', function() {
|
|||||||
'Note title', 'Body and title'],
|
'Note title', 'Body and title'],
|
||||||
[ {title: 'Title and no body', body:'', parent_id: folder1.id},
|
[ {title: 'Title and no body', body:'', parent_id: folder1.id},
|
||||||
'Title and no body', ''],
|
'Title and no body', ''],
|
||||||
]
|
];
|
||||||
|
|
||||||
for (let i = 0; i < testCases.length; i++) {
|
for (let i = 0; i < testCases.length; i++) {
|
||||||
const t = testCases[i];
|
const t = testCases[i];
|
||||||
@@ -107,7 +109,7 @@ describe('models_Note', function() {
|
|||||||
|
|
||||||
let note1 = await Note.save(input);
|
let note1 = await Note.save(input);
|
||||||
let serialized = await Note.serialize(note1);
|
let serialized = await Note.serialize(note1);
|
||||||
let unserialized = await Note.unserialize( serialized);
|
let unserialized = await Note.unserialize(serialized);
|
||||||
|
|
||||||
expect(unserialized.title).toBe(input.title);
|
expect(unserialized.title).toBe(input.title);
|
||||||
expect(unserialized.body).toBe(input.body);
|
expect(unserialized.body).toBe(input.body);
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars, require-atomic-updates */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -25,7 +27,7 @@ describe('models_Resource', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should have a "done" fetch_status when created locally', asyncTest(async () => {
|
it('should have a "done" fetch_status when created locally', 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 });
|
||||||
await shim.attachFileToNote(note1, testImagePath);
|
await shim.attachFileToNote(note1, testImagePath);
|
||||||
let resource1 = (await Resource.all())[0];
|
let resource1 = (await Resource.all())[0];
|
||||||
@@ -34,7 +36,7 @@ describe('models_Resource', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should have a default local state', asyncTest(async () => {
|
it('should have a default local state', 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 });
|
||||||
await shim.attachFileToNote(note1, testImagePath);
|
await shim.attachFileToNote(note1, testImagePath);
|
||||||
let resource1 = (await Resource.all())[0];
|
let resource1 = (await Resource.all())[0];
|
||||||
@@ -45,7 +47,7 @@ describe('models_Resource', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should save and delete local state', asyncTest(async () => {
|
it('should save and delete local state', 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 });
|
||||||
await shim.attachFileToNote(note1, testImagePath);
|
await shim.attachFileToNote(note1, testImagePath);
|
||||||
let resource1 = (await Resource.all())[0];
|
let resource1 = (await Resource.all())[0];
|
||||||
@@ -61,7 +63,7 @@ describe('models_Resource', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should resize the resource if the image is below the required dimensions', asyncTest(async () => {
|
it('should resize the resource if the image is below the required dimensions', 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 });
|
||||||
const previousMax = Resource.IMAGE_MAX_DIMENSION;
|
const previousMax = Resource.IMAGE_MAX_DIMENSION;
|
||||||
Resource.IMAGE_MAX_DIMENSION = 5;
|
Resource.IMAGE_MAX_DIMENSION = 5;
|
||||||
@@ -76,7 +78,7 @@ describe('models_Resource', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not resize the resource if the image is below the required dimensions', asyncTest(async () => {
|
it('should not resize the resource if the image is below the required dimensions', 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 });
|
||||||
await shim.attachFileToNote(note1, testImagePath);
|
await shim.attachFileToNote(note1, testImagePath);
|
||||||
let resource1 = (await Resource.all())[0];
|
let resource1 = (await Resource.all())[0];
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -41,7 +43,7 @@ describe('models_Revision', function() {
|
|||||||
const newObject = {
|
const newObject = {
|
||||||
one: '123',
|
one: '123',
|
||||||
three: '999',
|
three: '999',
|
||||||
}
|
};
|
||||||
|
|
||||||
const patch = Revision.createObjectPatch(oldObject, newObject);
|
const patch = Revision.createObjectPatch(oldObject, newObject);
|
||||||
const merged = Revision.applyObjectPatch(oldObject, patch);
|
const merged = Revision.applyObjectPatch(oldObject, patch);
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -18,7 +20,7 @@ describe('models_Setting', function() {
|
|||||||
const settings = {
|
const settings = {
|
||||||
'sync.5.path': 'http://example.com',
|
'sync.5.path': 'http://example.com',
|
||||||
'sync.5.username': 'testing',
|
'sync.5.username': 'testing',
|
||||||
}
|
};
|
||||||
|
|
||||||
let output = Setting.subValues('sync.5', settings);
|
let output = Setting.subValues('sync.5', settings);
|
||||||
expect(output['path']).toBe('http://example.com');
|
expect(output['path']).toBe('http://example.com');
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -22,7 +24,7 @@ describe('models_Tag', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should add tags by title', asyncTest(async () => {
|
it('should add tags by title', 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 });
|
||||||
|
|
||||||
await Tag.setNoteTagsByTitles(note1.id, ['un', 'deux']);
|
await Tag.setNoteTagsByTitles(note1.id, ['un', 'deux']);
|
||||||
@@ -32,7 +34,7 @@ describe('models_Tag', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not allow renaming tag to existing tag names', asyncTest(async () => {
|
it('should not allow renaming tag to existing tag names', 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 });
|
||||||
|
|
||||||
await Tag.setNoteTagsByTitles(note1.id, ['un', 'deux']);
|
await Tag.setNoteTagsByTitles(note1.id, ['un', 'deux']);
|
||||||
@@ -44,7 +46,7 @@ describe('models_Tag', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not return tags without notes', asyncTest(async () => {
|
it('should not return tags without notes', 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 });
|
||||||
await Tag.setNoteTagsByTitles(note1.id, ['un']);
|
await Tag.setNoteTagsByTitles(note1.id, ['un']);
|
||||||
|
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { extractExecutablePath, quotePath, unquotePath, friendlySafeFilename, toFileProtocolPath} = require('lib/path-utils.js');
|
const { extractExecutablePath, quotePath, unquotePath, friendlySafeFilename, toFileProtocolPath} = require('lib/path-utils.js');
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -44,7 +46,7 @@ describe('services_InteropService', function() {
|
|||||||
|
|
||||||
it('should export and import folders', asyncTest(async () => {
|
it('should export and import folders', asyncTest(async () => {
|
||||||
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';
|
||||||
|
|
||||||
@@ -79,7 +81,7 @@ describe('services_InteropService', function() {
|
|||||||
|
|
||||||
it('should export and import folders and notes', asyncTest(async () => {
|
it('should export and import folders and notes', asyncTest(async () => {
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
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';
|
||||||
@@ -118,7 +120,7 @@ describe('services_InteropService', function() {
|
|||||||
|
|
||||||
it('should export and import notes to specific folder', asyncTest(async () => {
|
it('should export and import notes to specific folder', asyncTest(async () => {
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
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';
|
||||||
@@ -138,7 +140,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' });
|
||||||
tag1 = await Tag.load(tag1.id);
|
tag1 = await Tag.load(tag1.id);
|
||||||
@@ -178,7 +180,7 @@ 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);
|
||||||
@@ -214,7 +216,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 });
|
||||||
|
|
||||||
await service.export({ path: filePath, sourceNoteIds: [note1.id] });
|
await service.export({ path: filePath, sourceNoteIds: [note1.id] });
|
||||||
@@ -234,7 +236,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 });
|
||||||
|
|
||||||
await service.export({ path: filePath, sourceFolderIds: [folder1.id] });
|
await service.export({ path: filePath, sourceFolderIds: [folder1.id] });
|
||||||
@@ -255,10 +257,10 @@ describe('services_InteropService', function() {
|
|||||||
|
|
||||||
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 });
|
||||||
let folder4 = await Folder.save({ title: "folder4", parent_id: folder2.id });
|
let folder4 = await Folder.save({ title: 'folder4', parent_id: folder2.id });
|
||||||
let note1 = await Note.save({ title: 'ma note', parent_id: folder4.id });
|
let note1 = await Note.save({ title: 'ma note', parent_id: folder4.id });
|
||||||
|
|
||||||
await service.export({ path: filePath, sourceFolderIds: [folder1.id] });
|
await service.export({ path: filePath, sourceFolderIds: [folder1.id] });
|
||||||
@@ -289,7 +291,7 @@ 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 });
|
||||||
|
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { asyncTest, fileContentEqual, setupDatabase, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
|
const { asyncTest, fileContentEqual, setupDatabase, revisionService, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -46,7 +48,7 @@ describe('services_ResourceService', function() {
|
|||||||
it('should delete orphaned resources', asyncTest(async () => {
|
it('should delete orphaned resources', asyncTest(async () => {
|
||||||
const service = new ResourceService();
|
const service = new ResourceService();
|
||||||
|
|
||||||
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];
|
||||||
@@ -77,7 +79,7 @@ describe('services_ResourceService', function() {
|
|||||||
it('should not delete resource if still associated with at least one note', asyncTest(async () => {
|
it('should not delete resource if still associated with at least one note', asyncTest(async () => {
|
||||||
const service = new ResourceService();
|
const service = new ResourceService();
|
||||||
|
|
||||||
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');
|
||||||
@@ -111,7 +113,7 @@ describe('services_ResourceService', function() {
|
|||||||
it('should not delete resource if it is used in an IMG tag', asyncTest(async () => {
|
it('should not delete resource if it is used in an IMG tag', asyncTest(async () => {
|
||||||
const service = new ResourceService();
|
const service = new ResourceService();
|
||||||
|
|
||||||
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];
|
||||||
@@ -130,7 +132,7 @@ describe('services_ResourceService', function() {
|
|||||||
it('should not process twice the same change', asyncTest(async () => {
|
it('should not process twice the same change', asyncTest(async () => {
|
||||||
const service = new ResourceService();
|
const service = new ResourceService();
|
||||||
|
|
||||||
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];
|
||||||
@@ -167,7 +169,7 @@ describe('services_ResourceService', function() {
|
|||||||
const masterKey = await loadEncryptionMasterKey();
|
const masterKey = await loadEncryptionMasterKey();
|
||||||
await encryptionService().enableEncryption(masterKey, '123456');
|
await encryptionService().enableEncryption(masterKey, '123456');
|
||||||
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();
|
||||||
@@ -197,7 +199,7 @@ describe('services_ResourceService', function() {
|
|||||||
it('should double-check if the resource is still linked before deleting it', asyncTest(async () => {
|
it('should double-check if the resource is still linked before deleting it', asyncTest(async () => {
|
||||||
SearchEngine.instance().setDb(db()); // /!\ Note that we use the global search engine here, which we shouldn't but will work for now
|
SearchEngine.instance().setDb(db()); // /!\ Note that we use the global search engine here, which we shouldn't but will work for now
|
||||||
|
|
||||||
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();
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -22,7 +24,7 @@ describe('services_Revision', function() {
|
|||||||
beforeEach(async (done) => {
|
beforeEach(async (done) => {
|
||||||
await setupDatabaseAndSynchronizer(1);
|
await setupDatabaseAndSynchronizer(1);
|
||||||
await switchClient(1);
|
await switchClient(1);
|
||||||
Setting.setValue('revisionService.intervalBetweenRevisions', 0)
|
Setting.setValue('revisionService.intervalBetweenRevisions', 0);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -28,8 +30,8 @@ describe('services_SearchEngine', function() {
|
|||||||
it('should keep the content and FTS table in sync', asyncTest(async () => {
|
it('should keep the content and FTS table in sync', asyncTest(async () => {
|
||||||
let rows, n1, n2, n3;
|
let rows, n1, n2, n3;
|
||||||
|
|
||||||
n1 = await Note.save({ title: "a" });
|
n1 = await Note.save({ title: 'a' });
|
||||||
n2 = await Note.save({ title: "b" });
|
n2 = await Note.save({ title: 'b' });
|
||||||
await engine.syncTables();
|
await engine.syncTables();
|
||||||
rows = await engine.search('a');
|
rows = await engine.search('a');
|
||||||
expect(rows.length).toBe(1);
|
expect(rows.length).toBe(1);
|
||||||
@@ -61,8 +63,8 @@ describe('services_SearchEngine', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should, after initial indexing, save the last change ID', asyncTest(async () => {
|
it('should, after initial indexing, save the last change ID', asyncTest(async () => {
|
||||||
const n1 = await Note.save({ title: "abcd efgh" }); // 3
|
const n1 = await Note.save({ title: 'abcd efgh' }); // 3
|
||||||
const n2 = await Note.save({ title: "abcd aaaaa abcd abcd" }); // 1
|
const n2 = await Note.save({ title: 'abcd aaaaa abcd abcd' }); // 1
|
||||||
|
|
||||||
expect(Setting.value('searchEngine.initialIndexingDone')).toBe(false);
|
expect(Setting.value('searchEngine.initialIndexingDone')).toBe(false);
|
||||||
|
|
||||||
@@ -77,9 +79,9 @@ describe('services_SearchEngine', function() {
|
|||||||
|
|
||||||
|
|
||||||
it('should order search results by relevance (1)', asyncTest(async () => {
|
it('should order search results by relevance (1)', asyncTest(async () => {
|
||||||
const n1 = await Note.save({ title: "abcd efgh" }); // 3
|
const n1 = await Note.save({ title: 'abcd efgh' }); // 3
|
||||||
const n2 = await Note.save({ title: "abcd aaaaa abcd abcd" }); // 1
|
const n2 = await Note.save({ title: 'abcd aaaaa abcd abcd' }); // 1
|
||||||
const n3 = await Note.save({ title: "abcd aaaaa bbbb eeee abcd" }); // 2
|
const n3 = await Note.save({ title: 'abcd aaaaa bbbb eeee abcd' }); // 2
|
||||||
|
|
||||||
await engine.syncTables();
|
await engine.syncTables();
|
||||||
const rows = await engine.search('abcd');
|
const rows = await engine.search('abcd');
|
||||||
@@ -91,15 +93,15 @@ describe('services_SearchEngine', function() {
|
|||||||
|
|
||||||
it('should order search results by relevance (2)', asyncTest(async () => {
|
it('should order search results by relevance (2)', asyncTest(async () => {
|
||||||
// 1
|
// 1
|
||||||
const n1 = await Note.save({ title: "abcd efgh", body: "XX abcd XX efgh" });
|
const n1 = await Note.save({ title: 'abcd efgh', body: 'XX abcd XX efgh' });
|
||||||
// 4
|
// 4
|
||||||
const n2 = await Note.save({ title: "abcd aaaaa bbbb eeee efgh" });
|
const n2 = await Note.save({ title: 'abcd aaaaa bbbb eeee efgh' });
|
||||||
// 3
|
// 3
|
||||||
const n3 = await Note.save({ title: "abcd aaaaa efgh" });
|
const n3 = await Note.save({ title: 'abcd aaaaa efgh' });
|
||||||
// 2
|
// 2
|
||||||
const n4 = await Note.save({ title: "blablablabla blabla bla abcd X efgh" });
|
const n4 = await Note.save({ title: 'blablablabla blabla bla abcd X efgh' });
|
||||||
// 5
|
// 5
|
||||||
const n5 = await Note.save({ title: "occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh" });
|
const n5 = await Note.save({ title: 'occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh occurence many times but very abcd spread appart spread appart spread appart spread appart spread appart efgh' });
|
||||||
|
|
||||||
await engine.syncTables();
|
await engine.syncTables();
|
||||||
const rows = await engine.search('abcd efgh');
|
const rows = await engine.search('abcd efgh');
|
||||||
@@ -114,11 +116,11 @@ describe('services_SearchEngine', function() {
|
|||||||
it('should order search results by relevance (last updated first)', asyncTest(async () => {
|
it('should order search results by relevance (last updated first)', asyncTest(async () => {
|
||||||
let rows;
|
let rows;
|
||||||
|
|
||||||
const n1 = await Note.save({ title: "abcd" });
|
const n1 = await Note.save({ title: 'abcd' });
|
||||||
await sleep(0.1);
|
await sleep(0.1);
|
||||||
const n2 = await Note.save({ title: "abcd" });
|
const n2 = await Note.save({ title: 'abcd' });
|
||||||
await sleep(0.1);
|
await sleep(0.1);
|
||||||
const n3 = await Note.save({ title: "abcd" });
|
const n3 = await Note.save({ title: 'abcd' });
|
||||||
await sleep(0.1);
|
await sleep(0.1);
|
||||||
|
|
||||||
await engine.syncTables();
|
await engine.syncTables();
|
||||||
@@ -128,7 +130,7 @@ describe('services_SearchEngine', function() {
|
|||||||
expect(rows[1].id).toBe(n2.id);
|
expect(rows[1].id).toBe(n2.id);
|
||||||
expect(rows[2].id).toBe(n1.id);
|
expect(rows[2].id).toBe(n1.id);
|
||||||
|
|
||||||
await Note.save({ id: n1.id, title: "abcd" });
|
await Note.save({ id: n1.id, title: 'abcd' });
|
||||||
|
|
||||||
await engine.syncTables();
|
await engine.syncTables();
|
||||||
rows = await engine.search('abcd');
|
rows = await engine.search('abcd');
|
||||||
@@ -140,11 +142,11 @@ describe('services_SearchEngine', function() {
|
|||||||
it('should order search results by relevance (completed to-dos last)', asyncTest(async () => {
|
it('should order search results by relevance (completed to-dos last)', asyncTest(async () => {
|
||||||
let rows;
|
let rows;
|
||||||
|
|
||||||
const n1 = await Note.save({ title: "abcd", is_todo: 1 });
|
const n1 = await Note.save({ title: 'abcd', is_todo: 1 });
|
||||||
await sleep(0.1);
|
await sleep(0.1);
|
||||||
const n2 = await Note.save({ title: "abcd", is_todo: 1 });
|
const n2 = await Note.save({ title: 'abcd', is_todo: 1 });
|
||||||
await sleep(0.1);
|
await sleep(0.1);
|
||||||
const n3 = await Note.save({ title: "abcd", is_todo: 1 });
|
const n3 = await Note.save({ title: 'abcd', is_todo: 1 });
|
||||||
await sleep(0.1);
|
await sleep(0.1);
|
||||||
|
|
||||||
await engine.syncTables();
|
await engine.syncTables();
|
||||||
@@ -166,11 +168,11 @@ describe('services_SearchEngine', function() {
|
|||||||
it('should supports various query types', asyncTest(async () => {
|
it('should supports various query types', asyncTest(async () => {
|
||||||
let rows;
|
let rows;
|
||||||
|
|
||||||
const n1 = await Note.save({ title: "abcd efgh ijkl", body: "aaaa bbbb" });
|
const n1 = await Note.save({ title: 'abcd efgh ijkl', body: 'aaaa bbbb' });
|
||||||
const n2 = await Note.save({ title: "iiii efgh bbbb", body: "aaaa bbbb" });
|
const n2 = await Note.save({ title: 'iiii efgh bbbb', body: 'aaaa bbbb' });
|
||||||
const n3 = await Note.save({ title: "Агентство Рейтер" });
|
const n3 = await Note.save({ title: 'Агентство Рейтер' });
|
||||||
const n4 = await Note.save({ title: "Dog" });
|
const n4 = await Note.save({ title: 'Dog' });
|
||||||
const n5 = await Note.save({ title: "СООБЩИЛО" });
|
const n5 = await Note.save({ title: 'СООБЩИЛО' });
|
||||||
|
|
||||||
await engine.syncTables();
|
await engine.syncTables();
|
||||||
|
|
||||||
@@ -216,7 +218,7 @@ describe('services_SearchEngine', function() {
|
|||||||
|
|
||||||
it('should support queries with or without accents', asyncTest(async () => {
|
it('should support queries with or without accents', asyncTest(async () => {
|
||||||
let rows;
|
let rows;
|
||||||
const n1 = await Note.save({ title: "père noël" });
|
const n1 = await Note.save({ title: 'père noël' });
|
||||||
|
|
||||||
await engine.syncTables();
|
await engine.syncTables();
|
||||||
|
|
||||||
@@ -228,7 +230,7 @@ describe('services_SearchEngine', function() {
|
|||||||
|
|
||||||
it('should support queries with Chinese characters', asyncTest(async () => {
|
it('should support queries with Chinese characters', asyncTest(async () => {
|
||||||
let rows;
|
let rows;
|
||||||
const n1 = await Note.save({ title: "我是法国人" });
|
const n1 = await Note.save({ title: '我是法国人' });
|
||||||
|
|
||||||
await engine.syncTables();
|
await engine.syncTables();
|
||||||
|
|
||||||
@@ -238,7 +240,7 @@ describe('services_SearchEngine', function() {
|
|||||||
|
|
||||||
it('should support queries with Japanese characters', asyncTest(async () => {
|
it('should support queries with Japanese characters', asyncTest(async () => {
|
||||||
let rows;
|
let rows;
|
||||||
const n1 = await Note.save({ title: "私は日本語を話すことができません" });
|
const n1 = await Note.save({ title: '私は日本語を話すことができません' });
|
||||||
|
|
||||||
await engine.syncTables();
|
await engine.syncTables();
|
||||||
|
|
||||||
@@ -248,7 +250,7 @@ describe('services_SearchEngine', function() {
|
|||||||
|
|
||||||
it('should support queries with Korean characters', asyncTest(async () => {
|
it('should support queries with Korean characters', asyncTest(async () => {
|
||||||
let rows;
|
let rows;
|
||||||
const n1 = await Note.save({ title: "이것은 한국말이다" });
|
const n1 = await Note.save({ title: '이것은 한국말이다' });
|
||||||
|
|
||||||
await engine.syncTables();
|
await engine.syncTables();
|
||||||
|
|
||||||
@@ -258,7 +260,7 @@ describe('services_SearchEngine', function() {
|
|||||||
|
|
||||||
it('should support field restricted queries with Chinese characters', asyncTest(async () => {
|
it('should support field restricted queries with Chinese characters', asyncTest(async () => {
|
||||||
let rows;
|
let rows;
|
||||||
const n1 = await Note.save({ title: "你好", body: "我是法国人" });
|
const n1 = await Note.save({ title: '你好', body: '我是法国人' });
|
||||||
|
|
||||||
await engine.syncTables();
|
await engine.syncTables();
|
||||||
|
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -40,7 +42,7 @@ describe('services_rest_Api', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should get folders', async (done) => {
|
it('should get folders', 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');
|
const response = await api.route('GET', 'folders');
|
||||||
expect(response.length).toBe(1);
|
expect(response.length).toBe(1);
|
||||||
expect(response[0].title).toBe('mon carnet');
|
expect(response[0].title).toBe('mon carnet');
|
||||||
@@ -48,7 +50,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é',
|
||||||
}));
|
}));
|
||||||
@@ -60,7 +62,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);
|
||||||
@@ -84,7 +86,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);
|
||||||
|
|
||||||
@@ -95,7 +97,7 @@ 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);
|
||||||
|
|
||||||
@@ -116,8 +118,8 @@ describe('services_rest_Api', function() {
|
|||||||
|
|
||||||
it('should get notes', async (done) => {
|
it('should get notes', async (done) => {
|
||||||
let response = null;
|
let response = null;
|
||||||
const f1 = await Folder.save({ title: "mon carnet" });
|
const f1 = await Folder.save({ title: 'mon carnet' });
|
||||||
const f2 = await Folder.save({ title: "mon deuxième carnet" });
|
const f2 = await Folder.save({ title: 'mon deuxième carnet' });
|
||||||
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 n3 = await Note.save({ title: 'trois', parent_id: f2.id });
|
const n3 = await Note.save({ title: 'trois', parent_id: f2.id });
|
||||||
@@ -138,7 +140,7 @@ describe('services_rest_Api', function() {
|
|||||||
|
|
||||||
it('should create notes', async (done) => {
|
it('should create notes', async (done) => {
|
||||||
let response = null;
|
let response = null;
|
||||||
const f = await Folder.save({ title: "mon carnet" });
|
const f = await Folder.save({ title: 'mon carnet' });
|
||||||
|
|
||||||
response = await api.route('POST', 'notes', null, JSON.stringify({
|
response = await api.route('POST', 'notes', null, JSON.stringify({
|
||||||
title: 'testing',
|
title: 'testing',
|
||||||
@@ -159,7 +161,7 @@ describe('services_rest_Api', function() {
|
|||||||
|
|
||||||
it('should preserve user timestamps when creating notes', async (done) => {
|
it('should preserve user timestamps when creating notes', async (done) => {
|
||||||
let response = null;
|
let response = null;
|
||||||
const f = await Folder.save({ title: "mon carnet" });
|
const f = await Folder.save({ title: 'mon carnet' });
|
||||||
|
|
||||||
const updatedTime = Date.now() - 1000;
|
const updatedTime = Date.now() - 1000;
|
||||||
const createdTime = Date.now() - 10000;
|
const createdTime = Date.now() - 10000;
|
||||||
@@ -178,7 +180,7 @@ describe('services_rest_Api', function() {
|
|||||||
|
|
||||||
it('should create notes with supplied ID', async (done) => {
|
it('should create notes with supplied ID', async (done) => {
|
||||||
let response = null;
|
let response = null;
|
||||||
const f = await Folder.save({ title: "mon carnet" });
|
const f = await Folder.save({ title: 'mon carnet' });
|
||||||
|
|
||||||
response = await api.route('POST', 'notes', null, JSON.stringify({
|
response = await api.route('POST', 'notes', null, JSON.stringify({
|
||||||
id: '12345678123456781234567812345678',
|
id: '12345678123456781234567812345678',
|
||||||
@@ -192,19 +194,19 @@ describe('services_rest_Api', function() {
|
|||||||
|
|
||||||
it('should create todos', async (done) => {
|
it('should create todos', async (done) => {
|
||||||
let response = null;
|
let response = null;
|
||||||
const f = await Folder.save({ title: "stuff to do" });
|
const f = await Folder.save({ title: 'stuff to do' });
|
||||||
|
|
||||||
response = await api.route('POST', 'notes', null, JSON.stringify({
|
response = await api.route('POST', 'notes', null, JSON.stringify({
|
||||||
title: 'testing',
|
title: 'testing',
|
||||||
parent_id: f.id,
|
parent_id: f.id,
|
||||||
is_todo: 1
|
is_todo: 1,
|
||||||
}));
|
}));
|
||||||
expect(response.is_todo).toBe(1);
|
expect(response.is_todo).toBe(1);
|
||||||
|
|
||||||
response = await api.route('POST', 'notes', null, JSON.stringify({
|
response = await api.route('POST', 'notes', null, JSON.stringify({
|
||||||
title: 'testing 2',
|
title: 'testing 2',
|
||||||
parent_id: f.id,
|
parent_id: f.id,
|
||||||
is_todo: 0
|
is_todo: 0,
|
||||||
}));
|
}));
|
||||||
expect(response.is_todo).toBe(0);
|
expect(response.is_todo).toBe(0);
|
||||||
|
|
||||||
@@ -217,7 +219,7 @@ describe('services_rest_Api', function() {
|
|||||||
response = await api.route('POST', 'notes', null, JSON.stringify({
|
response = await api.route('POST', 'notes', null, JSON.stringify({
|
||||||
title: 'testing 4',
|
title: 'testing 4',
|
||||||
parent_id: f.id,
|
parent_id: f.id,
|
||||||
is_todo: '1'
|
is_todo: '1',
|
||||||
}));
|
}));
|
||||||
expect(response.is_todo).toBe(1);
|
expect(response.is_todo).toBe(1);
|
||||||
done();
|
done();
|
||||||
@@ -236,12 +238,12 @@ describe('services_rest_Api', function() {
|
|||||||
|
|
||||||
it('should create notes with images', async (done) => {
|
it('should create notes with images', async (done) => {
|
||||||
let response = null;
|
let response = null;
|
||||||
const f = await Folder.save({ title: "mon carnet" });
|
const f = await Folder.save({ title: 'mon carnet' });
|
||||||
|
|
||||||
response = await api.route('POST', 'notes', null, JSON.stringify({
|
response = await api.route('POST', 'notes', null, JSON.stringify({
|
||||||
title: 'testing image',
|
title: 'testing image',
|
||||||
parent_id: f.id,
|
parent_id: f.id,
|
||||||
image_data_url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANZJREFUeNoAyAA3/wFwtO3K6gUB/vz2+Prw9fj/+/r+/wBZKAAExOgF4/MC9ff+MRH6Ui4E+/0Bqc/zutj6AgT+/Pz7+vv7++nu82c4DlMqCvLs8goA/gL8/fz09fb59vXa6vzZ6vjT5fbn6voD/fwC8vX4UiT9Zi//APHyAP8ACgUBAPv5APz7BPj2+DIaC2o3E+3o6ywaC5fT6gD6/QD9/QEVf9kD+/dcLQgJA/7v8vqfwOf18wA1IAIEVycAyt//v9XvAPv7APz8LhoIAPz9Ri4OAgwARgx4W/6fVeEAAAAASUVORK5CYII="
|
image_data_url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANZJREFUeNoAyAA3/wFwtO3K6gUB/vz2+Prw9fj/+/r+/wBZKAAExOgF4/MC9ff+MRH6Ui4E+/0Bqc/zutj6AgT+/Pz7+vv7++nu82c4DlMqCvLs8goA/gL8/fz09fb59vXa6vzZ6vjT5fbn6voD/fwC8vX4UiT9Zi//APHyAP8ACgUBAPv5APz7BPj2+DIaC2o3E+3o6ywaC5fT6gD6/QD9/QEVf9kD+/dcLQgJA/7v8vqfwOf18wA1IAIEVycAyt//v9XvAPv7APz8LhoIAPz9Ri4OAgwARgx4W/6fVeEAAAAASUVORK5CYII=',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const resources = await Resource.all();
|
const resources = await Resource.all();
|
||||||
@@ -255,12 +257,12 @@ describe('services_rest_Api', function() {
|
|||||||
|
|
||||||
it('should delete resources', async (done) => {
|
it('should delete resources', async (done) => {
|
||||||
let response = null;
|
let response = null;
|
||||||
const f = await Folder.save({ title: "mon carnet" });
|
const f = await Folder.save({ title: 'mon carnet' });
|
||||||
|
|
||||||
response = await api.route('POST', 'notes', null, JSON.stringify({
|
response = await api.route('POST', 'notes', null, JSON.stringify({
|
||||||
title: 'testing image',
|
title: 'testing image',
|
||||||
parent_id: f.id,
|
parent_id: f.id,
|
||||||
image_data_url: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANZJREFUeNoAyAA3/wFwtO3K6gUB/vz2+Prw9fj/+/r+/wBZKAAExOgF4/MC9ff+MRH6Ui4E+/0Bqc/zutj6AgT+/Pz7+vv7++nu82c4DlMqCvLs8goA/gL8/fz09fb59vXa6vzZ6vjT5fbn6voD/fwC8vX4UiT9Zi//APHyAP8ACgUBAPv5APz7BPj2+DIaC2o3E+3o6ywaC5fT6gD6/QD9/QEVf9kD+/dcLQgJA/7v8vqfwOf18wA1IAIEVycAyt//v9XvAPv7APz8LhoIAPz9Ri4OAgwARgx4W/6fVeEAAAAASUVORK5CYII="
|
image_data_url: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAIAAABLbSncAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANZJREFUeNoAyAA3/wFwtO3K6gUB/vz2+Prw9fj/+/r+/wBZKAAExOgF4/MC9ff+MRH6Ui4E+/0Bqc/zutj6AgT+/Pz7+vv7++nu82c4DlMqCvLs8goA/gL8/fz09fb59vXa6vzZ6vjT5fbn6voD/fwC8vX4UiT9Zi//APHyAP8ACgUBAPv5APz7BPj2+DIaC2o3E+3o6ywaC5fT6gD6/QD9/QEVf9kD+/dcLQgJA/7v8vqfwOf18wA1IAIEVycAyt//v9XvAPv7APz8LhoIAPz9Ri4OAgwARgx4W/6fVeEAAAAASUVORK5CYII=',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const resource = (await Resource.all())[0];
|
const resource = (await Resource.all())[0];
|
||||||
@@ -277,7 +279,7 @@ describe('services_rest_Api', function() {
|
|||||||
|
|
||||||
it('should create notes from HTML', async (done) => {
|
it('should create notes from HTML', async (done) => {
|
||||||
let response = null;
|
let response = null;
|
||||||
const f = await Folder.save({ title: "mon carnet" });
|
const f = await Folder.save({ title: 'mon carnet' });
|
||||||
|
|
||||||
response = await api.route('POST', 'notes', null, JSON.stringify({
|
response = await api.route('POST', 'notes', null, JSON.stringify({
|
||||||
title: 'testing HTML',
|
title: 'testing HTML',
|
||||||
@@ -314,7 +316,7 @@ describe('services_rest_Api', function() {
|
|||||||
let hasThrown = await checkThrowAsync(async () => await api.route('GET', 'notes'));
|
let hasThrown = await checkThrowAsync(async () => await api.route('GET', 'notes'));
|
||||||
expect(hasThrown).toBe(true);
|
expect(hasThrown).toBe(true);
|
||||||
|
|
||||||
const response = await api.route('GET', 'notes', { token: 'mytoken' })
|
const response = await api.route('GET', 'notes', { token: 'mytoken' });
|
||||||
expect(response.length).toBe(0);
|
expect(response.length).toBe(0);
|
||||||
|
|
||||||
hasThrown = await checkThrowAsync(async () => await api.route('POST', 'notes', null, JSON.stringify({title:'testing'})));
|
hasThrown = await checkThrowAsync(async () => await api.route('POST', 'notes', null, JSON.stringify({title:'testing'})));
|
||||||
@@ -324,8 +326,8 @@ describe('services_rest_Api', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should add tags to notes', async (done) => {
|
it('should add tags to notes', async (done) => {
|
||||||
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,
|
||||||
@@ -338,8 +340,8 @@ describe('services_rest_Api', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should remove tags from notes', async (done) => {
|
it('should remove tags from notes', async (done) => {
|
||||||
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' });
|
||||||
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);
|
||||||
@@ -351,10 +353,10 @@ describe('services_rest_Api', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should list all tag notes', async (done) => {
|
it('should list all tag notes', async (done) => {
|
||||||
const tag = await Tag.save({ title: "mon étiquette" });
|
const tag = await Tag.save({ title: 'mon étiquette' });
|
||||||
const tag2 = await Tag.save({ title: "mon étiquette 2" });
|
const tag2 = await Tag.save({ title: 'mon étiquette 2' });
|
||||||
const note1 = await Note.save({ title: "ma note un" });
|
const note1 = await Note.save({ title: 'ma note un' });
|
||||||
const note2 = await Note.save({ title: "ma note deux" });
|
const note2 = await Note.save({ title: 'ma note deux' });
|
||||||
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);
|
||||||
|
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
const { time } = require('lib/time-utils.js');
|
||||||
@@ -99,8 +101,8 @@ describe('Synchronizer', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should create remote items', asyncTest(async () => {
|
it('should create remote items', asyncTest(async () => {
|
||||||
let folder = await Folder.save({ title: "folder1" });
|
let folder = await Folder.save({ title: 'folder1' });
|
||||||
await Note.save({ title: "un", parent_id: folder.id });
|
await Note.save({ title: 'un', parent_id: folder.id });
|
||||||
|
|
||||||
let all = await allNotesFolders();
|
let all = await allNotesFolders();
|
||||||
|
|
||||||
@@ -110,11 +112,11 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should update remote items', asyncTest(async () => {
|
it('should update remote items', asyncTest(async () => {
|
||||||
let folder = await Folder.save({ title: "folder1" });
|
let folder = await Folder.save({ title: 'folder1' });
|
||||||
let note = await Note.save({ title: "un", parent_id: folder.id });
|
let note = await Note.save({ title: 'un', parent_id: folder.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await Note.save({ title: "un UPDATE", id: note.id });
|
await Note.save({ title: 'un UPDATE', id: note.id });
|
||||||
|
|
||||||
let all = await allNotesFolders();
|
let all = await allNotesFolders();
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
@@ -123,8 +125,8 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should create local items', asyncTest(async () => {
|
it('should create local items', asyncTest(async () => {
|
||||||
let folder = await Folder.save({ title: "folder1" });
|
let folder = await Folder.save({ title: 'folder1' });
|
||||||
await Note.save({ title: "un", parent_id: folder.id });
|
await Note.save({ title: 'un', parent_id: folder.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -137,8 +139,8 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should update local items', asyncTest(async () => {
|
it('should update local items', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: "un", parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'un', parent_id: folder1.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -148,7 +150,7 @@ describe('Synchronizer', function() {
|
|||||||
await sleep(0.1);
|
await sleep(0.1);
|
||||||
|
|
||||||
let note2 = await Note.load(note1.id);
|
let note2 = await Note.load(note1.id);
|
||||||
note2.title = "Updated on client 2";
|
note2.title = 'Updated on client 2';
|
||||||
await Note.save(note2);
|
await Note.save(note2);
|
||||||
note2 = await Note.load(note2.id);
|
note2 = await Note.load(note2.id);
|
||||||
|
|
||||||
@@ -164,15 +166,15 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should resolve note conflicts', asyncTest(async () => {
|
it('should resolve note conflicts', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: "un", parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'un', parent_id: folder1.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
|
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
let note2 = await Note.load(note1.id);
|
let note2 = await Note.load(note1.id);
|
||||||
note2.title = "Updated on client 2";
|
note2.title = 'Updated on client 2';
|
||||||
await Note.save(note2);
|
await Note.save(note2);
|
||||||
note2 = await Note.load(note2.id);
|
note2 = await Note.load(note2.id);
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
@@ -180,7 +182,7 @@ describe('Synchronizer', function() {
|
|||||||
await switchClient(1);
|
await switchClient(1);
|
||||||
|
|
||||||
let note2conf = await Note.load(note1.id);
|
let note2conf = await Note.load(note1.id);
|
||||||
note2conf.title = "Updated on client 1";
|
note2conf.title = 'Updated on client 1';
|
||||||
await Note.save(note2conf);
|
await Note.save(note2conf);
|
||||||
note2conf = await Note.load(note1.id);
|
note2conf = await Note.load(note1.id);
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
@@ -205,8 +207,8 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should resolve folders conflicts', asyncTest(async () => {
|
it('should resolve folders conflicts', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: "un", parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'un', parent_id: folder1.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2); // ----------------------------------
|
await switchClient(2); // ----------------------------------
|
||||||
@@ -216,7 +218,7 @@ describe('Synchronizer', function() {
|
|||||||
await sleep(0.1);
|
await sleep(0.1);
|
||||||
|
|
||||||
let folder1_modRemote = await Folder.load(folder1.id);
|
let folder1_modRemote = await Folder.load(folder1.id);
|
||||||
folder1_modRemote.title = "folder1 UPDATE CLIENT 2";
|
folder1_modRemote.title = 'folder1 UPDATE CLIENT 2';
|
||||||
await Folder.save(folder1_modRemote);
|
await Folder.save(folder1_modRemote);
|
||||||
folder1_modRemote = await Folder.load(folder1_modRemote.id);
|
folder1_modRemote = await Folder.load(folder1_modRemote.id);
|
||||||
|
|
||||||
@@ -227,7 +229,7 @@ describe('Synchronizer', function() {
|
|||||||
await sleep(0.1);
|
await sleep(0.1);
|
||||||
|
|
||||||
let folder1_modLocal = await Folder.load(folder1.id);
|
let folder1_modLocal = await Folder.load(folder1.id);
|
||||||
folder1_modLocal.title = "folder1 UPDATE CLIENT 1";
|
folder1_modLocal.title = 'folder1 UPDATE CLIENT 1';
|
||||||
await Folder.save(folder1_modLocal);
|
await Folder.save(folder1_modLocal);
|
||||||
folder1_modLocal = await Folder.load(folder1.id);
|
folder1_modLocal = await Folder.load(folder1.id);
|
||||||
|
|
||||||
@@ -238,8 +240,8 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should delete remote notes', asyncTest(async () => {
|
it('should delete remote notes', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: "un", parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'un', parent_id: folder1.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -261,8 +263,8 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not created deleted_items entries for items deleted via sync', asyncTest(async () => {
|
it('should not created deleted_items entries for items deleted via sync', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: "un", parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'un', parent_id: folder1.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -283,9 +285,9 @@ describe('Synchronizer', function() {
|
|||||||
// property of the basicDelta() function is cleared properly at the end of a sync operation. If it is not cleared
|
// property of the basicDelta() function is cleared properly at the end of a sync operation. If it is not cleared
|
||||||
// it means items will no longer be deleted locally via sync.
|
// it means items will no longer be deleted locally via sync.
|
||||||
|
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: "un", parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'un', parent_id: folder1.id });
|
||||||
let note2 = await Note.save({ title: "deux", parent_id: folder1.id });
|
let note2 = await Note.save({ title: 'deux', parent_id: folder1.id });
|
||||||
let context1 = await synchronizer().start();
|
let context1 = await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -306,8 +308,8 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should delete remote folder', asyncTest(async () => {
|
it('should delete remote folder', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let folder2 = await Folder.save({ title: "folder2" });
|
let folder2 = await Folder.save({ title: 'folder2' });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -325,8 +327,8 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should delete local folder', asyncTest(async () => {
|
it('should delete local folder', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let folder2 = await Folder.save({ title: "folder2" });
|
let folder2 = await Folder.save({ title: 'folder2' });
|
||||||
let context1 = await synchronizer().start();
|
let context1 = await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -343,7 +345,7 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should resolve conflict if remote folder has been deleted, but note has been added to folder locally', asyncTest(async () => {
|
it('should resolve conflict if remote folder has been deleted, but note has been added to folder locally', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -354,7 +356,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
await switchClient(1);
|
await switchClient(1);
|
||||||
|
|
||||||
let note = await Note.save({ title: "note1", parent_id: folder1.id });
|
let note = await Note.save({ title: 'note1', parent_id: folder1.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
let items = await allNotesFolders();
|
let items = await allNotesFolders();
|
||||||
expect(items.length).toBe(1);
|
expect(items.length).toBe(1);
|
||||||
@@ -363,8 +365,8 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should resolve conflict if note has been deleted remotely and locally', asyncTest(async () => {
|
it('should resolve conflict if note has been deleted remotely and locally', asyncTest(async () => {
|
||||||
let folder = await Folder.save({ title: "folder" });
|
let folder = await Folder.save({ title: 'folder' });
|
||||||
let note = await Note.save({ title: "note", parent_id: folder.title });
|
let note = await Note.save({ title: 'note', parent_id: folder.title });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -389,8 +391,8 @@ describe('Synchronizer', function() {
|
|||||||
// If client1 and 2 have two folders, client 1 deletes item 1 and client
|
// If client1 and 2 have two folders, client 1 deletes item 1 and client
|
||||||
// 2 deletes item 2, they should both end up with no items after sync.
|
// 2 deletes item 2, they should both end up with no items after sync.
|
||||||
|
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let folder2 = await Folder.save({ title: "folder2" });
|
let folder2 = await Folder.save({ title: 'folder2' });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -424,8 +426,8 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle conflict when remote note is deleted then local note is modified', asyncTest(async () => {
|
it('should handle conflict when remote note is deleted then local note is modified', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: "un", parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'un', parent_id: folder1.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -456,9 +458,9 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should handle conflict when remote folder is deleted then local folder is renamed', asyncTest(async () => {
|
it('should handle conflict when remote folder is deleted then local folder is renamed', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let folder2 = await Folder.save({ title: "folder2" });
|
let folder2 = await Folder.save({ title: 'folder2' });
|
||||||
let note1 = await Note.save({ title: "un", parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'un', parent_id: folder1.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -486,11 +488,11 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should allow duplicate folder titles', asyncTest(async () => {
|
it('should allow duplicate folder titles', asyncTest(async () => {
|
||||||
let localF1 = await Folder.save({ title: "folder" });
|
let localF1 = await Folder.save({ title: 'folder' });
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
|
|
||||||
let remoteF2 = await Folder.save({ title: "folder" });
|
let remoteF2 = await Folder.save({ title: 'folder' });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(1);
|
await switchClient(1);
|
||||||
@@ -526,9 +528,9 @@ describe('Synchronizer', function() {
|
|||||||
masterKey = await loadEncryptionMasterKey();
|
masterKey = await loadEncryptionMasterKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
let f1 = await Folder.save({ title: "folder" });
|
let f1 = await Folder.save({ title: 'folder' });
|
||||||
let n1 = await Note.save({ title: "mynote" });
|
let n1 = await Note.save({ title: 'mynote' });
|
||||||
let n2 = await Note.save({ title: "mynote2" });
|
let n2 = await Note.save({ title: 'mynote2' });
|
||||||
let tag = await Tag.save({ title: 'mytag' });
|
let tag = await Tag.save({ title: 'mytag' });
|
||||||
let context1 = await synchronizer().start();
|
let context1 = await synchronizer().start();
|
||||||
|
|
||||||
@@ -577,22 +579,22 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not sync notes with conflicts', asyncTest(async () => {
|
it('should not sync notes with conflicts', asyncTest(async () => {
|
||||||
let f1 = await Folder.save({ title: "folder" });
|
let f1 = await Folder.save({ title: 'folder' });
|
||||||
let n1 = await Note.save({ title: "mynote", parent_id: f1.id, is_conflict: 1 });
|
let n1 = await Note.save({ title: 'mynote', parent_id: f1.id, is_conflict: 1 });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
|
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
let notes = await Note.all();
|
let notes = await Note.all();
|
||||||
let folders = await Folder.all()
|
let folders = await Folder.all();
|
||||||
expect(notes.length).toBe(0);
|
expect(notes.length).toBe(0);
|
||||||
expect(folders.length).toBe(1);
|
expect(folders.length).toBe(1);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should not try to delete on remote conflicted notes that have been deleted', asyncTest(async () => {
|
it('should not try to delete on remote conflicted notes that have been deleted', asyncTest(async () => {
|
||||||
let f1 = await Folder.save({ title: "folder" });
|
let f1 = await Folder.save({ title: 'folder' });
|
||||||
let n1 = await Note.save({ title: "mynote", parent_id: f1.id });
|
let n1 = await Note.save({ title: 'mynote', parent_id: f1.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -611,8 +613,8 @@ describe('Synchronizer', function() {
|
|||||||
await loadEncryptionMasterKey();
|
await loadEncryptionMasterKey();
|
||||||
}
|
}
|
||||||
|
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: "un", is_todo: 1, parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'un', is_todo: 1, parent_id: folder1.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -673,8 +675,8 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('items should be downloaded again when user cancels in the middle of delta operation', asyncTest(async () => {
|
it('items should be downloaded again when user cancels in the middle of delta operation', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: "un", is_todo: 1, parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'un', is_todo: 1, parent_id: folder1.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -691,13 +693,13 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should skip items that cannot be synced', asyncTest(async () => {
|
it('should skip items that cannot be synced', asyncTest(async () => {
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: "un", is_todo: 1, parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'un', is_todo: 1, parent_id: folder1.id });
|
||||||
const noteId = note1.id;
|
const noteId = note1.id;
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
let disabledItems = await BaseItem.syncDisabledItems(syncTargetId());
|
let disabledItems = await BaseItem.syncDisabledItems(syncTargetId());
|
||||||
expect(disabledItems.length).toBe(0);
|
expect(disabledItems.length).toBe(0);
|
||||||
await Note.save({ id: noteId, title: "un mod", });
|
await Note.save({ id: noteId, title: 'un mod' });
|
||||||
synchronizer().testingHooks_ = ['notesRejectedByTarget'];
|
synchronizer().testingHooks_ = ['notesRejectedByTarget'];
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
synchronizer().testingHooks_ = [];
|
synchronizer().testingHooks_ = [];
|
||||||
@@ -719,8 +721,8 @@ describe('Synchronizer', function() {
|
|||||||
it('notes and folders should get encrypted when encryption is enabled', asyncTest(async () => {
|
it('notes and folders should get encrypted when encryption is enabled', asyncTest(async () => {
|
||||||
Setting.setValue('encryption.enabled', true);
|
Setting.setValue('encryption.enabled', true);
|
||||||
const masterKey = await loadEncryptionMasterKey();
|
const masterKey = await loadEncryptionMasterKey();
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
let note1 = await Note.save({ title: "un", body: 'to be encrypted', parent_id: folder1.id });
|
let note1 = await Note.save({ title: 'un', body: 'to be encrypted', parent_id: folder1.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
// After synchronisation, remote items should be encrypted but local ones remain plain text
|
// After synchronisation, remote items should be encrypted but local ones remain plain text
|
||||||
note1 = await Note.load(note1.id);
|
note1 = await Note.load(note1.id);
|
||||||
@@ -762,7 +764,7 @@ describe('Synchronizer', function() {
|
|||||||
// Enable encryption on client 1 and sync an item
|
// Enable encryption on client 1 and sync an item
|
||||||
Setting.setValue('encryption.enabled', true);
|
Setting.setValue('encryption.enabled', true);
|
||||||
await loadEncryptionMasterKey();
|
await loadEncryptionMasterKey();
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -802,7 +804,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
// Decrypt all the data. Now change the title and sync again - this time the changes should be transmitted
|
// Decrypt all the data. Now change the title and sync again - this time the changes should be transmitted
|
||||||
await decryptionWorker().start();
|
await decryptionWorker().start();
|
||||||
folder1_2 = await Folder.save({ id: folder1.id, title: "change test" });
|
await Folder.save({ id: folder1.id, title: 'change test' });
|
||||||
|
|
||||||
// If we sync now, this time client 1 should get the changes we did earlier
|
// If we sync now, this time client 1 should get the changes we did earlier
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
@@ -818,11 +820,11 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
it('should encrypt existing notes too when enabling E2EE', asyncTest(async () => {
|
it('should encrypt existing notes too when enabling E2EE', asyncTest(async () => {
|
||||||
// First create a folder, without encryption enabled, and sync it
|
// First create a folder, without encryption enabled, and sync it
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
let files = await fileApi().list()
|
let files = await fileApi().list();
|
||||||
let content = await fileApi().get(files.items[0].path);
|
let content = await fileApi().get(files.items[0].path);
|
||||||
expect(content.indexOf('folder1') >= 0).toBe(true)
|
expect(content.indexOf('folder1') >= 0).toBe(true);
|
||||||
|
|
||||||
// Then enable encryption and sync again
|
// Then enable encryption and sync again
|
||||||
let masterKey = await encryptionService().generateMasterKey('123456');
|
let masterKey = await encryptionService().generateMasterKey('123456');
|
||||||
@@ -833,7 +835,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
// Even though the folder has not been changed it should have been synced again so that
|
// Even though the folder has not been changed it should have been synced again so that
|
||||||
// an encrypted version of it replaces the decrypted version.
|
// an encrypted version of it replaces the decrypted version.
|
||||||
files = await fileApi().list()
|
files = await fileApi().list();
|
||||||
expect(files.items.length).toBe(2);
|
expect(files.items.length).toBe(2);
|
||||||
// By checking that the folder title is not present, we can confirm that the item has indeed been encrypted
|
// By checking that the folder title is not present, we can confirm that the item has indeed been encrypted
|
||||||
// One of the two items is the master key
|
// One of the two items is the master key
|
||||||
@@ -846,7 +848,7 @@ describe('Synchronizer', function() {
|
|||||||
it('should sync resources', asyncTest(async () => {
|
it('should sync resources', asyncTest(async () => {
|
||||||
while (insideBeforeEach) await time.msleep(500);
|
while (insideBeforeEach) await time.msleep(500);
|
||||||
|
|
||||||
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];
|
||||||
@@ -864,7 +866,7 @@ describe('Synchronizer', function() {
|
|||||||
expect(resource1_2.id).toBe(resource1.id);
|
expect(resource1_2.id).toBe(resource1.id);
|
||||||
expect(ls.fetch_status).toBe(Resource.FETCH_STATUS_IDLE);
|
expect(ls.fetch_status).toBe(Resource.FETCH_STATUS_IDLE);
|
||||||
|
|
||||||
const fetcher = new ResourceFetcher(() => { return synchronizer().api() });
|
const fetcher = new ResourceFetcher(() => { return synchronizer().api(); });
|
||||||
fetcher.queueDownload_(resource1_2.id);
|
fetcher.queueDownload_(resource1_2.id);
|
||||||
await fetcher.waitForAllFinished();
|
await fetcher.waitForAllFinished();
|
||||||
|
|
||||||
@@ -879,7 +881,7 @@ describe('Synchronizer', function() {
|
|||||||
it('should handle resource download errors', asyncTest(async () => {
|
it('should handle resource download errors', asyncTest(async () => {
|
||||||
while (insideBeforeEach) await time.msleep(500);
|
while (insideBeforeEach) await time.msleep(500);
|
||||||
|
|
||||||
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];
|
||||||
@@ -892,8 +894,8 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
const fetcher = new ResourceFetcher(() => { return {
|
const fetcher = new ResourceFetcher(() => { return {
|
||||||
// Simulate a failed download
|
// Simulate a failed download
|
||||||
get: () => { return new Promise((resolve, reject) => { reject(new Error('did not work')) }); }
|
get: () => { return new Promise((resolve, reject) => { reject(new Error('did not work')); }); },
|
||||||
} });
|
}; });
|
||||||
fetcher.queueDownload_(resource1.id);
|
fetcher.queueDownload_(resource1.id);
|
||||||
await fetcher.waitForAllFinished();
|
await fetcher.waitForAllFinished();
|
||||||
|
|
||||||
@@ -906,7 +908,7 @@ describe('Synchronizer', function() {
|
|||||||
it('should set the resource file size if it is missing', asyncTest(async () => {
|
it('should set the resource file size if it is missing', asyncTest(async () => {
|
||||||
while (insideBeforeEach) await time.msleep(500);
|
while (insideBeforeEach) await time.msleep(500);
|
||||||
|
|
||||||
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();
|
||||||
@@ -919,7 +921,7 @@ describe('Synchronizer', function() {
|
|||||||
r1 = await Resource.load(r1.id);
|
r1 = await Resource.load(r1.id);
|
||||||
expect(r1.size).toBe(-1);
|
expect(r1.size).toBe(-1);
|
||||||
|
|
||||||
const fetcher = new ResourceFetcher(() => { return synchronizer().api() });
|
const fetcher = new ResourceFetcher(() => { return synchronizer().api(); });
|
||||||
fetcher.queueDownload_(r1.id);
|
fetcher.queueDownload_(r1.id);
|
||||||
await fetcher.waitForAllFinished();
|
await fetcher.waitForAllFinished();
|
||||||
r1 = await Resource.load(r1.id);
|
r1 = await Resource.load(r1.id);
|
||||||
@@ -929,7 +931,7 @@ describe('Synchronizer', function() {
|
|||||||
it('should delete resources', asyncTest(async () => {
|
it('should delete resources', asyncTest(async () => {
|
||||||
while (insideBeforeEach) await time.msleep(500);
|
while (insideBeforeEach) await time.msleep(500);
|
||||||
|
|
||||||
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];
|
||||||
@@ -963,7 +965,7 @@ describe('Synchronizer', function() {
|
|||||||
Setting.setValue('encryption.enabled', true);
|
Setting.setValue('encryption.enabled', true);
|
||||||
const masterKey = await loadEncryptionMasterKey();
|
const masterKey = await loadEncryptionMasterKey();
|
||||||
|
|
||||||
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];
|
||||||
@@ -976,7 +978,7 @@ describe('Synchronizer', function() {
|
|||||||
Setting.setObjectKey('encryption.passwordCache', masterKey.id, '123456');
|
Setting.setObjectKey('encryption.passwordCache', masterKey.id, '123456');
|
||||||
await encryptionService().loadMasterKeysFromSettings();
|
await encryptionService().loadMasterKeysFromSettings();
|
||||||
|
|
||||||
const fetcher = new ResourceFetcher(() => { return synchronizer().api() });
|
const fetcher = new ResourceFetcher(() => { return synchronizer().api(); });
|
||||||
fetcher.queueDownload_(resource1.id);
|
fetcher.queueDownload_(resource1.id);
|
||||||
await fetcher.waitForAllFinished();
|
await fetcher.waitForAllFinished();
|
||||||
|
|
||||||
@@ -991,7 +993,7 @@ describe('Synchronizer', function() {
|
|||||||
Setting.setValue('encryption.enabled', true);
|
Setting.setValue('encryption.enabled', true);
|
||||||
const masterKey = await loadEncryptionMasterKey();
|
const masterKey = await loadEncryptionMasterKey();
|
||||||
|
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
let allEncrypted = await allSyncTargetItemsEncrypted();
|
let allEncrypted = await allSyncTargetItemsEncrypted();
|
||||||
@@ -1012,7 +1014,7 @@ describe('Synchronizer', function() {
|
|||||||
Setting.setValue('encryption.enabled', true);
|
Setting.setValue('encryption.enabled', true);
|
||||||
const masterKey = await loadEncryptionMasterKey();
|
const masterKey = await loadEncryptionMasterKey();
|
||||||
|
|
||||||
let folder1 = await Folder.save({ title: "folder1" });
|
let folder1 = await Folder.save({ title: 'folder1' });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
@@ -1032,12 +1034,12 @@ describe('Synchronizer', function() {
|
|||||||
await decryptionWorker().start();
|
await decryptionWorker().start();
|
||||||
|
|
||||||
// Try to disable encryption again
|
// Try to disable encryption again
|
||||||
hasThrown = await checkThrowAsync(async () => await encryptionService().disableEncryption());
|
const hasThrown = await checkThrowAsync(async () => await encryptionService().disableEncryption());
|
||||||
expect(hasThrown).toBe(false);
|
expect(hasThrown).toBe(false);
|
||||||
|
|
||||||
// If we sync now the target should receive the decrypted items
|
// If we sync now the target should receive the decrypted items
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
allEncrypted = await allSyncTargetItemsEncrypted();
|
const allEncrypted = await allSyncTargetItemsEncrypted();
|
||||||
expect(allEncrypted).toBe(false);
|
expect(allEncrypted).toBe(false);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -1045,7 +1047,7 @@ describe('Synchronizer', function() {
|
|||||||
Setting.setValue('encryption.enabled', true);
|
Setting.setValue('encryption.enabled', true);
|
||||||
const masterKey = await loadEncryptionMasterKey();
|
const masterKey = await loadEncryptionMasterKey();
|
||||||
|
|
||||||
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];
|
||||||
@@ -1059,7 +1061,7 @@ describe('Synchronizer', function() {
|
|||||||
Setting.setObjectKey('encryption.passwordCache', masterKey.id, '123456');
|
Setting.setObjectKey('encryption.passwordCache', masterKey.id, '123456');
|
||||||
await encryptionService().loadMasterKeysFromSettings();
|
await encryptionService().loadMasterKeysFromSettings();
|
||||||
|
|
||||||
const fetcher = new ResourceFetcher(() => { return synchronizer().api() });
|
const fetcher = new ResourceFetcher(() => { return synchronizer().api(); });
|
||||||
fetcher.queueDownload_(resource1.id);
|
fetcher.queueDownload_(resource1.id);
|
||||||
await fetcher.waitForAllFinished();
|
await fetcher.waitForAllFinished();
|
||||||
await decryptionWorker().start();
|
await decryptionWorker().start();
|
||||||
@@ -1071,10 +1073,9 @@ describe('Synchronizer', function() {
|
|||||||
it('should encrypt remote resources after encryption has been enabled', asyncTest(async () => {
|
it('should encrypt remote resources after encryption has been enabled', asyncTest(async () => {
|
||||||
while (insideBeforeEach) await time.msleep(100);
|
while (insideBeforeEach) await time.msleep(100);
|
||||||
|
|
||||||
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];
|
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
expect(await allSyncTargetItemsEncrypted()).toBe(false);
|
expect(await allSyncTargetItemsEncrypted()).toBe(false);
|
||||||
@@ -1091,7 +1092,7 @@ describe('Synchronizer', function() {
|
|||||||
it('should upload encrypted resource, but it should not mark the blob as encrypted locally', asyncTest(async () => {
|
it('should upload encrypted resource, but it should not mark the blob as encrypted locally', asyncTest(async () => {
|
||||||
while (insideBeforeEach) await time.msleep(100);
|
while (insideBeforeEach) await time.msleep(100);
|
||||||
|
|
||||||
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();
|
||||||
@@ -1104,8 +1105,8 @@ describe('Synchronizer', function() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
it('should create remote items with UTF-8 content', asyncTest(async () => {
|
it('should create remote items with UTF-8 content', asyncTest(async () => {
|
||||||
let folder = await Folder.save({ title: "Fahrräder" });
|
let folder = await Folder.save({ title: 'Fahrräder' });
|
||||||
await Note.save({ title: "Fahrräder", body: "Fahrräder", parent_id: folder.id });
|
await Note.save({ title: 'Fahrräder', body: 'Fahrräder', parent_id: folder.id });
|
||||||
let all = await allNotesFolders();
|
let all = await allNotesFolders();
|
||||||
|
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
@@ -1113,21 +1114,21 @@ describe('Synchronizer', function() {
|
|||||||
await localNotesFoldersSameAsRemote(all, expect);
|
await localNotesFoldersSameAsRemote(all, expect);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("should update remote items but not pull remote changes", asyncTest(async () => {
|
it('should update remote items but not pull remote changes', asyncTest(async () => {
|
||||||
let folder = await Folder.save({ title: "folder1" });
|
let folder = await Folder.save({ title: 'folder1' });
|
||||||
let note = await Note.save({ title: "un", parent_id: folder.id });
|
let note = await Note.save({ title: 'un', parent_id: folder.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(2);
|
await switchClient(2);
|
||||||
|
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
await Note.save({ title: "deux", parent_id: folder.id });
|
await Note.save({ title: 'deux', parent_id: folder.id });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
await switchClient(1);
|
await switchClient(1);
|
||||||
|
|
||||||
await Note.save({ title: "un UPDATE", id: note.id });
|
await Note.save({ title: 'un UPDATE', id: note.id });
|
||||||
await synchronizer().start({ syncSteps: ["update_remote"] });
|
await synchronizer().start({ syncSteps: ['update_remote'] });
|
||||||
let all = await allNotesFolders();
|
let all = await allNotesFolders();
|
||||||
expect(all.length).toBe(2);
|
expect(all.length).toBe(2);
|
||||||
|
|
||||||
@@ -1135,10 +1136,10 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
let note2 = await Note.load(note.id);
|
let note2 = await Note.load(note.id);
|
||||||
expect(note2.title).toBe("un UPDATE");
|
expect(note2.title).toBe('un UPDATE');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("should create a new Welcome notebook on each client", asyncTest(async () => {
|
it('should create a new Welcome notebook on each client', asyncTest(async () => {
|
||||||
// Create the Welcome items on two separate clients
|
// Create the Welcome items on two separate clients
|
||||||
|
|
||||||
await WelcomeUtils.createWelcomeItems();
|
await WelcomeUtils.createWelcomeItems();
|
||||||
@@ -1175,7 +1176,7 @@ describe('Synchronizer', function() {
|
|||||||
expect(f1_1.title).toBe('Welcome MOD');
|
expect(f1_1.title).toBe('Welcome MOD');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("should not save revisions when updating a note via sync", asyncTest(async () => {
|
it('should not save revisions when updating a note via sync', asyncTest(async () => {
|
||||||
// When a note is updated, a revision of the original is created.
|
// When a note is updated, a revision of the original is created.
|
||||||
// Here, on client 1, the note is updated for the first time, however since it is
|
// Here, on client 1, the note is updated for the first time, however since it is
|
||||||
// via sync, we don't create a revision - that revision has already been created on client
|
// via sync, we don't create a revision - that revision has already been created on client
|
||||||
@@ -1201,7 +1202,7 @@ describe('Synchronizer', function() {
|
|||||||
expect(allRevs2[0].id).toBe(allRevs1[0].id);
|
expect(allRevs2[0].id).toBe(allRevs1[0].id);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("should not save revisions when deleting a note via sync", asyncTest(async () => {
|
it('should not save revisions when deleting a note via sync', asyncTest(async () => {
|
||||||
const n1 = await Note.save({ title: 'testing' });
|
const n1 = await Note.save({ title: 'testing' });
|
||||||
await synchronizer().start();
|
await synchronizer().start();
|
||||||
|
|
||||||
@@ -1228,7 +1229,7 @@ describe('Synchronizer', function() {
|
|||||||
expect(notes.length).toBe(0);
|
expect(notes.length).toBe(0);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("should not save revisions when an item_change has been generated as a result of a sync", asyncTest(async () => {
|
it('should not save revisions when an item_change has been generated as a result of a sync', asyncTest(async () => {
|
||||||
// When a note is modified an item_change object is going to be created. This
|
// When a note is modified an item_change object is going to be created. This
|
||||||
// is used for example to tell the search engine, when note should be indexed. It is
|
// is used for example to tell the search engine, when note should be indexed. It is
|
||||||
// also used by the revision service to tell what note should get a new revision.
|
// also used by the revision service to tell what note should get a new revision.
|
||||||
@@ -1266,7 +1267,7 @@ describe('Synchronizer', function() {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("should handle case when new rev is created on client, then older rev arrives later via sync", asyncTest(async () => {
|
it('should handle case when new rev is created on client, then older rev arrives later via sync', asyncTest(async () => {
|
||||||
// - C1 creates note 1
|
// - C1 creates note 1
|
||||||
// - C1 modifies note 1 - REV1 created
|
// - C1 modifies note 1 - REV1 created
|
||||||
// - C1 sync
|
// - C1 sync
|
||||||
@@ -1304,7 +1305,7 @@ describe('Synchronizer', function() {
|
|||||||
expect((await revisionService().revisionNote(revisions, 1)).title).toBe('note REV2');
|
expect((await revisionService().revisionNote(revisions, 1)).title).toBe('note REV2');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
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();
|
||||||
@@ -1322,7 +1323,7 @@ describe('Synchronizer', function() {
|
|||||||
expect(syncItems[1].sync_disabled).toBe(1);
|
expect(syncItems[1].sync_disabled).toBe(1);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it("should not upload a resource if it has not been fetched yet", asyncTest(async () => {
|
it('should not upload a resource if it has not been fetched yet', asyncTest(async () => {
|
||||||
// In some rare cases, the synchronizer might try to upload a resource even though it
|
// In some rare cases, the synchronizer might try to upload a resource even though it
|
||||||
// doesn't have the resource file. It can happen in this situation:
|
// doesn't have the resource file. It can happen in this situation:
|
||||||
// - C1 create resource
|
// - C1 create resource
|
||||||
@@ -1370,7 +1371,7 @@ describe('Synchronizer', function() {
|
|||||||
expect(!!resource.encryption_applied).toBe(false);
|
expect(!!resource.encryption_applied).toBe(false);
|
||||||
expect(!!resource.encryption_blob_encrypted).toBe(true);
|
expect(!!resource.encryption_blob_encrypted).toBe(true);
|
||||||
|
|
||||||
const resourceFetcher = new ResourceFetcher(() => { return synchronizer().api() });
|
const resourceFetcher = new ResourceFetcher(() => { return synchronizer().api(); });
|
||||||
await resourceFetcher.start();
|
await resourceFetcher.start();
|
||||||
await resourceFetcher.waitForAllFinished();
|
await resourceFetcher.waitForAllFinished();
|
||||||
|
|
||||||
@@ -1400,7 +1401,7 @@ describe('Synchronizer', function() {
|
|||||||
|
|
||||||
const dateInPast = revisionService().oldNoteCutOffDate_() - 1000;
|
const dateInPast = revisionService().oldNoteCutOffDate_() - 1000;
|
||||||
|
|
||||||
const note1 = await Note.save({ title: 'ma note', updated_time: dateInPast, created_time: dateInPast }, { autoTimestamp: false });
|
await Note.save({ title: 'ma note', updated_time: dateInPast, created_time: dateInPast }, { autoTimestamp: false });
|
||||||
const masterKey = await loadEncryptionMasterKey();
|
const masterKey = await loadEncryptionMasterKey();
|
||||||
await encryptionService().enableEncryption(masterKey, '123456');
|
await encryptionService().enableEncryption(masterKey, '123456');
|
||||||
await encryptionService().loadMasterKeysFromSettings();
|
await encryptionService().loadMasterKeysFromSettings();
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable require-atomic-updates */
|
||||||
|
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const { JoplinDatabase } = require('lib/joplin-database.js');
|
const { JoplinDatabase } = require('lib/joplin-database.js');
|
||||||
const { DatabaseDriverNode } = require('lib/database-driver-node.js');
|
const { DatabaseDriverNode } = require('lib/database-driver-node.js');
|
||||||
@@ -13,7 +15,6 @@ const { Logger } = require('lib/logger.js');
|
|||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
const MasterKey = require('lib/models/MasterKey');
|
const MasterKey = require('lib/models/MasterKey');
|
||||||
const BaseItem = require('lib/models/BaseItem.js');
|
const BaseItem = require('lib/models/BaseItem.js');
|
||||||
const { Synchronizer } = require('lib/synchronizer.js');
|
|
||||||
const { FileApi } = require('lib/file-api.js');
|
const { FileApi } = require('lib/file-api.js');
|
||||||
const { FileApiDriverMemory } = require('lib/file-api-driver-memory.js');
|
const { FileApiDriverMemory } = require('lib/file-api-driver-memory.js');
|
||||||
const { FileApiDriverLocal } = require('lib/file-api-driver-local.js');
|
const { FileApiDriverLocal } = require('lib/file-api-driver-local.js');
|
||||||
@@ -67,7 +68,7 @@ SyncTargetRegistry.addClass(SyncTargetNextcloud);
|
|||||||
SyncTargetRegistry.addClass(SyncTargetDropbox);
|
SyncTargetRegistry.addClass(SyncTargetDropbox);
|
||||||
|
|
||||||
// const syncTargetId_ = SyncTargetRegistry.nameToId("nextcloud");
|
// const syncTargetId_ = SyncTargetRegistry.nameToId("nextcloud");
|
||||||
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';
|
||||||
@@ -186,7 +187,7 @@ async function setupDatabase(id = null) {
|
|||||||
await fs.unlink(filePath);
|
await fs.unlink(filePath);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Don't care if the file doesn't exist
|
// Don't care if the file doesn't exist
|
||||||
};
|
}
|
||||||
|
|
||||||
databases_[id] = new JoplinDatabase(new DatabaseDriverNode());
|
databases_[id] = new JoplinDatabase(new DatabaseDriverNode());
|
||||||
databases_[id].setLogger(dbLogger);
|
databases_[id].setLogger(dbLogger);
|
||||||
@@ -279,9 +280,9 @@ async function loadEncryptionMasterKey(id = null, useExisting = false) {
|
|||||||
masterKey = await service.generateMasterKey('123456');
|
masterKey = await service.generateMasterKey('123456');
|
||||||
masterKey = await MasterKey.save(masterKey);
|
masterKey = await MasterKey.save(masterKey);
|
||||||
} else { // Use the one already available
|
} else { // Use the one already available
|
||||||
materKey = await MasterKey.all();
|
const masterKeys = await MasterKey.all();
|
||||||
if (!materKey.length) throw new Error('No mater key available');
|
if (!masterKeys.length) throw new Error('No mater key available');
|
||||||
masterKey = materKey[0];
|
masterKey = masterKeys[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
await service.loadMasterKey(masterKey, '123456', true);
|
await service.loadMasterKey(masterKey, '123456', true);
|
||||||
@@ -293,7 +294,7 @@ function fileApi() {
|
|||||||
if (fileApi_) return fileApi_;
|
if (fileApi_) return fileApi_;
|
||||||
|
|
||||||
if (syncTargetId_ == SyncTargetRegistry.nameToId('filesystem')) {
|
if (syncTargetId_ == SyncTargetRegistry.nameToId('filesystem')) {
|
||||||
fs.removeSync(syncDir)
|
fs.removeSync(syncDir);
|
||||||
fs.mkdirpSync(syncDir, 0o755);
|
fs.mkdirpSync(syncDir, 0o755);
|
||||||
fileApi_ = new FileApi(syncDir, new FileApiDriverLocal());
|
fileApi_ = new FileApi(syncDir, new FileApiDriverLocal());
|
||||||
} else if (syncTargetId_ == SyncTargetRegistry.nameToId('memory')) {
|
} else if (syncTargetId_ == SyncTargetRegistry.nameToId('memory')) {
|
||||||
@@ -359,7 +360,7 @@ function asyncTest(callback) {
|
|||||||
} finally {
|
} finally {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function allSyncTargetItemsEncrypted() {
|
async function allSyncTargetItemsEncrypted() {
|
||||||
@@ -381,10 +382,10 @@ async function allSyncTargetItemsEncrypted() {
|
|||||||
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') output = encryptedCount++;
|
if (content.substr(0, 5) === 'JED01') encryptedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!!remoteContent.encryption_applied) encryptedCount++;
|
if (remoteContent.encryption_applied) encryptedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!totalCount) throw new Error('No encryptable item on sync target');
|
if (!totalCount) throw new Error('No encryptable item on sync target');
|
||||||
|
@@ -1,7 +1,5 @@
|
|||||||
require('app-module-path').addPath(__dirname);
|
require('app-module-path').addPath(__dirname);
|
||||||
|
|
||||||
const { time } = require('lib/time-utils.js');
|
|
||||||
const { fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
|
|
||||||
const urlUtils = require('lib/urlUtils.js');
|
const urlUtils = require('lib/urlUtils.js');
|
||||||
|
|
||||||
process.on('unhandledRejection', (reason, p) => {
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
|
@@ -1,13 +1,10 @@
|
|||||||
let browser_ = null;
|
let browser_ = null;
|
||||||
let browserName_ = null;
|
|
||||||
if (typeof browser !== 'undefined') {
|
if (typeof browser !== 'undefined') {
|
||||||
browser_ = browser;
|
browser_ = browser;
|
||||||
browserSupportsPromises_ = true;
|
browserSupportsPromises_ = true;
|
||||||
browserName_ = 'firefox';
|
|
||||||
} else if (typeof chrome !== 'undefined') {
|
} else if (typeof chrome !== 'undefined') {
|
||||||
browser_ = chrome;
|
browser_ = chrome;
|
||||||
browserSupportsPromises_ = false;
|
browserSupportsPromises_ = false;
|
||||||
browserName_ = 'chrome';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let env_ = null;
|
let env_ = null;
|
||||||
@@ -21,7 +18,7 @@ window.joplinEnv = function() {
|
|||||||
const manifest = browser_.runtime.getManifest();
|
const manifest = browser_.runtime.getManifest();
|
||||||
env_ = manifest.name.indexOf('[DEV]') >= 0 ? 'dev' : 'prod';
|
env_ = manifest.name.indexOf('[DEV]') >= 0 ? 'dev' : 'prod';
|
||||||
return env_;
|
return env_;
|
||||||
}
|
};
|
||||||
|
|
||||||
async function browserCaptureVisibleTabs(windowId) {
|
async function browserCaptureVisibleTabs(windowId) {
|
||||||
const options = { format: 'jpeg' };
|
const options = { format: 'jpeg' };
|
||||||
@@ -58,7 +55,7 @@ browser_.runtime.onMessage.addListener(async (command) => {
|
|||||||
const zoom = await browserGetZoom();
|
const zoom = await browserGetZoom();
|
||||||
|
|
||||||
const imageDataUrl = await browserCaptureVisibleTabs(null);
|
const imageDataUrl = await browserCaptureVisibleTabs(null);
|
||||||
content = Object.assign({}, command.content);
|
const content = Object.assign({}, command.content);
|
||||||
content.image_data_url = imageDataUrl;
|
content.image_data_url = imageDataUrl;
|
||||||
|
|
||||||
const newArea = Object.assign({}, command.content.crop_rect);
|
const newArea = Object.assign({}, command.content.crop_rect);
|
||||||
@@ -68,13 +65,13 @@ 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',
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
body: JSON.stringify(content)
|
body: JSON.stringify(content),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -32,19 +32,19 @@
|
|||||||
// XML only defines these and the numeric ones:
|
// XML only defines these and the numeric ones:
|
||||||
|
|
||||||
var entityTable = {
|
var entityTable = {
|
||||||
"lt": "<",
|
'lt': '<',
|
||||||
"gt": ">",
|
'gt': '>',
|
||||||
"amp": "&",
|
'amp': '&',
|
||||||
"quot": '"',
|
'quot': '"',
|
||||||
"apos": "'",
|
'apos': '\'',
|
||||||
};
|
};
|
||||||
|
|
||||||
var reverseEntityTable = {
|
var reverseEntityTable = {
|
||||||
"<": "<",
|
'<': '<',
|
||||||
">": ">",
|
'>': '>',
|
||||||
"&": "&",
|
'&': '&',
|
||||||
'"': """,
|
'"': '"',
|
||||||
"'": "'",
|
'\'': ''',
|
||||||
};
|
};
|
||||||
|
|
||||||
function encodeTextContentHTML(s) {
|
function encodeTextContentHTML(s) {
|
||||||
@@ -70,215 +70,215 @@
|
|||||||
|
|
||||||
// When a style is set in JS, map it to the corresponding CSS attribute
|
// When a style is set in JS, map it to the corresponding CSS attribute
|
||||||
var styleMap = {
|
var styleMap = {
|
||||||
"alignmentBaseline": "alignment-baseline",
|
'alignmentBaseline': 'alignment-baseline',
|
||||||
"background": "background",
|
'background': 'background',
|
||||||
"backgroundAttachment": "background-attachment",
|
'backgroundAttachment': 'background-attachment',
|
||||||
"backgroundClip": "background-clip",
|
'backgroundClip': 'background-clip',
|
||||||
"backgroundColor": "background-color",
|
'backgroundColor': 'background-color',
|
||||||
"backgroundImage": "background-image",
|
'backgroundImage': 'background-image',
|
||||||
"backgroundOrigin": "background-origin",
|
'backgroundOrigin': 'background-origin',
|
||||||
"backgroundPosition": "background-position",
|
'backgroundPosition': 'background-position',
|
||||||
"backgroundPositionX": "background-position-x",
|
'backgroundPositionX': 'background-position-x',
|
||||||
"backgroundPositionY": "background-position-y",
|
'backgroundPositionY': 'background-position-y',
|
||||||
"backgroundRepeat": "background-repeat",
|
'backgroundRepeat': 'background-repeat',
|
||||||
"backgroundRepeatX": "background-repeat-x",
|
'backgroundRepeatX': 'background-repeat-x',
|
||||||
"backgroundRepeatY": "background-repeat-y",
|
'backgroundRepeatY': 'background-repeat-y',
|
||||||
"backgroundSize": "background-size",
|
'backgroundSize': 'background-size',
|
||||||
"baselineShift": "baseline-shift",
|
'baselineShift': 'baseline-shift',
|
||||||
"border": "border",
|
'border': 'border',
|
||||||
"borderBottom": "border-bottom",
|
'borderBottom': 'border-bottom',
|
||||||
"borderBottomColor": "border-bottom-color",
|
'borderBottomColor': 'border-bottom-color',
|
||||||
"borderBottomLeftRadius": "border-bottom-left-radius",
|
'borderBottomLeftRadius': 'border-bottom-left-radius',
|
||||||
"borderBottomRightRadius": "border-bottom-right-radius",
|
'borderBottomRightRadius': 'border-bottom-right-radius',
|
||||||
"borderBottomStyle": "border-bottom-style",
|
'borderBottomStyle': 'border-bottom-style',
|
||||||
"borderBottomWidth": "border-bottom-width",
|
'borderBottomWidth': 'border-bottom-width',
|
||||||
"borderCollapse": "border-collapse",
|
'borderCollapse': 'border-collapse',
|
||||||
"borderColor": "border-color",
|
'borderColor': 'border-color',
|
||||||
"borderImage": "border-image",
|
'borderImage': 'border-image',
|
||||||
"borderImageOutset": "border-image-outset",
|
'borderImageOutset': 'border-image-outset',
|
||||||
"borderImageRepeat": "border-image-repeat",
|
'borderImageRepeat': 'border-image-repeat',
|
||||||
"borderImageSlice": "border-image-slice",
|
'borderImageSlice': 'border-image-slice',
|
||||||
"borderImageSource": "border-image-source",
|
'borderImageSource': 'border-image-source',
|
||||||
"borderImageWidth": "border-image-width",
|
'borderImageWidth': 'border-image-width',
|
||||||
"borderLeft": "border-left",
|
'borderLeft': 'border-left',
|
||||||
"borderLeftColor": "border-left-color",
|
'borderLeftColor': 'border-left-color',
|
||||||
"borderLeftStyle": "border-left-style",
|
'borderLeftStyle': 'border-left-style',
|
||||||
"borderLeftWidth": "border-left-width",
|
'borderLeftWidth': 'border-left-width',
|
||||||
"borderRadius": "border-radius",
|
'borderRadius': 'border-radius',
|
||||||
"borderRight": "border-right",
|
'borderRight': 'border-right',
|
||||||
"borderRightColor": "border-right-color",
|
'borderRightColor': 'border-right-color',
|
||||||
"borderRightStyle": "border-right-style",
|
'borderRightStyle': 'border-right-style',
|
||||||
"borderRightWidth": "border-right-width",
|
'borderRightWidth': 'border-right-width',
|
||||||
"borderSpacing": "border-spacing",
|
'borderSpacing': 'border-spacing',
|
||||||
"borderStyle": "border-style",
|
'borderStyle': 'border-style',
|
||||||
"borderTop": "border-top",
|
'borderTop': 'border-top',
|
||||||
"borderTopColor": "border-top-color",
|
'borderTopColor': 'border-top-color',
|
||||||
"borderTopLeftRadius": "border-top-left-radius",
|
'borderTopLeftRadius': 'border-top-left-radius',
|
||||||
"borderTopRightRadius": "border-top-right-radius",
|
'borderTopRightRadius': 'border-top-right-radius',
|
||||||
"borderTopStyle": "border-top-style",
|
'borderTopStyle': 'border-top-style',
|
||||||
"borderTopWidth": "border-top-width",
|
'borderTopWidth': 'border-top-width',
|
||||||
"borderWidth": "border-width",
|
'borderWidth': 'border-width',
|
||||||
"bottom": "bottom",
|
'bottom': 'bottom',
|
||||||
"boxShadow": "box-shadow",
|
'boxShadow': 'box-shadow',
|
||||||
"boxSizing": "box-sizing",
|
'boxSizing': 'box-sizing',
|
||||||
"captionSide": "caption-side",
|
'captionSide': 'caption-side',
|
||||||
"clear": "clear",
|
'clear': 'clear',
|
||||||
"clip": "clip",
|
'clip': 'clip',
|
||||||
"clipPath": "clip-path",
|
'clipPath': 'clip-path',
|
||||||
"clipRule": "clip-rule",
|
'clipRule': 'clip-rule',
|
||||||
"color": "color",
|
'color': 'color',
|
||||||
"colorInterpolation": "color-interpolation",
|
'colorInterpolation': 'color-interpolation',
|
||||||
"colorInterpolationFilters": "color-interpolation-filters",
|
'colorInterpolationFilters': 'color-interpolation-filters',
|
||||||
"colorProfile": "color-profile",
|
'colorProfile': 'color-profile',
|
||||||
"colorRendering": "color-rendering",
|
'colorRendering': 'color-rendering',
|
||||||
"content": "content",
|
'content': 'content',
|
||||||
"counterIncrement": "counter-increment",
|
'counterIncrement': 'counter-increment',
|
||||||
"counterReset": "counter-reset",
|
'counterReset': 'counter-reset',
|
||||||
"cursor": "cursor",
|
'cursor': 'cursor',
|
||||||
"direction": "direction",
|
'direction': 'direction',
|
||||||
"display": "display",
|
'display': 'display',
|
||||||
"dominantBaseline": "dominant-baseline",
|
'dominantBaseline': 'dominant-baseline',
|
||||||
"emptyCells": "empty-cells",
|
'emptyCells': 'empty-cells',
|
||||||
"enableBackground": "enable-background",
|
'enableBackground': 'enable-background',
|
||||||
"fill": "fill",
|
'fill': 'fill',
|
||||||
"fillOpacity": "fill-opacity",
|
'fillOpacity': 'fill-opacity',
|
||||||
"fillRule": "fill-rule",
|
'fillRule': 'fill-rule',
|
||||||
"filter": "filter",
|
'filter': 'filter',
|
||||||
"cssFloat": "float",
|
'cssFloat': 'float',
|
||||||
"floodColor": "flood-color",
|
'floodColor': 'flood-color',
|
||||||
"floodOpacity": "flood-opacity",
|
'floodOpacity': 'flood-opacity',
|
||||||
"font": "font",
|
'font': 'font',
|
||||||
"fontFamily": "font-family",
|
'fontFamily': 'font-family',
|
||||||
"fontSize": "font-size",
|
'fontSize': 'font-size',
|
||||||
"fontStretch": "font-stretch",
|
'fontStretch': 'font-stretch',
|
||||||
"fontStyle": "font-style",
|
'fontStyle': 'font-style',
|
||||||
"fontVariant": "font-variant",
|
'fontVariant': 'font-variant',
|
||||||
"fontWeight": "font-weight",
|
'fontWeight': 'font-weight',
|
||||||
"glyphOrientationHorizontal": "glyph-orientation-horizontal",
|
'glyphOrientationHorizontal': 'glyph-orientation-horizontal',
|
||||||
"glyphOrientationVertical": "glyph-orientation-vertical",
|
'glyphOrientationVertical': 'glyph-orientation-vertical',
|
||||||
"height": "height",
|
'height': 'height',
|
||||||
"imageRendering": "image-rendering",
|
'imageRendering': 'image-rendering',
|
||||||
"kerning": "kerning",
|
'kerning': 'kerning',
|
||||||
"left": "left",
|
'left': 'left',
|
||||||
"letterSpacing": "letter-spacing",
|
'letterSpacing': 'letter-spacing',
|
||||||
"lightingColor": "lighting-color",
|
'lightingColor': 'lighting-color',
|
||||||
"lineHeight": "line-height",
|
'lineHeight': 'line-height',
|
||||||
"listStyle": "list-style",
|
'listStyle': 'list-style',
|
||||||
"listStyleImage": "list-style-image",
|
'listStyleImage': 'list-style-image',
|
||||||
"listStylePosition": "list-style-position",
|
'listStylePosition': 'list-style-position',
|
||||||
"listStyleType": "list-style-type",
|
'listStyleType': 'list-style-type',
|
||||||
"margin": "margin",
|
'margin': 'margin',
|
||||||
"marginBottom": "margin-bottom",
|
'marginBottom': 'margin-bottom',
|
||||||
"marginLeft": "margin-left",
|
'marginLeft': 'margin-left',
|
||||||
"marginRight": "margin-right",
|
'marginRight': 'margin-right',
|
||||||
"marginTop": "margin-top",
|
'marginTop': 'margin-top',
|
||||||
"marker": "marker",
|
'marker': 'marker',
|
||||||
"markerEnd": "marker-end",
|
'markerEnd': 'marker-end',
|
||||||
"markerMid": "marker-mid",
|
'markerMid': 'marker-mid',
|
||||||
"markerStart": "marker-start",
|
'markerStart': 'marker-start',
|
||||||
"mask": "mask",
|
'mask': 'mask',
|
||||||
"maxHeight": "max-height",
|
'maxHeight': 'max-height',
|
||||||
"maxWidth": "max-width",
|
'maxWidth': 'max-width',
|
||||||
"minHeight": "min-height",
|
'minHeight': 'min-height',
|
||||||
"minWidth": "min-width",
|
'minWidth': 'min-width',
|
||||||
"opacity": "opacity",
|
'opacity': 'opacity',
|
||||||
"orphans": "orphans",
|
'orphans': 'orphans',
|
||||||
"outline": "outline",
|
'outline': 'outline',
|
||||||
"outlineColor": "outline-color",
|
'outlineColor': 'outline-color',
|
||||||
"outlineOffset": "outline-offset",
|
'outlineOffset': 'outline-offset',
|
||||||
"outlineStyle": "outline-style",
|
'outlineStyle': 'outline-style',
|
||||||
"outlineWidth": "outline-width",
|
'outlineWidth': 'outline-width',
|
||||||
"overflow": "overflow",
|
'overflow': 'overflow',
|
||||||
"overflowX": "overflow-x",
|
'overflowX': 'overflow-x',
|
||||||
"overflowY": "overflow-y",
|
'overflowY': 'overflow-y',
|
||||||
"padding": "padding",
|
'padding': 'padding',
|
||||||
"paddingBottom": "padding-bottom",
|
'paddingBottom': 'padding-bottom',
|
||||||
"paddingLeft": "padding-left",
|
'paddingLeft': 'padding-left',
|
||||||
"paddingRight": "padding-right",
|
'paddingRight': 'padding-right',
|
||||||
"paddingTop": "padding-top",
|
'paddingTop': 'padding-top',
|
||||||
"page": "page",
|
'page': 'page',
|
||||||
"pageBreakAfter": "page-break-after",
|
'pageBreakAfter': 'page-break-after',
|
||||||
"pageBreakBefore": "page-break-before",
|
'pageBreakBefore': 'page-break-before',
|
||||||
"pageBreakInside": "page-break-inside",
|
'pageBreakInside': 'page-break-inside',
|
||||||
"pointerEvents": "pointer-events",
|
'pointerEvents': 'pointer-events',
|
||||||
"position": "position",
|
'position': 'position',
|
||||||
"quotes": "quotes",
|
'quotes': 'quotes',
|
||||||
"resize": "resize",
|
'resize': 'resize',
|
||||||
"right": "right",
|
'right': 'right',
|
||||||
"shapeRendering": "shape-rendering",
|
'shapeRendering': 'shape-rendering',
|
||||||
"size": "size",
|
'size': 'size',
|
||||||
"speak": "speak",
|
'speak': 'speak',
|
||||||
"src": "src",
|
'src': 'src',
|
||||||
"stopColor": "stop-color",
|
'stopColor': 'stop-color',
|
||||||
"stopOpacity": "stop-opacity",
|
'stopOpacity': 'stop-opacity',
|
||||||
"stroke": "stroke",
|
'stroke': 'stroke',
|
||||||
"strokeDasharray": "stroke-dasharray",
|
'strokeDasharray': 'stroke-dasharray',
|
||||||
"strokeDashoffset": "stroke-dashoffset",
|
'strokeDashoffset': 'stroke-dashoffset',
|
||||||
"strokeLinecap": "stroke-linecap",
|
'strokeLinecap': 'stroke-linecap',
|
||||||
"strokeLinejoin": "stroke-linejoin",
|
'strokeLinejoin': 'stroke-linejoin',
|
||||||
"strokeMiterlimit": "stroke-miterlimit",
|
'strokeMiterlimit': 'stroke-miterlimit',
|
||||||
"strokeOpacity": "stroke-opacity",
|
'strokeOpacity': 'stroke-opacity',
|
||||||
"strokeWidth": "stroke-width",
|
'strokeWidth': 'stroke-width',
|
||||||
"tableLayout": "table-layout",
|
'tableLayout': 'table-layout',
|
||||||
"textAlign": "text-align",
|
'textAlign': 'text-align',
|
||||||
"textAnchor": "text-anchor",
|
'textAnchor': 'text-anchor',
|
||||||
"textDecoration": "text-decoration",
|
'textDecoration': 'text-decoration',
|
||||||
"textIndent": "text-indent",
|
'textIndent': 'text-indent',
|
||||||
"textLineThrough": "text-line-through",
|
'textLineThrough': 'text-line-through',
|
||||||
"textLineThroughColor": "text-line-through-color",
|
'textLineThroughColor': 'text-line-through-color',
|
||||||
"textLineThroughMode": "text-line-through-mode",
|
'textLineThroughMode': 'text-line-through-mode',
|
||||||
"textLineThroughStyle": "text-line-through-style",
|
'textLineThroughStyle': 'text-line-through-style',
|
||||||
"textLineThroughWidth": "text-line-through-width",
|
'textLineThroughWidth': 'text-line-through-width',
|
||||||
"textOverflow": "text-overflow",
|
'textOverflow': 'text-overflow',
|
||||||
"textOverline": "text-overline",
|
'textOverline': 'text-overline',
|
||||||
"textOverlineColor": "text-overline-color",
|
'textOverlineColor': 'text-overline-color',
|
||||||
"textOverlineMode": "text-overline-mode",
|
'textOverlineMode': 'text-overline-mode',
|
||||||
"textOverlineStyle": "text-overline-style",
|
'textOverlineStyle': 'text-overline-style',
|
||||||
"textOverlineWidth": "text-overline-width",
|
'textOverlineWidth': 'text-overline-width',
|
||||||
"textRendering": "text-rendering",
|
'textRendering': 'text-rendering',
|
||||||
"textShadow": "text-shadow",
|
'textShadow': 'text-shadow',
|
||||||
"textTransform": "text-transform",
|
'textTransform': 'text-transform',
|
||||||
"textUnderline": "text-underline",
|
'textUnderline': 'text-underline',
|
||||||
"textUnderlineColor": "text-underline-color",
|
'textUnderlineColor': 'text-underline-color',
|
||||||
"textUnderlineMode": "text-underline-mode",
|
'textUnderlineMode': 'text-underline-mode',
|
||||||
"textUnderlineStyle": "text-underline-style",
|
'textUnderlineStyle': 'text-underline-style',
|
||||||
"textUnderlineWidth": "text-underline-width",
|
'textUnderlineWidth': 'text-underline-width',
|
||||||
"top": "top",
|
'top': 'top',
|
||||||
"unicodeBidi": "unicode-bidi",
|
'unicodeBidi': 'unicode-bidi',
|
||||||
"unicodeRange": "unicode-range",
|
'unicodeRange': 'unicode-range',
|
||||||
"vectorEffect": "vector-effect",
|
'vectorEffect': 'vector-effect',
|
||||||
"verticalAlign": "vertical-align",
|
'verticalAlign': 'vertical-align',
|
||||||
"visibility": "visibility",
|
'visibility': 'visibility',
|
||||||
"whiteSpace": "white-space",
|
'whiteSpace': 'white-space',
|
||||||
"widows": "widows",
|
'widows': 'widows',
|
||||||
"width": "width",
|
'width': 'width',
|
||||||
"wordBreak": "word-break",
|
'wordBreak': 'word-break',
|
||||||
"wordSpacing": "word-spacing",
|
'wordSpacing': 'word-spacing',
|
||||||
"wordWrap": "word-wrap",
|
'wordWrap': 'word-wrap',
|
||||||
"writingMode": "writing-mode",
|
'writingMode': 'writing-mode',
|
||||||
"zIndex": "z-index",
|
'zIndex': 'z-index',
|
||||||
"zoom": "zoom",
|
'zoom': 'zoom',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Elements that can be self-closing
|
// Elements that can be self-closing
|
||||||
var voidElems = {
|
var voidElems = {
|
||||||
"area": true,
|
'area': true,
|
||||||
"base": true,
|
'base': true,
|
||||||
"br": true,
|
'br': true,
|
||||||
"col": true,
|
'col': true,
|
||||||
"command": true,
|
'command': true,
|
||||||
"embed": true,
|
'embed': true,
|
||||||
"hr": true,
|
'hr': true,
|
||||||
"img": true,
|
'img': true,
|
||||||
"input": true,
|
'input': true,
|
||||||
"link": true,
|
'link': true,
|
||||||
"meta": true,
|
'meta': true,
|
||||||
"param": true,
|
'param': true,
|
||||||
"source": true,
|
'source': true,
|
||||||
"wbr": true
|
'wbr': true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var whitespace = [" ", "\t", "\n", "\r"];
|
var whitespace = [' ', '\t', '\n', '\r'];
|
||||||
|
|
||||||
// See http://www.w3schools.com/dom/dom_nodetype.asp
|
// See http://www.w3schools.com/dom/dom_nodetype.asp
|
||||||
var nodeTypes = {
|
var nodeTypes = {
|
||||||
@@ -293,13 +293,13 @@
|
|||||||
DOCUMENT_NODE: 9,
|
DOCUMENT_NODE: 9,
|
||||||
DOCUMENT_TYPE_NODE: 10,
|
DOCUMENT_TYPE_NODE: 10,
|
||||||
DOCUMENT_FRAGMENT_NODE: 11,
|
DOCUMENT_FRAGMENT_NODE: 11,
|
||||||
NOTATION_NODE: 12
|
NOTATION_NODE: 12,
|
||||||
};
|
};
|
||||||
|
|
||||||
function getElementsByTagName(tag) {
|
function getElementsByTagName(tag) {
|
||||||
tag = tag.toUpperCase();
|
tag = tag.toUpperCase();
|
||||||
var elems = [];
|
var elems = [];
|
||||||
var allTags = (tag === "*");
|
var allTags = (tag === '*');
|
||||||
function getElems(node) {
|
function getElems(node) {
|
||||||
var length = node.children.length;
|
var length = node.children.length;
|
||||||
for (var i = 0; i < length; i++) {
|
for (var i = 0; i < length; i++) {
|
||||||
@@ -364,7 +364,7 @@
|
|||||||
var childNodes = this.childNodes;
|
var childNodes = this.childNodes;
|
||||||
var childIndex = childNodes.indexOf(child);
|
var childIndex = childNodes.indexOf(child);
|
||||||
if (childIndex === -1) {
|
if (childIndex === -1) {
|
||||||
throw "removeChild: node not found";
|
throw 'removeChild: node not found';
|
||||||
} else {
|
} else {
|
||||||
child.parentNode = null;
|
child.parentNode = null;
|
||||||
var prev = child.previousSibling;
|
var prev = child.previousSibling;
|
||||||
@@ -395,7 +395,7 @@
|
|||||||
var childNodes = this.childNodes;
|
var childNodes = this.childNodes;
|
||||||
var childIndex = childNodes.indexOf(oldNode);
|
var childIndex = childNodes.indexOf(oldNode);
|
||||||
if (childIndex === -1) {
|
if (childIndex === -1) {
|
||||||
throw "replaceChild: node not found";
|
throw 'replaceChild: node not found';
|
||||||
} else {
|
} else {
|
||||||
// This will take care of updating the new node if it was somewhere else before:
|
// This will take care of updating the new node if it was somewhere else before:
|
||||||
if (newNode.parentNode)
|
if (newNode.parentNode)
|
||||||
@@ -511,8 +511,8 @@
|
|||||||
Comment.prototype = {
|
Comment.prototype = {
|
||||||
__proto__: Node.prototype,
|
__proto__: Node.prototype,
|
||||||
|
|
||||||
nodeName: "#comment",
|
nodeName: '#comment',
|
||||||
nodeType: Node.COMMENT_NODE
|
nodeType: Node.COMMENT_NODE,
|
||||||
};
|
};
|
||||||
|
|
||||||
var Text = function () {
|
var Text = function () {
|
||||||
@@ -522,17 +522,17 @@
|
|||||||
Text.prototype = {
|
Text.prototype = {
|
||||||
__proto__: Node.prototype,
|
__proto__: Node.prototype,
|
||||||
|
|
||||||
nodeName: "#text",
|
nodeName: '#text',
|
||||||
nodeType: Node.TEXT_NODE,
|
nodeType: Node.TEXT_NODE,
|
||||||
get textContent() {
|
get textContent() {
|
||||||
if (typeof this._textContent === "undefined") {
|
if (typeof this._textContent === 'undefined') {
|
||||||
this._textContent = decodeHTML(this._innerHTML || "");
|
this._textContent = decodeHTML(this._innerHTML || '');
|
||||||
}
|
}
|
||||||
return this._textContent;
|
return this._textContent;
|
||||||
},
|
},
|
||||||
get innerHTML() {
|
get innerHTML() {
|
||||||
if (typeof this._innerHTML === "undefined") {
|
if (typeof this._innerHTML === 'undefined') {
|
||||||
this._innerHTML = encodeTextContentHTML(this._textContent || "");
|
this._innerHTML = encodeTextContentHTML(this._textContent || '');
|
||||||
}
|
}
|
||||||
return this._innerHTML;
|
return this._innerHTML;
|
||||||
},
|
},
|
||||||
@@ -557,9 +557,9 @@
|
|||||||
Document.prototype = {
|
Document.prototype = {
|
||||||
__proto__: Node.prototype,
|
__proto__: Node.prototype,
|
||||||
|
|
||||||
nodeName: "#document",
|
nodeName: '#document',
|
||||||
nodeType: Node.DOCUMENT_NODE,
|
nodeType: Node.DOCUMENT_NODE,
|
||||||
title: "",
|
title: '',
|
||||||
|
|
||||||
getElementsByTagName: getElementsByTagName,
|
getElementsByTagName: getElementsByTagName,
|
||||||
|
|
||||||
@@ -590,10 +590,10 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
get baseURI() {
|
get baseURI() {
|
||||||
if (!this.hasOwnProperty("_baseURI")) {
|
if (!this.hasOwnProperty('_baseURI')) {
|
||||||
this._baseURI = this.documentURI;
|
this._baseURI = this.documentURI;
|
||||||
var baseElements = this.getElementsByTagName("base");
|
var baseElements = this.getElementsByTagName('base');
|
||||||
var href = baseElements[0] && baseElements[0].getAttribute("href");
|
var href = baseElements[0] && baseElements[0].getAttribute('href');
|
||||||
if (href) {
|
if (href) {
|
||||||
try {
|
try {
|
||||||
this._baseURI = (new URL(href, this._baseURI)).href;
|
this._baseURI = (new URL(href, this._baseURI)).href;
|
||||||
@@ -608,7 +608,7 @@
|
|||||||
// We use this to find the closing tag.
|
// We use this to find the closing tag.
|
||||||
this._matchingTag = tag;
|
this._matchingTag = tag;
|
||||||
// We're explicitly a non-namespace aware parser, we just pretend it's all HTML.
|
// We're explicitly a non-namespace aware parser, we just pretend it's all HTML.
|
||||||
var lastColonIndex = tag.lastIndexOf(":");
|
var lastColonIndex = tag.lastIndexOf(':');
|
||||||
if (lastColonIndex != -1) {
|
if (lastColonIndex != -1) {
|
||||||
tag = tag.substring(lastColonIndex + 1);
|
tag = tag.substring(lastColonIndex + 1);
|
||||||
}
|
}
|
||||||
@@ -629,43 +629,43 @@
|
|||||||
getElementsByTagName: getElementsByTagName,
|
getElementsByTagName: getElementsByTagName,
|
||||||
|
|
||||||
get className() {
|
get className() {
|
||||||
return this.getAttribute("class") || "";
|
return this.getAttribute('class') || '';
|
||||||
},
|
},
|
||||||
|
|
||||||
set className(str) {
|
set className(str) {
|
||||||
this.setAttribute("class", str);
|
this.setAttribute('class', str);
|
||||||
},
|
},
|
||||||
|
|
||||||
get id() {
|
get id() {
|
||||||
return this.getAttribute("id") || "";
|
return this.getAttribute('id') || '';
|
||||||
},
|
},
|
||||||
|
|
||||||
set id(str) {
|
set id(str) {
|
||||||
this.setAttribute("id", str);
|
this.setAttribute('id', str);
|
||||||
},
|
},
|
||||||
|
|
||||||
get href() {
|
get href() {
|
||||||
return this.getAttribute("href") || "";
|
return this.getAttribute('href') || '';
|
||||||
},
|
},
|
||||||
|
|
||||||
set href(str) {
|
set href(str) {
|
||||||
this.setAttribute("href", str);
|
this.setAttribute('href', str);
|
||||||
},
|
},
|
||||||
|
|
||||||
get src() {
|
get src() {
|
||||||
return this.getAttribute("src") || "";
|
return this.getAttribute('src') || '';
|
||||||
},
|
},
|
||||||
|
|
||||||
set src(str) {
|
set src(str) {
|
||||||
this.setAttribute("src", str);
|
this.setAttribute('src', str);
|
||||||
},
|
},
|
||||||
|
|
||||||
get srcset() {
|
get srcset() {
|
||||||
return this.getAttribute("srcset") || "";
|
return this.getAttribute('srcset') || '';
|
||||||
},
|
},
|
||||||
|
|
||||||
set srcset(str) {
|
set srcset(str) {
|
||||||
this.setAttribute("srcset", str);
|
this.setAttribute('srcset', str);
|
||||||
},
|
},
|
||||||
|
|
||||||
get nodeName() {
|
get nodeName() {
|
||||||
@@ -678,25 +678,25 @@
|
|||||||
for (i = 0; i < node.childNodes.length; i++) {
|
for (i = 0; i < node.childNodes.length; i++) {
|
||||||
var child = node.childNodes[i];
|
var child = node.childNodes[i];
|
||||||
if (child.localName) {
|
if (child.localName) {
|
||||||
arr.push("<" + child.localName);
|
arr.push('<' + child.localName);
|
||||||
|
|
||||||
// serialize attribute list
|
// serialize attribute list
|
||||||
for (var j = 0; j < child.attributes.length; j++) {
|
for (var j = 0; j < child.attributes.length; j++) {
|
||||||
var attr = child.attributes[j];
|
var attr = child.attributes[j];
|
||||||
// the attribute value will be HTML escaped.
|
// the attribute value will be HTML escaped.
|
||||||
var val = attr.getEncodedValue();
|
var val = attr.getEncodedValue();
|
||||||
var quote = (val.indexOf('"') === -1 ? '"' : "'");
|
var quote = (val.indexOf('"') === -1 ? '"' : '\'');
|
||||||
arr.push(" " + attr.name + "=" + quote + val + quote);
|
arr.push(' ' + attr.name + '=' + quote + val + quote);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child.localName in voidElems && !child.childNodes.length) {
|
if (child.localName in voidElems && !child.childNodes.length) {
|
||||||
// if this is a self-closing element, end it here
|
// if this is a self-closing element, end it here
|
||||||
arr.push("/>");
|
arr.push('/>');
|
||||||
} else {
|
} else {
|
||||||
// otherwise, add its children
|
// otherwise, add its children
|
||||||
arr.push(">");
|
arr.push('>');
|
||||||
getHTML(child);
|
getHTML(child);
|
||||||
arr.push("</" + child.localName + ">");
|
arr.push('</' + child.localName + '>');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This is a text node, so asking for innerHTML won't recurse.
|
// This is a text node, so asking for innerHTML won't recurse.
|
||||||
@@ -709,7 +709,7 @@
|
|||||||
// See http://blog.cdleary.com/2012/01/string-representation-in-spidermonkey/#ropes
|
// See http://blog.cdleary.com/2012/01/string-representation-in-spidermonkey/#ropes
|
||||||
var arr = [];
|
var arr = [];
|
||||||
getHTML(this);
|
getHTML(this);
|
||||||
return arr.join("");
|
return arr.join('');
|
||||||
},
|
},
|
||||||
|
|
||||||
set innerHTML(html) {
|
set innerHTML(html) {
|
||||||
@@ -756,7 +756,7 @@
|
|||||||
// See http://blog.cdleary.com/2012/01/string-representation-in-spidermonkey/#ropes
|
// See http://blog.cdleary.com/2012/01/string-representation-in-spidermonkey/#ropes
|
||||||
var text = [];
|
var text = [];
|
||||||
getText(this);
|
getText(this);
|
||||||
return text.join("");
|
return text.join('');
|
||||||
},
|
},
|
||||||
|
|
||||||
getAttribute: function (name) {
|
getAttribute: function (name) {
|
||||||
@@ -808,13 +808,13 @@
|
|||||||
// manipulations, so this should be okay.
|
// manipulations, so this should be okay.
|
||||||
Style.prototype = {
|
Style.prototype = {
|
||||||
getStyle: function (styleName) {
|
getStyle: function (styleName) {
|
||||||
var attr = this.node.getAttribute("style");
|
var attr = this.node.getAttribute('style');
|
||||||
if (!attr)
|
if (!attr)
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
||||||
var styles = attr.split(";");
|
var styles = attr.split(';');
|
||||||
for (var i = 0; i < styles.length; i++) {
|
for (var i = 0; i < styles.length; i++) {
|
||||||
var style = styles[i].split(":");
|
var style = styles[i].split(':');
|
||||||
var name = style[0].trim();
|
var name = style[0].trim();
|
||||||
if (name === styleName)
|
if (name === styleName)
|
||||||
return style[1].trim();
|
return style[1].trim();
|
||||||
@@ -824,22 +824,22 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
setStyle: function (styleName, styleValue) {
|
setStyle: function (styleName, styleValue) {
|
||||||
var value = this.node.getAttribute("style") || "";
|
var value = this.node.getAttribute('style') || '';
|
||||||
var index = 0;
|
var index = 0;
|
||||||
do {
|
do {
|
||||||
var next = value.indexOf(";", index) + 1;
|
var next = value.indexOf(';', index) + 1;
|
||||||
var length = next - index - 1;
|
var length = next - index - 1;
|
||||||
var style = (length > 0 ? value.substr(index, length) : value.substr(index));
|
var style = (length > 0 ? value.substr(index, length) : value.substr(index));
|
||||||
if (style.substr(0, style.indexOf(":")).trim() === styleName) {
|
if (style.substr(0, style.indexOf(':')).trim() === styleName) {
|
||||||
value = value.substr(0, index).trim() + (next ? " " + value.substr(next).trim() : "");
|
value = value.substr(0, index).trim() + (next ? ' ' + value.substr(next).trim() : '');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
index = next;
|
index = next;
|
||||||
} while (index);
|
} while (index);
|
||||||
|
|
||||||
value += " " + styleName + ": " + styleValue + ";";
|
value += ' ' + styleName + ': ' + styleValue + ';';
|
||||||
this.node.setAttribute("style", value.trim());
|
this.node.setAttribute('style', value.trim());
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// For each item in styleMap, define a getter and setter on the style
|
// For each item in styleMap, define a getter and setter on the style
|
||||||
@@ -871,13 +871,13 @@
|
|||||||
// every time.
|
// every time.
|
||||||
this.retPair = [];
|
this.retPair = [];
|
||||||
|
|
||||||
this.errorState = "";
|
this.errorState = '';
|
||||||
};
|
};
|
||||||
|
|
||||||
JSDOMParser.prototype = {
|
JSDOMParser.prototype = {
|
||||||
error: function(m) {
|
error: function(m) {
|
||||||
dump("JSDOMParser error: " + m + "\n");
|
dump('JSDOMParser error: ' + m + '\n');
|
||||||
this.errorState += m + "\n";
|
this.errorState += m + '\n';
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -917,9 +917,9 @@
|
|||||||
* pair and adds the result to the attributes list.
|
* pair and adds the result to the attributes list.
|
||||||
*/
|
*/
|
||||||
readAttribute: function (node) {
|
readAttribute: function (node) {
|
||||||
var name = "";
|
var name = '';
|
||||||
|
|
||||||
var n = this.html.indexOf("=", this.currentChar);
|
var n = this.html.indexOf('=', this.currentChar);
|
||||||
if (n === -1) {
|
if (n === -1) {
|
||||||
this.currentChar = this.html.length;
|
this.currentChar = this.html.length;
|
||||||
} else {
|
} else {
|
||||||
@@ -933,8 +933,8 @@
|
|||||||
|
|
||||||
// After a '=', we should see a '"' for the attribute value
|
// After a '=', we should see a '"' for the attribute value
|
||||||
var c = this.nextChar();
|
var c = this.nextChar();
|
||||||
if (c !== '"' && c !== "'") {
|
if (c !== '"' && c !== '\'') {
|
||||||
this.error("Error reading attribute " + name + ", expecting '\"'");
|
this.error('Error reading attribute ' + name + ', expecting \'"\'');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -960,13 +960,13 @@
|
|||||||
// Read the Element tag name
|
// Read the Element tag name
|
||||||
var strBuf = this.strBuf;
|
var strBuf = this.strBuf;
|
||||||
strBuf.length = 0;
|
strBuf.length = 0;
|
||||||
while (whitespace.indexOf(c) == -1 && c !== ">" && c !== "/") {
|
while (whitespace.indexOf(c) == -1 && c !== '>' && c !== '/') {
|
||||||
if (c === undefined)
|
if (c === undefined)
|
||||||
return false;
|
return false;
|
||||||
strBuf.push(c);
|
strBuf.push(c);
|
||||||
c = this.nextChar();
|
c = this.nextChar();
|
||||||
}
|
}
|
||||||
var tag = strBuf.join("");
|
var tag = strBuf.join('');
|
||||||
|
|
||||||
if (!tag)
|
if (!tag)
|
||||||
return false;
|
return false;
|
||||||
@@ -974,7 +974,7 @@
|
|||||||
var node = new Element(tag);
|
var node = new Element(tag);
|
||||||
|
|
||||||
// Read Element attributes
|
// Read Element attributes
|
||||||
while (c !== "/" && c !== ">") {
|
while (c !== '/' && c !== '>') {
|
||||||
if (c === undefined)
|
if (c === undefined)
|
||||||
return false;
|
return false;
|
||||||
while (whitespace.indexOf(this.html[this.currentChar++]) != -1) {
|
while (whitespace.indexOf(this.html[this.currentChar++]) != -1) {
|
||||||
@@ -982,7 +982,7 @@
|
|||||||
}
|
}
|
||||||
this.currentChar--;
|
this.currentChar--;
|
||||||
c = this.nextChar();
|
c = this.nextChar();
|
||||||
if (c !== "/" && c !== ">") {
|
if (c !== '/' && c !== '>') {
|
||||||
--this.currentChar;
|
--this.currentChar;
|
||||||
this.readAttribute(node);
|
this.readAttribute(node);
|
||||||
}
|
}
|
||||||
@@ -990,11 +990,11 @@
|
|||||||
|
|
||||||
// If this is a self-closing tag, read '/>'
|
// If this is a self-closing tag, read '/>'
|
||||||
var closed = false;
|
var closed = false;
|
||||||
if (c === "/") {
|
if (c === '/') {
|
||||||
closed = true;
|
closed = true;
|
||||||
c = this.nextChar();
|
c = this.nextChar();
|
||||||
if (c !== ">") {
|
if (c !== '>') {
|
||||||
this.error("expected '>' to close " + tag);
|
this.error('expected \'>\' to close ' + tag);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1044,14 +1044,14 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
discardNextComment: function() {
|
discardNextComment: function() {
|
||||||
if (this.match("--")) {
|
if (this.match('--')) {
|
||||||
this.discardTo("-->");
|
this.discardTo('-->');
|
||||||
} else {
|
} else {
|
||||||
var c = this.nextChar();
|
var c = this.nextChar();
|
||||||
while (c !== ">") {
|
while (c !== '>') {
|
||||||
if (c === undefined)
|
if (c === undefined)
|
||||||
return null;
|
return null;
|
||||||
if (c === '"' || c === "'")
|
if (c === '"' || c === '\'')
|
||||||
this.readString(c);
|
this.readString(c);
|
||||||
c = this.nextChar();
|
c = this.nextChar();
|
||||||
}
|
}
|
||||||
@@ -1074,10 +1074,10 @@
|
|||||||
|
|
||||||
// Read any text as Text node
|
// Read any text as Text node
|
||||||
var textNode;
|
var textNode;
|
||||||
if (c !== "<") {
|
if (c !== '<') {
|
||||||
--this.currentChar;
|
--this.currentChar;
|
||||||
textNode = new Text();
|
textNode = new Text();
|
||||||
var n = this.html.indexOf("<", this.currentChar);
|
var n = this.html.indexOf('<', this.currentChar);
|
||||||
if (n === -1) {
|
if (n === -1) {
|
||||||
textNode.innerHTML = this.html.substring(this.currentChar, this.html.length);
|
textNode.innerHTML = this.html.substring(this.currentChar, this.html.length);
|
||||||
this.currentChar = this.html.length;
|
this.currentChar = this.html.length;
|
||||||
@@ -1088,15 +1088,15 @@
|
|||||||
return textNode;
|
return textNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.match("![CDATA[")) {
|
if (this.match('![CDATA[')) {
|
||||||
var endChar = this.html.indexOf("]]>", this.currentChar);
|
var endChar = this.html.indexOf(']]>', this.currentChar);
|
||||||
if (endChar === -1) {
|
if (endChar === -1) {
|
||||||
this.error("unclosed CDATA section");
|
this.error('unclosed CDATA section');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
textNode = new Text();
|
textNode = new Text();
|
||||||
textNode.textContent = this.html.substring(this.currentChar, endChar);
|
textNode.textContent = this.html.substring(this.currentChar, endChar);
|
||||||
this.currentChar = endChar + ("]]>").length;
|
this.currentChar = endChar + (']]>').length;
|
||||||
return textNode;
|
return textNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1106,7 +1106,7 @@
|
|||||||
// textContent, but we don't really care about Comment nodes (we throw
|
// textContent, but we don't really care about Comment nodes (we throw
|
||||||
// them away in readChildren()). So just returning an empty Comment node
|
// them away in readChildren()). So just returning an empty Comment node
|
||||||
// here is sufficient.
|
// here is sufficient.
|
||||||
if (c === "!" || c === "?") {
|
if (c === '!' || c === '?') {
|
||||||
// We're still before the ! or ? that is starting this comment:
|
// We're still before the ! or ? that is starting this comment:
|
||||||
this.currentChar++;
|
this.currentChar++;
|
||||||
return this.discardNextComment();
|
return this.discardNextComment();
|
||||||
@@ -1114,7 +1114,7 @@
|
|||||||
|
|
||||||
// If we're reading a closing tag, return null. This means we've reached
|
// If we're reading a closing tag, return null. This means we've reached
|
||||||
// the end of this set of child nodes.
|
// the end of this set of child nodes.
|
||||||
if (c === "/") {
|
if (c === '/') {
|
||||||
--this.currentChar;
|
--this.currentChar;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1131,9 +1131,9 @@
|
|||||||
// If this isn't a void Element, read its child nodes
|
// If this isn't a void Element, read its child nodes
|
||||||
if (!closed) {
|
if (!closed) {
|
||||||
this.readChildren(node);
|
this.readChildren(node);
|
||||||
var closingTag = "</" + node._matchingTag + ">";
|
var closingTag = '</' + node._matchingTag + '>';
|
||||||
if (!this.match(closingTag)) {
|
if (!this.match(closingTag)) {
|
||||||
this.error("expected '" + closingTag + "' and got " + this.html.substr(this.currentChar, closingTag.length));
|
this.error('expected \'' + closingTag + '\' and got ' + this.html.substr(this.currentChar, closingTag.length));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1141,13 +1141,13 @@
|
|||||||
// Only use the first title, because SVG might have other
|
// Only use the first title, because SVG might have other
|
||||||
// title elements which we don't care about (medium.com
|
// title elements which we don't care about (medium.com
|
||||||
// does this, at least).
|
// does this, at least).
|
||||||
if (localName === "title" && !this.doc.title) {
|
if (localName === 'title' && !this.doc.title) {
|
||||||
this.doc.title = node.textContent.trim();
|
this.doc.title = node.textContent.trim();
|
||||||
} else if (localName === "head") {
|
} else if (localName === 'head') {
|
||||||
this.doc.head = node;
|
this.doc.head = node;
|
||||||
} else if (localName === "body") {
|
} else if (localName === 'body') {
|
||||||
this.doc.body = node;
|
this.doc.body = node;
|
||||||
} else if (localName === "html") {
|
} else if (localName === 'html') {
|
||||||
this.doc.documentElement = node;
|
this.doc.documentElement = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1174,7 +1174,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
return doc;
|
return doc;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Attach the standard DOM types to the global scope
|
// Attach the standard DOM types to the global scope
|
||||||
|
@@ -32,7 +32,7 @@ var REGEXPS = {
|
|||||||
|
|
||||||
function isNodeVisible(node) {
|
function isNodeVisible(node) {
|
||||||
// Have to null-check node.style to deal with SVG and MathML nodes.
|
// Have to null-check node.style to deal with SVG and MathML nodes.
|
||||||
return (!node.style || node.style.display != "none") && !node.hasAttribute("hidden");
|
return (!node.style || node.style.display != 'none') && !node.hasAttribute('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,7 +45,7 @@ function isProbablyReaderable(doc, isVisible) {
|
|||||||
isVisible = isNodeVisible;
|
isVisible = isNodeVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
var nodes = doc.querySelectorAll("p, pre");
|
var nodes = doc.querySelectorAll('p, pre');
|
||||||
|
|
||||||
// Get <div> nodes which have <br> node(s) and append them into the `nodes` variable.
|
// Get <div> nodes which have <br> node(s) and append them into the `nodes` variable.
|
||||||
// Some articles' DOM structures might look like
|
// Some articles' DOM structures might look like
|
||||||
@@ -54,7 +54,7 @@ function isProbablyReaderable(doc, isVisible) {
|
|||||||
// <br>
|
// <br>
|
||||||
// Sentences<br>
|
// Sentences<br>
|
||||||
// </div>
|
// </div>
|
||||||
var brNodes = doc.querySelectorAll("div > br");
|
var brNodes = doc.querySelectorAll('div > br');
|
||||||
if (brNodes.length) {
|
if (brNodes.length) {
|
||||||
var set = new Set(nodes);
|
var set = new Set(nodes);
|
||||||
[].forEach.call(brNodes, function(node) {
|
[].forEach.call(brNodes, function(node) {
|
||||||
@@ -70,13 +70,13 @@ function isProbablyReaderable(doc, isVisible) {
|
|||||||
if (!isVisible(node))
|
if (!isVisible(node))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var matchString = node.className + " " + node.id;
|
var matchString = node.className + ' ' + node.id;
|
||||||
if (REGEXPS.unlikelyCandidates.test(matchString) &&
|
if (REGEXPS.unlikelyCandidates.test(matchString) &&
|
||||||
!REGEXPS.okMaybeItsACandidate.test(matchString)) {
|
!REGEXPS.okMaybeItsACandidate.test(matchString)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.matches("li p")) {
|
if (node.matches('li p')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +94,6 @@ function isProbablyReaderable(doc, isVisible) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof exports === "object") {
|
if (typeof exports === 'object') {
|
||||||
exports.isProbablyReaderable = isProbablyReaderable;
|
exports.isProbablyReaderable = isProbablyReaderable;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -7,10 +7,14 @@
|
|||||||
|
|
||||||
let browser_ = null;
|
let browser_ = null;
|
||||||
if (typeof browser !== 'undefined') {
|
if (typeof browser !== 'undefined') {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
browser_ = browser;
|
browser_ = browser;
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
browserSupportsPromises_ = true;
|
browserSupportsPromises_ = true;
|
||||||
} else if (typeof chrome !== 'undefined') {
|
} else if (typeof chrome !== 'undefined') {
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
browser_ = chrome;
|
browser_ = chrome;
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
browserSupportsPromises_ = false;
|
browserSupportsPromises_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,7 +33,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function pageTitle() {
|
function pageTitle() {
|
||||||
const titleElements = document.getElementsByTagName("title");
|
const titleElements = document.getElementsByTagName('title');
|
||||||
if (titleElements.length) return titleElements[0].text.trim();
|
if (titleElements.length) return titleElements[0].text.trim();
|
||||||
return document.title.trim();
|
return document.title.trim();
|
||||||
}
|
}
|
||||||
@@ -179,7 +183,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nodeName === 'source' && nodeParentName === 'picture') {
|
if (nodeName === 'source' && nodeParentName === 'picture') {
|
||||||
isVisible = false
|
isVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.nodeType === 8) { // Comments are just removed since we can't add a class
|
if (node.nodeType === 8) { // Comments are just removed since we can't add a class
|
||||||
@@ -238,14 +242,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function readabilityProcess() {
|
function readabilityProcess() {
|
||||||
var uri = {
|
// eslint-disable-next-line no-undef
|
||||||
spec: location.href,
|
|
||||||
host: location.host,
|
|
||||||
prePath: location.protocol + "//" + location.host,
|
|
||||||
scheme: location.protocol.substr(0, location.protocol.indexOf(":")),
|
|
||||||
pathBase: location.protocol + "//" + location.host + location.pathname.substr(0, location.pathname.lastIndexOf("/") + 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
const readability = new Readability(documentForReadability());
|
const readability = new Readability(documentForReadability());
|
||||||
const article = readability.parse();
|
const article = readability.parse();
|
||||||
|
|
||||||
@@ -254,7 +251,7 @@
|
|||||||
return {
|
return {
|
||||||
title: article.title,
|
title: article.title,
|
||||||
body: article.content,
|
body: article.content,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function prepareCommandResponse(command) {
|
async function prepareCommandResponse(command) {
|
||||||
@@ -277,9 +274,9 @@
|
|||||||
convert_to: convertToMarkup,
|
convert_to: convertToMarkup,
|
||||||
stylesheets: stylesheets,
|
stylesheets: stylesheets,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
if (command.name === "simplifiedPageHtml") {
|
if (command.name === 'simplifiedPageHtml') {
|
||||||
|
|
||||||
let article = null;
|
let article = null;
|
||||||
try {
|
try {
|
||||||
@@ -294,12 +291,13 @@
|
|||||||
}
|
}
|
||||||
return clippedContentResponse(article.title, article.body, getImageSizes(document), getAnchorNames(document));
|
return clippedContentResponse(article.title, article.body, getImageSizes(document), getAnchorNames(document));
|
||||||
|
|
||||||
} else if (command.name === "isProbablyReaderable") {
|
} else if (command.name === 'isProbablyReaderable') {
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
const ok = isProbablyReaderable(documentForReadability());
|
const ok = isProbablyReaderable(documentForReadability());
|
||||||
return { name: 'isProbablyReaderable', value: ok };
|
return { name: 'isProbablyReaderable', value: ok };
|
||||||
|
|
||||||
} else if (command.name === "completePageHtml") {
|
} else if (command.name === 'completePageHtml') {
|
||||||
|
|
||||||
hardcodePreStyles(document);
|
hardcodePreStyles(document);
|
||||||
preProcessDocument(document);
|
preProcessDocument(document);
|
||||||
@@ -313,7 +311,7 @@
|
|||||||
const stylesheets = convertToMarkup === 'html' ? getStyleSheets(document) : null;
|
const stylesheets = convertToMarkup === 'html' ? getStyleSheets(document) : null;
|
||||||
return clippedContentResponse(pageTitle(), cleanDocument.innerHTML, imageSizes, getAnchorNames(document), stylesheets);
|
return clippedContentResponse(pageTitle(), cleanDocument.innerHTML, imageSizes, getAnchorNames(document), stylesheets);
|
||||||
|
|
||||||
} else if (command.name === "selectedHtml") {
|
} else if (command.name === 'selectedHtml') {
|
||||||
|
|
||||||
hardcodePreStyles(document);
|
hardcodePreStyles(document);
|
||||||
preProcessDocument(document);
|
preProcessDocument(document);
|
||||||
@@ -342,19 +340,19 @@
|
|||||||
const messageComp = document.createElement('div');
|
const messageComp = document.createElement('div');
|
||||||
|
|
||||||
const messageCompWidth = 300;
|
const messageCompWidth = 300;
|
||||||
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';
|
||||||
|
|
||||||
@@ -376,32 +374,32 @@
|
|||||||
let draggingStartPos = null;
|
let draggingStartPos = null;
|
||||||
let selectionArea = {};
|
let selectionArea = {};
|
||||||
|
|
||||||
function updateSelection() {
|
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';
|
||||||
}
|
};
|
||||||
|
|
||||||
function setSelectionSizeFromMouse(event) {
|
const setSelectionSizeFromMouse = function(event) {
|
||||||
selectionArea.width = Math.max(1, event.clientX - draggingStartPos.x);
|
selectionArea.width = Math.max(1, event.clientX - draggingStartPos.x);
|
||||||
selectionArea.height = Math.max(1, event.clientY - draggingStartPos.y);
|
selectionArea.height = Math.max(1, event.clientY - draggingStartPos.y);
|
||||||
updateSelection();
|
updateSelection();
|
||||||
}
|
};
|
||||||
|
|
||||||
function selection_mouseDown(event) {
|
const selection_mouseDown = function(event) {
|
||||||
selectionArea = { x: event.clientX, y: event.clientY, width: 0, height: 0 }
|
selectionArea = { x: event.clientX, y: event.clientY, width: 0, height: 0 };
|
||||||
draggingStartPos = { x: event.clientX, y: event.clientY };
|
draggingStartPos = { x: event.clientX, y: event.clientY };
|
||||||
isDragging = true;
|
isDragging = true;
|
||||||
updateSelection();
|
updateSelection();
|
||||||
}
|
};
|
||||||
|
|
||||||
function selection_mouseMove(event) {
|
const selection_mouseMove = function(event) {
|
||||||
if (!isDragging) return;
|
if (!isDragging) return;
|
||||||
setSelectionSizeFromMouse(event);
|
setSelectionSizeFromMouse(event);
|
||||||
}
|
};
|
||||||
|
|
||||||
function selection_mouseUp(event) {
|
const selection_mouseUp = function(event) {
|
||||||
setSelectionSizeFromMouse(event);
|
setSelectionSizeFromMouse(event);
|
||||||
|
|
||||||
isDragging = false;
|
isDragging = false;
|
||||||
@@ -436,7 +434,7 @@
|
|||||||
api_base_url: command.api_base_url,
|
api_base_url: command.api_base_url,
|
||||||
});
|
});
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
};
|
||||||
|
|
||||||
overlay.addEventListener('mousedown', selection_mouseDown);
|
overlay.addEventListener('mousedown', selection_mouseDown);
|
||||||
overlay.addEventListener('mousemove', selection_mouseMove);
|
overlay.addEventListener('mousemove', selection_mouseMove);
|
||||||
@@ -444,7 +442,7 @@
|
|||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
} else if (command.name === "pageUrl") {
|
} else if (command.name === 'pageUrl') {
|
||||||
|
|
||||||
let url = pageLocationOrigin() + location.pathname + location.search;
|
let url = pageLocationOrigin() + location.pathname + location.search;
|
||||||
return clippedContentResponse(pageTitle(), url, getImageSizes(document), getAnchorNames(document));
|
return clippedContentResponse(pageTitle(), url, getImageSizes(document), getAnchorNames(document));
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
|
||||||
// Add here all the external scripts that the content script might need
|
// Add here all the external scripts that the content script might need
|
||||||
// and run browserify on it to create vendor.bundle.js
|
// and run browserify on it to create vendor.bundle.js
|
||||||
const Readability = require('readability-node').Readability;
|
const Readability = require('readability-node').Readability;
|
@@ -3,9 +3,6 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@@ -45,9 +45,9 @@ class PreviewComponent extends React.PureComponent {
|
|||||||
return (
|
return (
|
||||||
<div className="Preview">
|
<div className="Preview">
|
||||||
<h2>Title:</h2>
|
<h2>Title:</h2>
|
||||||
<input className={"Title"} value={this.props.title} onChange={this.props.onTitleChange}/>
|
<input className={'Title'} value={this.props.title} onChange={this.props.onTitleChange}/>
|
||||||
<p><span>Type:</span> {commandUserString(this.props.command)}</p>
|
<p><span>Type:</span> {commandUserString(this.props.command)}</p>
|
||||||
<a className={"Confirm Button"} onClick={this.props.onConfirmClick}>Confirm</a>
|
<a className={'Confirm Button'} onClick={this.props.onConfirmClick}>Confirm</a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -81,46 +81,46 @@ class AppComponent extends Component {
|
|||||||
content.tags = this.state.selectedTags.join(',');
|
content.tags = this.state.selectedTags.join(',');
|
||||||
content.parent_id = this.props.selectedFolderId;
|
content.parent_id = this.props.selectedFolderId;
|
||||||
bridge().sendContentToJoplin(content);
|
bridge().sendContentToJoplin(content);
|
||||||
}
|
};
|
||||||
|
|
||||||
this.contentTitle_change = (event) => {
|
this.contentTitle_change = (event) => {
|
||||||
this.props.dispatch({
|
this.props.dispatch({
|
||||||
type: 'CLIPPED_CONTENT_TITLE_SET',
|
type: 'CLIPPED_CONTENT_TITLE_SET',
|
||||||
text: event.currentTarget.value
|
text: event.currentTarget.value,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
this.clipSimplified_click = () => {
|
this.clipSimplified_click = () => {
|
||||||
bridge().sendCommandToActiveTab({
|
bridge().sendCommandToActiveTab({
|
||||||
name: 'simplifiedPageHtml',
|
name: 'simplifiedPageHtml',
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
this.clipComplete_click = () => {
|
this.clipComplete_click = () => {
|
||||||
bridge().sendCommandToActiveTab({
|
bridge().sendCommandToActiveTab({
|
||||||
name: 'completePageHtml',
|
name: 'completePageHtml',
|
||||||
preProcessFor: 'markdown',
|
preProcessFor: 'markdown',
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
this.clipCompleteHtml_click = () => {
|
this.clipCompleteHtml_click = () => {
|
||||||
bridge().sendCommandToActiveTab({
|
bridge().sendCommandToActiveTab({
|
||||||
name: 'completePageHtml',
|
name: 'completePageHtml',
|
||||||
preProcessFor: 'html',
|
preProcessFor: 'html',
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
this.clipSelection_click = () => {
|
this.clipSelection_click = () => {
|
||||||
bridge().sendCommandToActiveTab({
|
bridge().sendCommandToActiveTab({
|
||||||
name: 'selectedHtml',
|
name: 'selectedHtml',
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
this.clipUrl_click = () => {
|
this.clipUrl_click = () => {
|
||||||
bridge().sendCommandToActiveTab({
|
bridge().sendCommandToActiveTab({
|
||||||
name: 'pageUrl',
|
name: 'pageUrl',
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
this.clipScreenshot_click = async () => {
|
this.clipScreenshot_click = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -137,18 +137,18 @@ class AppComponent extends Component {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.props.dispatch({ type: 'CONTENT_UPLOAD', operation: { uploading: false, success: false, errorMessage: error.message } });
|
this.props.dispatch({ type: 'CONTENT_UPLOAD', operation: { uploading: false, success: false, errorMessage: error.message } });
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
this.clipperServerHelpLink_click = () => {
|
this.clipperServerHelpLink_click = () => {
|
||||||
bridge().tabsCreate({ url: 'https://joplinapp.org/clipper/' });
|
bridge().tabsCreate({ url: 'https://joplinapp.org/clipper/' });
|
||||||
}
|
};
|
||||||
|
|
||||||
this.folderSelect_change = (event) => {
|
this.folderSelect_change = (event) => {
|
||||||
this.props.dispatch({
|
this.props.dispatch({
|
||||||
type: 'SELECTED_FOLDER_SET',
|
type: 'SELECTED_FOLDER_SET',
|
||||||
id: event.target.value,
|
id: event.target.value,
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
this.tagCompChanged = this.tagCompChanged.bind(this);
|
this.tagCompChanged = this.tagCompChanged.bind(this);
|
||||||
this.onAddTagClick = this.onAddTagClick.bind(this);
|
this.onAddTagClick = this.onAddTagClick.bind(this);
|
||||||
@@ -187,10 +187,10 @@ class AppComponent extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async loadContentScripts() {
|
async loadContentScripts() {
|
||||||
await bridge().tabsExecuteScript({file: "/content_scripts/JSDOMParser.js"});
|
await bridge().tabsExecuteScript({file: '/content_scripts/JSDOMParser.js'});
|
||||||
await bridge().tabsExecuteScript({file: "/content_scripts/Readability.js"});
|
await bridge().tabsExecuteScript({file: '/content_scripts/Readability.js'});
|
||||||
await bridge().tabsExecuteScript({file: "/content_scripts/Readability-readerable.js"});
|
await bridge().tabsExecuteScript({file: '/content_scripts/Readability-readerable.js'});
|
||||||
await bridge().tabsExecuteScript({file: "/content_scripts/index.js"});
|
await bridge().tabsExecuteScript({file: '/content_scripts/index.js'});
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
@@ -214,7 +214,7 @@ class AppComponent extends Component {
|
|||||||
if (folder.id === this.props.selectedFolderId) foundSelectedFolderId = true;
|
if (folder.id === this.props.selectedFolderId) foundSelectedFolderId = true;
|
||||||
if (folder.children) searchSelectedFolder(folder.children);
|
if (folder.children) searchSelectedFolder(folder.children);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
searchSelectedFolder(this.props.folders);
|
searchSelectedFolder(this.props.folders);
|
||||||
|
|
||||||
@@ -249,7 +249,7 @@ class AppComponent extends Component {
|
|||||||
return <div style={{padding: 10, fontSize: 12, maxWidth: 200}}>{msg}</div>;
|
return <div style={{padding: 10, fontSize: 12, maxWidth: 200}}>{msg}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const warningComponent = !this.props.warning ? null : <div className="Warning">{ this.props.warning }</div>
|
const warningComponent = !this.props.warning ? null : <div className="Warning">{ this.props.warning }</div>;
|
||||||
|
|
||||||
const hasContent = !!this.props.clippedContent;
|
const hasContent = !!this.props.clippedContent;
|
||||||
const content = this.props.clippedContent;
|
const content = this.props.clippedContent;
|
||||||
@@ -283,7 +283,7 @@ class AppComponent extends Component {
|
|||||||
body_html={content.body_html}
|
body_html={content.body_html}
|
||||||
onTitleChange={this.contentTitle_change}
|
onTitleChange={this.contentTitle_change}
|
||||||
command={content.source_command}
|
command={content.source_command}
|
||||||
/>
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const clipperStatusComp = () => {
|
const clipperStatusComp = () => {
|
||||||
@@ -291,43 +291,43 @@ class AppComponent extends Component {
|
|||||||
const stateToString = function(state) {
|
const stateToString = function(state) {
|
||||||
if (state === 'not_found') return 'Not found';
|
if (state === 'not_found') return 'Not found';
|
||||||
return state.charAt(0).toUpperCase() + state.slice(1);
|
return state.charAt(0).toUpperCase() + state.slice(1);
|
||||||
}
|
};
|
||||||
|
|
||||||
let msg = ''
|
let msg = '';
|
||||||
let led = null;
|
let led = null;
|
||||||
let helpLink = null;
|
let helpLink = null;
|
||||||
|
|
||||||
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);
|
||||||
led = foundState === 'searching' ? led_orange : led_red
|
led = foundState === 'searching' ? led_orange : led_red;
|
||||||
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>;
|
||||||
}
|
};
|
||||||
|
|
||||||
const foldersComp = () => {
|
const foldersComp = () => {
|
||||||
const optionComps = [];
|
const optionComps = [];
|
||||||
|
|
||||||
const nonBreakingSpacify = (s) => {
|
const nonBreakingSpacify = (s) => {
|
||||||
// https://stackoverflow.com/a/24437562/561309
|
// https://stackoverflow.com/a/24437562/561309
|
||||||
return s.replace(/ /g, "\u00a0");
|
return s.replace(/ /g, '\u00a0');
|
||||||
}
|
};
|
||||||
|
|
||||||
const addOptions = (folders, depth) => {
|
const addOptions = (folders, depth) => {
|
||||||
for (let i = 0; i < folders.length; i++) {
|
for (let i = 0; i < folders.length; i++) {
|
||||||
const folder = folders[i];
|
const folder = folders[i];
|
||||||
optionComps.push(<option key={folder.id} value={folder.id}>{nonBreakingSpacify(' '.repeat(depth) + folder.title)}</option>)
|
optionComps.push(<option key={folder.id} value={folder.id}>{nonBreakingSpacify(' '.repeat(depth) + folder.title)}</option>);
|
||||||
if (folder.children) addOptions(folder.children, depth + 1);
|
if (folder.children) addOptions(folder.children, depth + 1);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
addOptions(this.props.folders, 0);
|
addOptions(this.props.folders, 0);
|
||||||
|
|
||||||
@@ -339,7 +339,7 @@ class AppComponent extends Component {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const tagsComp = () => {
|
const tagsComp = () => {
|
||||||
const comps = [];
|
const comps = [];
|
||||||
@@ -363,7 +363,7 @@ class AppComponent extends Component {
|
|||||||
<a className="AddTagButton" href="#" onClick={this.onAddTagClick}>Add tag</a>
|
<a className="AddTagButton" href="#" onClick={this.onAddTagClick}>Add tag</a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
const tagDataListOptions = [];
|
const tagDataListOptions = [];
|
||||||
for (let i = 0; i < this.props.tags.length; i++) {
|
for (let i = 0; i < this.props.tags.length; i++) {
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
const Global = {}
|
const Global = {};
|
||||||
|
|
||||||
Global.browser = function() {
|
Global.browser = function() {
|
||||||
return window.browser;
|
return window.browser;
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = Global;
|
module.exports = Global;
|
@@ -46,7 +46,7 @@ class Bridge {
|
|||||||
if (command.name === 'isProbablyReaderable') {
|
if (command.name === 'isProbablyReaderable') {
|
||||||
this.dispatch({ type: 'IS_PROBABLY_READERABLE', value: command.value });
|
this.dispatch({ type: 'IS_PROBABLY_READERABLE', value: command.value });
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
this.browser_.runtime.onMessage.addListener(this.browser_notify);
|
this.browser_.runtime.onMessage.addListener(this.browser_notify);
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ class Bridge {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
browser.runtime.getBackgroundPage((bgp) => {
|
browser.runtime.getBackgroundPage((bgp) => {
|
||||||
resolve(bgp);
|
resolve(bgp);
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +166,7 @@ class Bridge {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
};
|
||||||
|
|
||||||
if (checkStatus()) return;
|
if (checkStatus()) return;
|
||||||
|
|
||||||
@@ -192,13 +192,13 @@ 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(': ')));
|
||||||
}
|
}
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async tabsQuery(options) {
|
async tabsQuery(options) {
|
||||||
@@ -284,9 +284,9 @@ class Bridge {
|
|||||||
const fetchOptions = {
|
const fetchOptions = {
|
||||||
method: method,
|
method: method,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
if (body) fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
|
if (body) fetchOptions.body = typeof body === 'string' ? body : JSON.stringify(body);
|
||||||
|
|
||||||
@@ -301,7 +301,7 @@ class Bridge {
|
|||||||
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);
|
||||||
@@ -361,6 +361,6 @@ const bridge_ = new Bridge();
|
|||||||
|
|
||||||
const bridge = function() {
|
const bridge = function() {
|
||||||
return bridge_;
|
return bridge_;
|
||||||
}
|
};
|
||||||
|
|
||||||
export { bridge }
|
export { bridge };
|
||||||
|
@@ -31,7 +31,7 @@ const reduxMiddleware = store => next => async (action) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
};
|
||||||
|
|
||||||
function reducer(state = defaultState, action) {
|
function reducer(state = defaultState, action) {
|
||||||
let newState = state;
|
let newState = state;
|
||||||
|
@@ -1,10 +1,8 @@
|
|||||||
const { _ } = require('lib/locale.js');
|
const { BrowserWindow, Tray } = require('electron');
|
||||||
const { BrowserWindow, Menu, Tray } = require('electron');
|
|
||||||
const { shim } = require('lib/shim');
|
const { shim } = require('lib/shim');
|
||||||
const url = require('url')
|
const url = require('url');
|
||||||
const path = require('path')
|
const path = require('path');
|
||||||
const urlUtils = require('lib/urlUtils.js');
|
const { dirname } = require('lib/path-utils');
|
||||||
const { dirname, basename } = require('lib/path-utils');
|
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
|
|
||||||
class ElectronAppWrapper {
|
class ElectronAppWrapper {
|
||||||
@@ -42,7 +40,7 @@ class ElectronAppWrapper {
|
|||||||
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_;
|
||||||
|
|
||||||
@@ -72,13 +70,13 @@ class ElectronAppWrapper {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.win_ = new BrowserWindow(windowOptions)
|
this.win_ = new BrowserWindow(windowOptions);
|
||||||
|
|
||||||
this.win_.loadURL(url.format({
|
this.win_.loadURL(url.format({
|
||||||
pathname: path.join(__dirname, 'index.html'),
|
pathname: path.join(__dirname, 'index.html'),
|
||||||
protocol: 'file:',
|
protocol: 'file:',
|
||||||
slashes: true
|
slashes: true,
|
||||||
}))
|
}));
|
||||||
|
|
||||||
// Uncomment this to view errors if the application does not start
|
// Uncomment this to view errors if the application does not start
|
||||||
if (this.env_ === 'dev') this.win_.webContents.openDevTools();
|
if (this.env_ === 'dev') this.win_.webContents.openDevTools();
|
||||||
@@ -106,7 +104,7 @@ class ElectronAppWrapper {
|
|||||||
this.win_ = null;
|
this.win_ = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
// Let us register listeners on the window, so we can update the state
|
// Let us register listeners on the window, so we can update the state
|
||||||
// automatically (the listeners will be removed when the window is closed)
|
// automatically (the listeners will be removed when the window is closed)
|
||||||
@@ -166,7 +164,7 @@ class ElectronAppWrapper {
|
|||||||
output = '16x16.png';
|
output = '16x16.png';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.env_ === 'dev') output = '16x16-dev.png'
|
if (this.env_ === 'dev') output = '16x16-dev.png';
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@@ -174,15 +172,15 @@ 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);
|
||||||
|
|
||||||
this.tray_.on('click', () => {
|
this.tray_.on('click', () => {
|
||||||
this.window().show();
|
this.window().show();
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Cannot create tray", error);
|
console.error('Cannot create tray', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,15 +225,15 @@ class ElectronAppWrapper {
|
|||||||
|
|
||||||
this.electronApp_.on('before-quit', () => {
|
this.electronApp_.on('before-quit', () => {
|
||||||
this.willQuitApp_ = true;
|
this.willQuitApp_ = true;
|
||||||
})
|
});
|
||||||
|
|
||||||
this.electronApp_.on('window-all-closed', () => {
|
this.electronApp_.on('window-all-closed', () => {
|
||||||
this.electronApp_.quit();
|
this.electronApp_.quit();
|
||||||
})
|
});
|
||||||
|
|
||||||
this.electronApp_.on('activate', () => {
|
this.electronApp_.on('activate', () => {
|
||||||
this.win_.show();
|
this.win_.show();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,7 @@ class InteropServiceHelper {
|
|||||||
|
|
||||||
if (module.target === 'file') {
|
if (module.target === 'file') {
|
||||||
path = bridge().showSaveDialog({
|
path = bridge().showSaveDialog({
|
||||||
filters: [{ name: module.description, extensions: module.fileExtensions}]
|
filters: [{ name: module.description, extensions: module.fileExtensions}],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
path = bridge().showOpenDialog({
|
path = bridge().showOpenDialog({
|
||||||
|
@@ -4,17 +4,13 @@ const { BaseApplication } = require('lib/BaseApplication');
|
|||||||
const { FoldersScreenUtils } = require('lib/folders-screen-utils.js');
|
const { FoldersScreenUtils } = require('lib/folders-screen-utils.js');
|
||||||
const Setting = require('lib/models/Setting.js');
|
const Setting = require('lib/models/Setting.js');
|
||||||
const { shim } = require('lib/shim.js');
|
const { shim } = require('lib/shim.js');
|
||||||
const BaseModel = require('lib/BaseModel.js');
|
|
||||||
const MasterKey = require('lib/models/MasterKey');
|
const MasterKey = require('lib/models/MasterKey');
|
||||||
|
const Note = require('lib/models/Note');
|
||||||
const { _, setLocale } = require('lib/locale.js');
|
const { _, setLocale } = require('lib/locale.js');
|
||||||
const os = require('os');
|
const { Logger } = require('lib/logger.js');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const Tag = require('lib/models/Tag.js');
|
const Tag = require('lib/models/Tag.js');
|
||||||
const { reg } = require('lib/registry.js');
|
const { reg } = require('lib/registry.js');
|
||||||
const { sprintf } = require('sprintf-js');
|
|
||||||
const { JoplinDatabase } = require('lib/joplin-database.js');
|
|
||||||
const { DatabaseDriverNode } = require('lib/database-driver-node.js');
|
|
||||||
const { ElectronAppWrapper } = require('./ElectronAppWrapper');
|
|
||||||
const { defaultState } = require('lib/reducer.js');
|
const { defaultState } = require('lib/reducer.js');
|
||||||
const packageInfo = require('./packageInfo.js');
|
const packageInfo = require('./packageInfo.js');
|
||||||
const AlarmService = require('lib/services/AlarmService.js');
|
const AlarmService = require('lib/services/AlarmService.js');
|
||||||
@@ -28,7 +24,6 @@ const ExternalEditWatcher = require('lib/services/ExternalEditWatcher');
|
|||||||
const { bridge } = require('electron').remote.require('./bridge');
|
const { bridge } = require('electron').remote.require('./bridge');
|
||||||
const { shell } = require('electron');
|
const { shell } = require('electron');
|
||||||
const Menu = bridge().Menu;
|
const Menu = bridge().Menu;
|
||||||
const MenuItem = bridge().MenuItem;
|
|
||||||
const PluginManager = require('lib/services/PluginManager');
|
const PluginManager = require('lib/services/PluginManager');
|
||||||
const RevisionService = require('lib/services/RevisionService');
|
const RevisionService = require('lib/services/RevisionService');
|
||||||
const MigrationService = require('lib/services/MigrationService');
|
const MigrationService = require('lib/services/MigrationService');
|
||||||
@@ -79,6 +74,7 @@ class Application extends BaseApplication {
|
|||||||
case 'NAV_BACK':
|
case 'NAV_BACK':
|
||||||
case 'NAV_GO':
|
case 'NAV_GO':
|
||||||
|
|
||||||
|
{
|
||||||
const goingBack = action.type === 'NAV_BACK';
|
const goingBack = action.type === 'NAV_BACK';
|
||||||
|
|
||||||
if (goingBack && !state.navHistory.length) break;
|
if (goingBack && !state.navHistory.length) break;
|
||||||
@@ -101,8 +97,9 @@ class Application extends BaseApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!goingBack) newNavHistory.push(currentRoute);
|
if (!goingBack) newNavHistory.push(currentRoute);
|
||||||
newState.navHistory = newNavHistory
|
newState.navHistory = newNavHistory;
|
||||||
newState.route = action;
|
newState.route = action;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'WINDOW_CONTENT_SIZE_SET':
|
case 'WINDOW_CONTENT_SIZE_SET':
|
||||||
@@ -113,14 +110,17 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
case 'WINDOW_COMMAND':
|
case 'WINDOW_COMMAND':
|
||||||
|
|
||||||
|
{
|
||||||
newState = Object.assign({}, state);
|
newState = Object.assign({}, state);
|
||||||
let command = Object.assign({}, action);
|
let command = Object.assign({}, action);
|
||||||
delete command.type;
|
delete command.type;
|
||||||
newState.windowCommand = command;
|
newState.windowCommand = command;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'NOTE_VISIBLE_PANES_TOGGLE':
|
case 'NOTE_VISIBLE_PANES_TOGGLE':
|
||||||
|
|
||||||
|
{
|
||||||
let panes = state.noteVisiblePanes.slice();
|
let panes = state.noteVisiblePanes.slice();
|
||||||
if (panes.length === 2) {
|
if (panes.length === 2) {
|
||||||
panes = ['editor'];
|
panes = ['editor'];
|
||||||
@@ -134,6 +134,7 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
newState = Object.assign({}, state);
|
newState = Object.assign({}, state);
|
||||||
newState.noteVisiblePanes = panes;
|
newState.noteVisiblePanes = panes;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'NOTE_VISIBLE_PANES_SET':
|
case 'NOTE_VISIBLE_PANES_SET':
|
||||||
@@ -165,6 +166,7 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
case 'NOTE_FILE_WATCHER_REMOVE':
|
case 'NOTE_FILE_WATCHER_REMOVE':
|
||||||
|
|
||||||
|
{
|
||||||
newState = Object.assign({}, state);
|
newState = Object.assign({}, state);
|
||||||
const idx = newState.watchedNoteFiles.indexOf(action.id);
|
const idx = newState.watchedNoteFiles.indexOf(action.id);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
@@ -172,6 +174,7 @@ class Application extends BaseApplication {
|
|||||||
watchedNoteFiles.splice(idx, 1);
|
watchedNoteFiles.splice(idx, 1);
|
||||||
newState.watchedNoteFiles = watchedNoteFiles;
|
newState.watchedNoteFiles = watchedNoteFiles;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'NOTE_FILE_WATCHER_CLEAR':
|
case 'NOTE_FILE_WATCHER_CLEAR':
|
||||||
@@ -184,10 +187,12 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
case 'EDITOR_SCROLL_PERCENT_SET':
|
case 'EDITOR_SCROLL_PERCENT_SET':
|
||||||
|
|
||||||
|
{
|
||||||
newState = Object.assign({}, state);
|
newState = Object.assign({}, state);
|
||||||
const newPercents = Object.assign({}, newState.lastEditorScrollPercents);
|
const newPercents = Object.assign({}, newState.lastEditorScrollPercents);
|
||||||
newPercents[action.noteId] = action.percent;
|
newPercents[action.noteId] = action.percent;
|
||||||
newState.lastEditorScrollPercents = newPercents;
|
newState.lastEditorScrollPercents = newPercents;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'NOTE_DEVTOOLS_TOGGLE':
|
case 'NOTE_DEVTOOLS_TOGGLE':
|
||||||
@@ -278,7 +283,7 @@ class Application extends BaseApplication {
|
|||||||
click: () => {
|
click: () => {
|
||||||
Setting.setValue(type + '.sortOrder.field', field);
|
Setting.setValue(type + '.sortOrder.field', field);
|
||||||
this.refreshMenu();
|
this.refreshMenu();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +300,7 @@ class Application extends BaseApplication {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return sortItems;
|
return sortItems;
|
||||||
}
|
};
|
||||||
|
|
||||||
const sortNoteItems = sortNoteFolderItems('notes');
|
const sortNoteItems = sortNoteFolderItems('notes');
|
||||||
const sortFolderItems = sortNoteFolderItems('folders');
|
const sortFolderItems = sortNoteFolderItems('folders');
|
||||||
@@ -304,25 +309,25 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
focusItems.push({
|
focusItems.push({
|
||||||
label: _('Sidebar'),
|
label: _('Sidebar'),
|
||||||
click: () => { this.focusElement_('sideBar') },
|
click: () => { this.focusElement_('sideBar'); },
|
||||||
accelerator: 'CommandOrControl+Shift+S',
|
accelerator: 'CommandOrControl+Shift+S',
|
||||||
});
|
});
|
||||||
|
|
||||||
focusItems.push({
|
focusItems.push({
|
||||||
label: _('Note list'),
|
label: _('Note list'),
|
||||||
click: () => { this.focusElement_('noteList') },
|
click: () => { this.focusElement_('noteList'); },
|
||||||
accelerator: 'CommandOrControl+Shift+L',
|
accelerator: 'CommandOrControl+Shift+L',
|
||||||
});
|
});
|
||||||
|
|
||||||
focusItems.push({
|
focusItems.push({
|
||||||
label: _('Note title'),
|
label: _('Note title'),
|
||||||
click: () => { this.focusElement_('noteTitle') },
|
click: () => { this.focusElement_('noteTitle'); },
|
||||||
accelerator: 'CommandOrControl+Shift+N',
|
accelerator: 'CommandOrControl+Shift+N',
|
||||||
});
|
});
|
||||||
|
|
||||||
focusItems.push({
|
focusItems.push({
|
||||||
label: _('Note body'),
|
label: _('Note body'),
|
||||||
click: () => { this.focusElement_('noteBody') },
|
click: () => { this.focusElement_('noteBody'); },
|
||||||
accelerator: 'CommandOrControl+Shift+B',
|
accelerator: 'CommandOrControl+Shift+B',
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -341,7 +346,7 @@ class Application extends BaseApplication {
|
|||||||
screens: ['Main'],
|
screens: ['Main'],
|
||||||
click: async () => {
|
click: async () => {
|
||||||
await InteropServiceHelper.export(this.dispatch.bind(this), module);
|
await InteropServiceHelper.export(this.dispatch.bind(this), module);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
for (let j = 0; j < module.sources.length; j++) {
|
for (let j = 0; j < module.sources.length; j++) {
|
||||||
@@ -356,7 +361,7 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
if (moduleSource === 'file') {
|
if (moduleSource === 'file') {
|
||||||
path = bridge().showOpenDialog({
|
path = bridge().showOpenDialog({
|
||||||
filters: [{ name: module.description, extensions: module.fileExtensions}]
|
filters: [{ name: module.description, extensions: module.fileExtensions}],
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
path = bridge().showOpenDialog({
|
path = bridge().showOpenDialog({
|
||||||
@@ -380,7 +385,7 @@ class Application extends BaseApplication {
|
|||||||
importOptions.destinationFolderId = !module.isNoteArchive && moduleSource === 'file' ? selectedFolderId : null;
|
importOptions.destinationFolderId = !module.isNoteArchive && moduleSource === 'file' ? selectedFolderId : null;
|
||||||
importOptions.onError = (error) => {
|
importOptions.onError = (error) => {
|
||||||
console.warn(error);
|
console.warn(error);
|
||||||
}
|
};
|
||||||
|
|
||||||
const service = new InteropService();
|
const service = new InteropService();
|
||||||
try {
|
try {
|
||||||
@@ -394,7 +399,7 @@ class Application extends BaseApplication {
|
|||||||
type: 'WINDOW_COMMAND',
|
type: 'WINDOW_COMMAND',
|
||||||
name: 'hideModalMessage',
|
name: 'hideModalMessage',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -408,15 +413,15 @@ class Application extends BaseApplication {
|
|||||||
type: 'WINDOW_COMMAND',
|
type: 'WINDOW_COMMAND',
|
||||||
name: 'exportPdf',
|
name: 'exportPdf',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/* We need a dummy entry, otherwise the ternary operator to show a
|
/* We need a dummy entry, otherwise the ternary operator to show a
|
||||||
* menu item only on a specific OS does not work. */
|
* menu item only on a specific OS does not work. */
|
||||||
const noItem = {
|
const noItem = {
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
visible: false
|
visible: false,
|
||||||
}
|
};
|
||||||
|
|
||||||
const syncStatusItem = {
|
const syncStatusItem = {
|
||||||
label: _('Synchronisation status'),
|
label: _('Synchronisation status'),
|
||||||
@@ -425,8 +430,8 @@ class Application extends BaseApplication {
|
|||||||
type: 'NAV_GO',
|
type: 'NAV_GO',
|
||||||
routeName: 'Status',
|
routeName: 'Status',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const newNoteItem = {
|
const newNoteItem = {
|
||||||
label: _('New note'),
|
label: _('New note'),
|
||||||
@@ -437,8 +442,8 @@ class Application extends BaseApplication {
|
|||||||
type: 'WINDOW_COMMAND',
|
type: 'WINDOW_COMMAND',
|
||||||
name: 'newNote',
|
name: 'newNote',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const newTodoItem = {
|
const newTodoItem = {
|
||||||
label: _('New to-do'),
|
label: _('New to-do'),
|
||||||
@@ -449,8 +454,8 @@ class Application extends BaseApplication {
|
|||||||
type: 'WINDOW_COMMAND',
|
type: 'WINDOW_COMMAND',
|
||||||
name: 'newTodo',
|
name: 'newTodo',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const newNotebookItem = {
|
const newNotebookItem = {
|
||||||
label: _('New notebook'),
|
label: _('New notebook'),
|
||||||
@@ -460,8 +465,8 @@ class Application extends BaseApplication {
|
|||||||
type: 'WINDOW_COMMAND',
|
type: 'WINDOW_COMMAND',
|
||||||
name: 'newNotebook',
|
name: 'newNotebook',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const printItem = {
|
const printItem = {
|
||||||
label: _('Print'),
|
label: _('Print'),
|
||||||
@@ -472,8 +477,8 @@ class Application extends BaseApplication {
|
|||||||
type: 'WINDOW_COMMAND',
|
type: 'WINDOW_COMMAND',
|
||||||
name: 'print',
|
name: 'print',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
preferencesItems.push({
|
preferencesItems.push({
|
||||||
label: _('General Options'),
|
label: _('General Options'),
|
||||||
@@ -483,7 +488,7 @@ class Application extends BaseApplication {
|
|||||||
type: 'NAV_GO',
|
type: 'NAV_GO',
|
||||||
routeName: 'Config',
|
routeName: 'Config',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}, {
|
}, {
|
||||||
label: _('Encryption options'),
|
label: _('Encryption options'),
|
||||||
click: () => {
|
click: () => {
|
||||||
@@ -491,7 +496,7 @@ class Application extends BaseApplication {
|
|||||||
type: 'NAV_GO',
|
type: 'NAV_GO',
|
||||||
routeName: 'EncryptionConfig',
|
routeName: 'EncryptionConfig',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}, {
|
}, {
|
||||||
label: _('Web clipper options'),
|
label: _('Web clipper options'),
|
||||||
click: () => {
|
click: () => {
|
||||||
@@ -499,7 +504,7 @@ class Application extends BaseApplication {
|
|||||||
type: 'NAV_GO',
|
type: 'NAV_GO',
|
||||||
routeName: 'ClipperConfig',
|
routeName: 'ClipperConfig',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
toolsItemsFirst.push(syncStatusItem, {
|
toolsItemsFirst.push(syncStatusItem, {
|
||||||
@@ -518,7 +523,7 @@ class Application extends BaseApplication {
|
|||||||
name: 'selectTemplate',
|
name: 'selectTemplate',
|
||||||
noteType: 'note',
|
noteType: 'note',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}, {
|
}, {
|
||||||
label: _('Create to-do from template'),
|
label: _('Create to-do from template'),
|
||||||
visible: templateDirExists,
|
visible: templateDirExists,
|
||||||
@@ -528,7 +533,7 @@ class Application extends BaseApplication {
|
|||||||
name: 'selectTemplate',
|
name: 'selectTemplate',
|
||||||
noteType: 'todo',
|
noteType: 'todo',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}, {
|
}, {
|
||||||
label: _('Insert template'),
|
label: _('Insert template'),
|
||||||
visible: templateDirExists,
|
visible: templateDirExists,
|
||||||
@@ -538,14 +543,14 @@ class Application extends BaseApplication {
|
|||||||
type: 'WINDOW_COMMAND',
|
type: 'WINDOW_COMMAND',
|
||||||
name: 'selectTemplate',
|
name: 'selectTemplate',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}, {
|
}, {
|
||||||
label: _('Open template directory'),
|
label: _('Open template directory'),
|
||||||
click: () => {
|
click: () => {
|
||||||
const templateDir = Setting.value('templateDir');
|
const templateDir = Setting.value('templateDir');
|
||||||
if (!templateDirExists) shim.fsDriver().mkdir(templateDir);
|
if (!templateDirExists) shim.fsDriver().mkdir(templateDir);
|
||||||
shell.openItem(templateDir);
|
shell.openItem(templateDir);
|
||||||
}
|
},
|
||||||
}, {
|
}, {
|
||||||
label: _('Refresh templates'),
|
label: _('Refresh templates'),
|
||||||
click: async () => {
|
click: async () => {
|
||||||
@@ -553,9 +558,9 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
this.store().dispatch({
|
this.store().dispatch({
|
||||||
type: 'TEMPLATE_UPDATE_ALL',
|
type: 'TEMPLATE_UPDATE_ALL',
|
||||||
templates: templates
|
templates: templates,
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const toolsItems = toolsItemsFirst.concat(preferencesItems);
|
const toolsItems = toolsItemsFirst.concat(preferencesItems);
|
||||||
@@ -567,7 +572,7 @@ class Application extends BaseApplication {
|
|||||||
function _showAbout() {
|
function _showAbout() {
|
||||||
const p = packageInfo;
|
const p = packageInfo;
|
||||||
let gitInfo = '';
|
let gitInfo = '';
|
||||||
if ("git" in p) {
|
if ('git' in p) {
|
||||||
gitInfo = _('Revision: %s (%s)', p.git.hash, p.git.branch);
|
gitInfo = _('Revision: %s (%s)', p.git.hash, p.git.branch);
|
||||||
}
|
}
|
||||||
let message = [
|
let message = [
|
||||||
@@ -576,8 +581,8 @@ class Application extends BaseApplication {
|
|||||||
'Copyright © 2016-2019 Laurent Cozic',
|
'Copyright © 2016-2019 Laurent Cozic',
|
||||||
_('%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'), {
|
||||||
@@ -596,34 +601,34 @@ class Application extends BaseApplication {
|
|||||||
submenu: [{
|
submenu: [{
|
||||||
label: _('About Joplin'),
|
label: _('About Joplin'),
|
||||||
visible: shim.isMac() ? true : false,
|
visible: shim.isMac() ? true : false,
|
||||||
click: () => _showAbout()
|
click: () => _showAbout(),
|
||||||
}, {
|
}, {
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
visible: shim.isMac() ? true : false
|
visible: shim.isMac() ? true : false,
|
||||||
}, {
|
}, {
|
||||||
label: _('Preferences...'),
|
label: _('Preferences...'),
|
||||||
visible: shim.isMac() ? true : false,
|
visible: shim.isMac() ? true : false,
|
||||||
submenu: preferencesItems
|
submenu: preferencesItems,
|
||||||
}, {
|
}, {
|
||||||
label: _('Check for updates...'),
|
label: _('Check for updates...'),
|
||||||
visible: shim.isMac() ? true : false,
|
visible: shim.isMac() ? true : false,
|
||||||
click: () => _checkForUpdates(this)
|
click: () => _checkForUpdates(this),
|
||||||
}, {
|
}, {
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
visible: shim.isMac() ? true : false
|
visible: shim.isMac() ? true : false,
|
||||||
},
|
},
|
||||||
shim.isMac() ? noItem : newNoteItem,
|
shim.isMac() ? noItem : newNoteItem,
|
||||||
shim.isMac() ? noItem : newTodoItem,
|
shim.isMac() ? noItem : newTodoItem,
|
||||||
shim.isMac() ? noItem : newNotebookItem, {
|
shim.isMac() ? noItem : newNotebookItem, {
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
visible: shim.isMac() ? false : true
|
visible: shim.isMac() ? false : true,
|
||||||
}, {
|
}, {
|
||||||
label: _('Templates'),
|
label: _('Templates'),
|
||||||
visible: shim.isMac() ? false : true,
|
visible: shim.isMac() ? false : true,
|
||||||
submenu: templateItems,
|
submenu: templateItems,
|
||||||
}, {
|
}, {
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
visible: shim.isMac() ? false : true
|
visible: shim.isMac() ? false : true,
|
||||||
}, {
|
}, {
|
||||||
label: _('Import'),
|
label: _('Import'),
|
||||||
visible: shim.isMac() ? false : true,
|
visible: shim.isMac() ? false : true,
|
||||||
@@ -643,7 +648,7 @@ class Application extends BaseApplication {
|
|||||||
type: 'WINDOW_COMMAND',
|
type: 'WINDOW_COMMAND',
|
||||||
name: 'synchronize',
|
name: 'synchronize',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}, shim.isMac() ? syncStatusItem : noItem, {
|
}, shim.isMac() ? syncStatusItem : noItem, {
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
}, shim.isMac() ? noItem : printItem, {
|
}, shim.isMac() ? noItem : printItem, {
|
||||||
@@ -653,14 +658,14 @@ class Application extends BaseApplication {
|
|||||||
label: _('Hide %s', 'Joplin'),
|
label: _('Hide %s', 'Joplin'),
|
||||||
platforms: ['darwin'],
|
platforms: ['darwin'],
|
||||||
accelerator: 'CommandOrControl+H',
|
accelerator: 'CommandOrControl+H',
|
||||||
click: () => { bridge().electronApp().hide() }
|
click: () => { bridge().electronApp().hide(); },
|
||||||
}, {
|
}, {
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
}, {
|
}, {
|
||||||
label: _('Quit'),
|
label: _('Quit'),
|
||||||
accelerator: 'CommandOrControl+Q',
|
accelerator: 'CommandOrControl+Q',
|
||||||
click: () => { bridge().electronApp().quit() }
|
click: () => { bridge().electronApp().quit(); },
|
||||||
}]
|
}],
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootMenuFileMacOs = {
|
const rootMenuFileMacOs = {
|
||||||
@@ -690,8 +695,8 @@ class Application extends BaseApplication {
|
|||||||
}, {
|
}, {
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
},
|
},
|
||||||
printItem
|
printItem,
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootMenus = {
|
const rootMenus = {
|
||||||
@@ -846,7 +851,7 @@ class Application extends BaseApplication {
|
|||||||
type: 'WINDOW_COMMAND',
|
type: 'WINDOW_COMMAND',
|
||||||
name: 'toggleSidebar',
|
name: 'toggleSidebar',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}, {
|
}, {
|
||||||
label: _('Toggle editor layout'),
|
label: _('Toggle editor layout'),
|
||||||
screens: ['Main'],
|
screens: ['Main'],
|
||||||
@@ -856,7 +861,7 @@ class Application extends BaseApplication {
|
|||||||
type: 'WINDOW_COMMAND',
|
type: 'WINDOW_COMMAND',
|
||||||
name: 'toggleVisiblePanes',
|
name: 'toggleVisiblePanes',
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}, {
|
}, {
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
screens: ['Main'],
|
screens: ['Main'],
|
||||||
@@ -902,14 +907,14 @@ class Application extends BaseApplication {
|
|||||||
submenu: [{
|
submenu: [{
|
||||||
label: _('Website and documentation'),
|
label: _('Website and documentation'),
|
||||||
accelerator: 'F1',
|
accelerator: 'F1',
|
||||||
click () { bridge().openExternal('https://joplinapp.org') }
|
click () { bridge().openExternal('https://joplinapp.org'); },
|
||||||
}, {
|
}, {
|
||||||
label: _('Make a donation'),
|
label: _('Make a donation'),
|
||||||
click () { bridge().openExternal('https://joplinapp.org/donate/') }
|
click () { bridge().openExternal('https://joplinapp.org/donate/'); },
|
||||||
}, {
|
}, {
|
||||||
label: _('Check for updates...'),
|
label: _('Check for updates...'),
|
||||||
visible: shim.isMac() ? false : true,
|
visible: shim.isMac() ? false : true,
|
||||||
click: () => _checkForUpdates(this)
|
click: () => _checkForUpdates(this),
|
||||||
}, {
|
}, {
|
||||||
type: 'separator',
|
type: 'separator',
|
||||||
screens: ['Main'],
|
screens: ['Main'],
|
||||||
@@ -928,8 +933,8 @@ class Application extends BaseApplication {
|
|||||||
}, {
|
}, {
|
||||||
label: _('About Joplin'),
|
label: _('About Joplin'),
|
||||||
visible: shim.isMac() ? false : true,
|
visible: shim.isMac() ? false : true,
|
||||||
click: () => _showAbout()
|
click: () => _showAbout(),
|
||||||
}]
|
}],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -950,7 +955,7 @@ class Application extends BaseApplication {
|
|||||||
output.push(item);
|
output.push(item);
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
};
|
||||||
|
|
||||||
for (const key in rootMenus) {
|
for (const key in rootMenus) {
|
||||||
if (!rootMenus.hasOwnProperty(key)) continue;
|
if (!rootMenus.hasOwnProperty(key)) continue;
|
||||||
@@ -1045,8 +1050,8 @@ class Application extends BaseApplication {
|
|||||||
const contextMenu = Menu.buildFromTemplate([
|
const contextMenu = Menu.buildFromTemplate([
|
||||||
{ label: _('Open %s', app.electronApp().getName()), click: () => { app.window().show(); } },
|
{ label: _('Open %s', app.electronApp().getName()), click: () => { app.window().show(); } },
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
{ label: _('Exit'), click: () => { app.quit() } },
|
{ label: _('Exit'), click: () => { app.quit(); } },
|
||||||
])
|
]);
|
||||||
app.createTray(contextMenu);
|
app.createTray(contextMenu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1095,7 +1100,7 @@ class Application extends BaseApplication {
|
|||||||
AlarmService.setDriver(new AlarmServiceDriverNode({ appName: packageInfo.build.appId }));
|
AlarmService.setDriver(new AlarmServiceDriverNode({ appName: packageInfo.build.appId }));
|
||||||
AlarmService.setLogger(reg.logger());
|
AlarmService.setLogger(reg.logger());
|
||||||
|
|
||||||
reg.setShowErrorMessageBoxHandler((message) => { bridge().showErrorMessageBox(message) });
|
reg.setShowErrorMessageBoxHandler((message) => { bridge().showErrorMessageBox(message); });
|
||||||
|
|
||||||
if (Setting.value('openDevTools')) {
|
if (Setting.value('openDevTools')) {
|
||||||
bridge().window().webContents.openDevTools();
|
bridge().window().webContents.openDevTools();
|
||||||
@@ -1144,14 +1149,14 @@ class Application extends BaseApplication {
|
|||||||
|
|
||||||
this.store().dispatch({
|
this.store().dispatch({
|
||||||
type: 'LOAD_CUSTOM_CSS',
|
type: 'LOAD_CUSTOM_CSS',
|
||||||
css: cssString
|
css: cssString,
|
||||||
});
|
});
|
||||||
|
|
||||||
const templates = await TemplateUtils.loadTemplates(Setting.value('templateDir'));
|
const templates = await TemplateUtils.loadTemplates(Setting.value('templateDir'));
|
||||||
|
|
||||||
this.store().dispatch({
|
this.store().dispatch({
|
||||||
type: 'TEMPLATE_UPDATE_ALL',
|
type: 'TEMPLATE_UPDATE_ALL',
|
||||||
templates: templates
|
templates: templates,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Note: Auto-update currently doesn't work in Linux: it downloads the update
|
// Note: Auto-update currently doesn't work in Linux: it downloads the update
|
||||||
@@ -1161,12 +1166,12 @@ class Application extends BaseApplication {
|
|||||||
if (Setting.value('autoUpdateEnabled')) {
|
if (Setting.value('autoUpdateEnabled')) {
|
||||||
bridge().checkForUpdates(true, bridge().window(), this.checkForUpdateLoggerPath(), { includePreReleases: Setting.value('autoUpdate.includePreReleases') });
|
bridge().checkForUpdates(true, bridge().window(), this.checkForUpdateLoggerPath(), { includePreReleases: Setting.value('autoUpdate.includePreReleases') });
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Initial check on startup
|
// Initial check on startup
|
||||||
setTimeout(() => { runAutoUpdateCheck() }, 5000);
|
setTimeout(() => { runAutoUpdateCheck(); }, 5000);
|
||||||
// Then every x hours
|
// Then every x hours
|
||||||
setInterval(() => { runAutoUpdateCheck() }, 12 * 60 * 60 * 1000);
|
setInterval(() => { runAutoUpdateCheck(); }, 12 * 60 * 60 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateTray();
|
this.updateTray();
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
const { _, setLocale } = require('lib/locale.js');
|
const { _, setLocale } = require('lib/locale.js');
|
||||||
const { dirname } = require('lib/path-utils.js');
|
const { dirname } = require('lib/path-utils.js');
|
||||||
const { Logger } = require('lib/logger.js');
|
|
||||||
|
|
||||||
class Bridge {
|
class Bridge {
|
||||||
|
|
||||||
@@ -65,7 +64,6 @@ class Bridge {
|
|||||||
// Don't use this directly - call one of the showXxxxxxxMessageBox() instead
|
// Don't use this directly - call one of the showXxxxxxxMessageBox() instead
|
||||||
showMessageBox_(window, options) {
|
showMessageBox_(window, options) {
|
||||||
const {dialog} = require('electron');
|
const {dialog} = require('electron');
|
||||||
const nativeImage = require('electron').nativeImage
|
|
||||||
if (!window) window = this.window();
|
if (!window) window = this.window();
|
||||||
return dialog.showMessageBox(window, options);
|
return dialog.showMessageBox(window, options);
|
||||||
}
|
}
|
||||||
@@ -112,11 +110,11 @@ class Bridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openExternal(url) {
|
openExternal(url) {
|
||||||
return require('electron').shell.openExternal(url)
|
return require('electron').shell.openExternal(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
openItem(fullPath) {
|
openItem(fullPath) {
|
||||||
return require('electron').shell.openItem(fullPath)
|
return require('electron').shell.openItem(fullPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
checkForUpdates(inBackground, window, logFilePath, options) {
|
checkForUpdates(inBackground, window, logFilePath, options) {
|
||||||
@@ -139,4 +137,4 @@ function bridge() {
|
|||||||
return bridge_;
|
return bridge_;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { bridge, initBridge }
|
module.exports = { bridge, initBridge };
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
const { dialog } = require('electron')
|
const { dialog } = require('electron');
|
||||||
const { shim } = require('lib/shim');
|
const { shim } = require('lib/shim');
|
||||||
const { Logger } = require('lib/logger.js');
|
const { Logger } = require('lib/logger.js');
|
||||||
const { _ } = require('lib/locale.js');
|
const { _ } = require('lib/locale.js');
|
||||||
@@ -46,7 +46,7 @@ async function fetchLatestRelease(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
json = await response.json();
|
json = await response.json();
|
||||||
if (!json.length) throw new Error('Cannot get latest release info: ' + responseText.substr(0,500));
|
if (!json.length) throw new Error('Cannot get latest release info (JSON)');
|
||||||
json = json[0];
|
json = json[0];
|
||||||
} else {
|
} else {
|
||||||
const response = await fetch('https://api.github.com/repos/laurent22/joplin/releases/latest');
|
const response = await fetch('https://api.github.com/repos/laurent22/joplin/releases/latest');
|
||||||
@@ -124,15 +124,15 @@ function checkForUpdates(inBackground, window, logFilePath, options) {
|
|||||||
type: 'info',
|
type: 'info',
|
||||||
message: _('Current version is up-to-date.'),
|
message: _('Current version is up-to-date.'),
|
||||||
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')],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (buttonIndex === 0) require('electron').shell.openExternal(release.downloadUrl ? release.downloadUrl : release.pageUrl);
|
if (buttonIndex === 0) require('electron').shell.openExternal(release.downloadUrl ? release.downloadUrl : release.pageUrl);
|
||||||
@@ -145,4 +145,4 @@ function checkForUpdates(inBackground, window, logFilePath, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.checkForUpdates = checkForUpdates
|
module.exports.checkForUpdates = checkForUpdates;
|
||||||
|
@@ -24,14 +24,14 @@ try {
|
|||||||
hash = execSync('git log --pretty="%h" -1').toString().trim();
|
hash = execSync('git log --pretty="%h" -1').toString().trim();
|
||||||
}
|
}
|
||||||
catch(err) {
|
catch(err) {
|
||||||
console.warn("Could not get git info", err);
|
console.warn('Could not get git info', err);
|
||||||
}
|
}
|
||||||
if (typeof branch !== 'undefined' && typeof hash !== 'undefined') {
|
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,10 +1,10 @@
|
|||||||
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) => {
|
||||||
let childProcess = exec(command, (error, stdout, stderr) => {
|
exec(command, (error, stdout, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
if (error.signal == 'SIGTERM') {
|
if (error.signal == 'SIGTERM') {
|
||||||
resolve('Process was killed');
|
resolve('Process was killed');
|
||||||
@@ -16,19 +16,11 @@ const execCommand = function(command) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const isLinux = () => {
|
|
||||||
return process && process.platform === 'linux';
|
|
||||||
}
|
|
||||||
|
|
||||||
const isWindows = () => {
|
const isWindows = () => {
|
||||||
return process && process.platform === 'win32';
|
return process && process.platform === 'win32';
|
||||||
}
|
};
|
||||||
|
|
||||||
const isMac = () => {
|
|
||||||
return process && process.platform === 'darwin';
|
|
||||||
}
|
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
// electron-rebuild --arch ia32 && electron-rebuild --arch x64
|
// electron-rebuild --arch ia32 && electron-rebuild --arch x64
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user