mirror of
https://github.com/laurent22/joplin.git
synced 2025-03-29 21:21:15 +02:00
Fixed editing notes
This commit is contained in:
parent
4f1133c59a
commit
dcacebf216
@ -52,8 +52,20 @@ class AppGui {
|
|||||||
|
|
||||||
this.inputMode_ = AppGui.INPUT_MODE_NORMAL;
|
this.inputMode_ = AppGui.INPUT_MODE_NORMAL;
|
||||||
|
|
||||||
|
this.commandCancelCalled_ = false;
|
||||||
|
|
||||||
this.currentShortcutKeys_ = [];
|
this.currentShortcutKeys_ = [];
|
||||||
this.lastShortcutKeyTime_ = 0;
|
this.lastShortcutKeyTime_ = 0;
|
||||||
|
|
||||||
|
cliUtils.setStdout((...object) => {
|
||||||
|
for (let i = 0; i < object.length; i++) {
|
||||||
|
this.widget('console').bufferPush(object[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer() {
|
||||||
|
return this.renderer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
buildUi() {
|
buildUi() {
|
||||||
@ -112,8 +124,10 @@ class AppGui {
|
|||||||
consoleWidget.hStretch = true;
|
consoleWidget.hStretch = true;
|
||||||
consoleWidget.name = 'console';
|
consoleWidget.name = 'console';
|
||||||
consoleWidget.prompt = chalk.green('Joplin') + ' ' + chalk.magenta('>') + ' ';
|
consoleWidget.prompt = chalk.green('Joplin') + ' ' + chalk.magenta('>') + ' ';
|
||||||
consoleWidget.on('accept', (event) => {
|
consoleWidget.on('accept', async (event) => {
|
||||||
this.processCommand(event.input, 'console');
|
consoleWidget.promptVisible = false;
|
||||||
|
await this.processCommand(event.input, 'console');
|
||||||
|
consoleWidget.promptVisible = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
const hLayout = new HLayoutWidget();
|
const hLayout = new HLayoutWidget();
|
||||||
@ -330,11 +344,21 @@ class AppGui {
|
|||||||
return ['ENTER', 'DOWN', 'UP', 'LEFT', 'RIGHT', 'DELETE', 'BACKSPACE', 'ESCAPE', 'TAB', 'SHIFT_TAB'].indexOf(name) >= 0;
|
return ['ENTER', 'DOWN', 'UP', 'LEFT', 'RIGHT', 'DELETE', 'BACKSPACE', 'ESCAPE', 'TAB', 'SHIFT_TAB'].indexOf(name) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fullScreen(enable = true) {
|
||||||
|
if (enable) {
|
||||||
|
this.term().fullscreen();
|
||||||
|
this.term().hideCursor();
|
||||||
|
this.widget('root').invalidate();
|
||||||
|
} else {
|
||||||
|
this.term().fullscreen(false);
|
||||||
|
this.term().showCursor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
const term = this.term();
|
const term = this.term();
|
||||||
|
|
||||||
term.fullscreen();
|
this.fullScreen();
|
||||||
term.hideCursor();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.renderer_.start();
|
this.renderer_.start();
|
||||||
@ -344,12 +368,32 @@ class AppGui {
|
|||||||
term.grabInput();
|
term.grabInput();
|
||||||
|
|
||||||
term.on('key', async (name, matches, data) => {
|
term.on('key', async (name, matches, data) => {
|
||||||
if (name === 'CTRL_C' ) {
|
|
||||||
term.showCursor();
|
if (name === 'CTRL_D') {
|
||||||
term.fullscreen(false);
|
const cmd = this.app().currentCommand();
|
||||||
|
|
||||||
|
if (cmd && cmd.cancellable() && !this.commandCancelCalled_) {
|
||||||
|
this.commandCancelCalled_ = true;
|
||||||
|
await cmd.cancel();
|
||||||
|
this.commandCancelCalled_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fullScreen(false);
|
||||||
await this.app().exit();
|
await this.app().exit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name === 'CTRL_C' ) {
|
||||||
|
const cmd = this.app().currentCommand();
|
||||||
|
if (!cmd || !cmd.cancellable() || this.commandCancelCalled_) {
|
||||||
|
consoleWidget.bufferPush(_('Press Ctrl+D or type "exit" to exit the application'));
|
||||||
|
} else {
|
||||||
|
this.commandCancelCalled_ = true;
|
||||||
|
await cmd.cancel();
|
||||||
|
this.commandCancelCalled_ = false;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const now = (new Date()).getTime();
|
const now = (new Date()).getTime();
|
||||||
|
|
||||||
@ -381,24 +425,20 @@ class AppGui {
|
|||||||
cmd();
|
cmd();
|
||||||
} else {
|
} else {
|
||||||
consoleWidget.bufferPush(cmd);
|
consoleWidget.bufferPush(cmd);
|
||||||
consoleWidget.pause();
|
|
||||||
await this.processCommand(cmd);
|
await this.processCommand(cmd);
|
||||||
consoleWidget.resume();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
this.fullScreen(false);
|
||||||
this.logger().error(error);
|
this.logger().error(error);
|
||||||
term.fullscreen(false);
|
|
||||||
this.term.showCursor();
|
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
process.on('unhandledRejection', (reason, p) => {
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
term.fullscreen(false);
|
this.fullScreen(false);
|
||||||
this.term.showCursor();
|
|
||||||
console.error('Unhandled promise rejection', p, 'reason:', reason);
|
console.error('Unhandled promise rejection', p, 'reason:', reason);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
@ -278,6 +278,11 @@ class Application {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cmd.setForceRender(async () => {
|
||||||
|
this.gui_.widget('root').invalidate();
|
||||||
|
await this.gui_.renderer().forceRender();
|
||||||
|
});
|
||||||
|
|
||||||
cmd.setPrompt(async (message, options) => {
|
cmd.setPrompt(async (message, options) => {
|
||||||
consoleWidget.focus();
|
consoleWidget.focus();
|
||||||
|
|
||||||
@ -384,6 +389,7 @@ class Application {
|
|||||||
this.activeCommand_ = this.findCommandByName(commandName);
|
this.activeCommand_ = this.findCommandByName(commandName);
|
||||||
const cmdArgs = cliUtils.makeCommandArgs(this.activeCommand_, argv);
|
const cmdArgs = cliUtils.makeCommandArgs(this.activeCommand_, argv);
|
||||||
await this.activeCommand_.action(cmdArgs);
|
await this.activeCommand_.action(cmdArgs);
|
||||||
|
this.activeCommand_ = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
currentCommand() {
|
currentCommand() {
|
||||||
|
@ -55,6 +55,14 @@ class BaseCommand {
|
|||||||
if (this.stdout_) this.stdout_(...object);
|
if (this.stdout_) this.stdout_(...object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setForceRender(fn) {
|
||||||
|
this.forceRender_ = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
async forceRender() {
|
||||||
|
if (this.forceRender_) await this.forceRender_();
|
||||||
|
}
|
||||||
|
|
||||||
setPrompt(fn) {
|
setPrompt(fn) {
|
||||||
this.prompt_ = fn;
|
this.prompt_ = fn;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ cliUtils.splitCommandString = function(s) {
|
|||||||
let r = yargParser(s);
|
let r = yargParser(s);
|
||||||
let output = [];
|
let output = [];
|
||||||
for (let i = 0; i < r._.length; i++) {
|
for (let i = 0; i < r._.length; i++) {
|
||||||
let a = r._[i];
|
let a = r._[i].toString();
|
||||||
a = a.replace(/__JOP_DASH_JOP_DASH__/g, '--');
|
a = a.replace(/__JOP_DASH_JOP_DASH__/g, '--');
|
||||||
a = a.replace(/__JOP_DASH__/g, '-');
|
a = a.replace(/__JOP_DASH__/g, '-');
|
||||||
output.push(a);
|
output.push(a);
|
||||||
@ -213,11 +213,15 @@ let redrawStarted_ = false;
|
|||||||
let redrawLastLog_ = null;
|
let redrawLastLog_ = null;
|
||||||
let redrawLastUpdateTime_ = 0;
|
let redrawLastUpdateTime_ = 0;
|
||||||
|
|
||||||
|
cliUtils.setStdout = function(v) {
|
||||||
|
this.stdout_ = v;
|
||||||
|
}
|
||||||
|
|
||||||
cliUtils.redraw = function(s) {
|
cliUtils.redraw = function(s) {
|
||||||
const now = time.unixMs();
|
const now = time.unixMs();
|
||||||
|
|
||||||
if (now - redrawLastUpdateTime_ > 4000) {
|
if (now - redrawLastUpdateTime_ > 4000) {
|
||||||
console.info(s);
|
this.stdout_ (s);
|
||||||
redrawLastUpdateTime_ = now;
|
redrawLastUpdateTime_ = now;
|
||||||
redrawLastLog_ = null;
|
redrawLastLog_ = null;
|
||||||
} else {
|
} else {
|
||||||
@ -231,7 +235,7 @@ cliUtils.redrawDone = function() {
|
|||||||
if (!redrawStarted_) return;
|
if (!redrawStarted_) return;
|
||||||
|
|
||||||
if (redrawLastLog_) {
|
if (redrawLastLog_) {
|
||||||
console.info(redrawLastLog_);
|
this.stdout_(redrawLastLog_);
|
||||||
}
|
}
|
||||||
|
|
||||||
redrawLastLog_ = null;
|
redrawLastLog_ = null;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import { BaseCommand } from './base-command.js';
|
import { BaseCommand } from './base-command.js';
|
||||||
|
import { uuid } from 'lib/uuid.js';
|
||||||
import { app } from './app.js';
|
import { app } from './app.js';
|
||||||
import { _ } from 'lib/locale.js';
|
import { _ } from 'lib/locale.js';
|
||||||
import { Folder } from 'lib/models/folder.js';
|
import { Folder } from 'lib/models/folder.js';
|
||||||
@ -7,6 +8,7 @@ import { Note } from 'lib/models/note.js';
|
|||||||
import { Setting } from 'lib/models/setting.js';
|
import { Setting } from 'lib/models/setting.js';
|
||||||
import { BaseModel } from 'lib/base-model.js';
|
import { BaseModel } from 'lib/base-model.js';
|
||||||
import { cliUtils } from './cli-utils.js';
|
import { cliUtils } from './cli-utils.js';
|
||||||
|
import { time } from 'lib/time-utils.js';
|
||||||
|
|
||||||
class Command extends BaseCommand {
|
class Command extends BaseCommand {
|
||||||
|
|
||||||
@ -20,13 +22,10 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
async action(args) {
|
async action(args) {
|
||||||
let watcher = null;
|
let watcher = null;
|
||||||
let newNote = null;
|
let tempFilePath = null;
|
||||||
|
|
||||||
const onFinishedEditing = async () => {
|
const onFinishedEditing = async () => {
|
||||||
if (watcher) watcher.close();
|
if (tempFilePath) fs.removeSync(tempFilePath);
|
||||||
//app().vorpal().show();
|
|
||||||
newNote = null;
|
|
||||||
this.stdout(_('Done editing.'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const textEditorPath = () => {
|
const textEditorPath = () => {
|
||||||
@ -36,6 +35,10 @@ class Command extends BaseCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Load note or create it if it doesn't exist
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
let title = args['note'];
|
let title = args['note'];
|
||||||
|
|
||||||
if (!app().currentFolder()) throw new Error(_('No active notebook.'));
|
if (!app().currentFolder()) throw new Error(_('No active notebook.'));
|
||||||
@ -44,47 +47,55 @@ class Command extends BaseCommand {
|
|||||||
if (!note) {
|
if (!note) {
|
||||||
const ok = await this.prompt(_('Note does not exist: "%s". Create it?', title));
|
const ok = await this.prompt(_('Note does not exist: "%s". Create it?', title));
|
||||||
if (!ok) return;
|
if (!ok) return;
|
||||||
newNote = await Note.save({ title: title, parent_id: app().currentFolder().id });
|
note = await Note.save({ title: title, parent_id: app().currentFolder().id });
|
||||||
note = await Note.load(newNote.id);
|
note = await Note.load(note.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Create the file to be edited and prepare the editor program arguments
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
let editorPath = textEditorPath();
|
let editorPath = textEditorPath();
|
||||||
let editorArgs = editorPath.split(' ');
|
let editorArgs = editorPath.split(' ');
|
||||||
|
|
||||||
editorPath = editorArgs[0];
|
editorPath = editorArgs[0];
|
||||||
editorArgs = editorArgs.splice(1);
|
editorArgs = editorArgs.splice(1);
|
||||||
|
|
||||||
let content = await Note.serializeForEdit(note);
|
const originalContent = await Note.serializeForEdit(note);
|
||||||
|
|
||||||
let tempFilePath = Setting.value('tempDir') + '/' + Note.systemPath(note);
|
tempFilePath = Setting.value('tempDir') + '/' + uuid.create() + '.md';
|
||||||
editorArgs.push(tempFilePath);
|
editorArgs.push(tempFilePath);
|
||||||
|
|
||||||
const spawn = require('child_process').spawn;
|
await fs.writeFile(tempFilePath, originalContent);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Start editing the file
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
this.logger().info('Disabling fullscreen...');
|
||||||
|
|
||||||
this.stdout(_('Starting to edit note. Close the editor to get back to the prompt.'));
|
this.stdout(_('Starting to edit note. Close the editor to get back to the prompt.'));
|
||||||
|
await this.forceRender();
|
||||||
|
|
||||||
await fs.writeFile(tempFilePath, content);
|
const spawnSync = require('child_process').spawnSync;
|
||||||
|
spawnSync(editorPath, editorArgs, { stdio: 'inherit' });
|
||||||
|
|
||||||
let watchTimeout = null;
|
await this.forceRender();
|
||||||
watcher = fs.watch(tempFilePath, (eventType, filename) => {
|
|
||||||
// We need a timeout because for each change to the file, multiple events are generated.
|
|
||||||
|
|
||||||
if (watchTimeout) return;
|
// -------------------------------------------------------------------------
|
||||||
|
// Save the note and clean up
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
watchTimeout = setTimeout(async () => {
|
const updatedContent = await fs.readFile(tempFilePath, 'utf8');
|
||||||
let updatedNote = await fs.readFile(tempFilePath, 'utf8');
|
if (updatedContent !== originalContent) {
|
||||||
updatedNote = await Note.unserializeForEdit(updatedNote);
|
let updatedNote = await Note.unserializeForEdit(updatedContent);
|
||||||
updatedNote.id = note.id;
|
updatedNote.id = note.id;
|
||||||
await Note.save(updatedNote);
|
await Note.save(updatedNote);
|
||||||
//process.stdout.write('.');
|
this.logger().info('Note has been saved');
|
||||||
watchTimeout = null;
|
}
|
||||||
}, 200);
|
|
||||||
});
|
await onFinishedEditing();
|
||||||
|
|
||||||
const childProcess = spawn(editorPath, editorArgs, { stdio: 'inherit' });
|
|
||||||
childProcess.on('exit', async (error, code) => {
|
|
||||||
await onFinishedEditing();
|
|
||||||
});
|
|
||||||
} catch(error) {
|
} catch(error) {
|
||||||
await onFinishedEditing();
|
await onFinishedEditing();
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -153,7 +153,7 @@ class Command extends BaseCommand {
|
|||||||
|
|
||||||
if (reg.syncHasAuth(target)) {
|
if (reg.syncHasAuth(target)) {
|
||||||
let sync = await reg.synchronizer(target);
|
let sync = await reg.synchronizer(target);
|
||||||
if (sync) sync.cancel();
|
if (sync) await sync.cancel();
|
||||||
} else {
|
} else {
|
||||||
if (this.releaseLockFn_) this.releaseLockFn_();
|
if (this.releaseLockFn_) this.releaseLockFn_();
|
||||||
this.releaseLockFn_ = null;
|
this.releaseLockFn_ = null;
|
||||||
|
@ -49,18 +49,18 @@ if (process.platform === "win32") {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let commandCancelCalled_ = false;
|
// let commandCancelCalled_ = false;
|
||||||
|
|
||||||
process.on("SIGINT", async function() {
|
// process.on("SIGINT", async function() {
|
||||||
const cmd = application.currentCommand();
|
// const cmd = application.currentCommand();
|
||||||
|
|
||||||
if (!cmd || !cmd.cancellable() || commandCancelCalled_) {
|
// if (!cmd || !cmd.cancellable() || commandCancelCalled_) {
|
||||||
process.exit(0);
|
// process.exit(0);
|
||||||
} else {
|
// } else {
|
||||||
commandCancelCalled_ = true;
|
// commandCancelCalled_ = true;
|
||||||
await cmd.cancel();
|
// await cmd.cancel();
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
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
|
||||||
|
@ -39,6 +39,9 @@ msgstr ""
|
|||||||
msgid "Maximise/minimise the console"
|
msgid "Maximise/minimise the console"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Press Ctrl+D or type \"exit\" to exit the application"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "[Cancel]"
|
msgid "[Cancel]"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -172,9 +175,6 @@ msgstr ""
|
|||||||
msgid "Edit note."
|
msgid "Edit note."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Done editing."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"No text editor is defined. Please set it using `config editor <editor-path>`"
|
"No text editor is defined. Please set it using `config editor <editor-path>`"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -46,6 +46,9 @@ msgstr "Créer un carnet."
|
|||||||
msgid "Maximise/minimise the console"
|
msgid "Maximise/minimise the console"
|
||||||
msgstr "Quitter le logiciel."
|
msgstr "Quitter le logiciel."
|
||||||
|
|
||||||
|
msgid "Press Ctrl+D or type \"exit\" to exit the application"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid "[Cancel]"
|
msgid "[Cancel]"
|
||||||
msgstr "Annulation..."
|
msgstr "Annulation..."
|
||||||
@ -189,9 +192,6 @@ msgstr ""
|
|||||||
msgid "Edit note."
|
msgid "Edit note."
|
||||||
msgstr "Editer la note."
|
msgstr "Editer la note."
|
||||||
|
|
||||||
msgid "Done editing."
|
|
||||||
msgstr "Edition terminée."
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"No text editor is defined. Please set it using `config editor <editor-path>`"
|
"No text editor is defined. Please set it using `config editor <editor-path>`"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -744,6 +744,9 @@ msgstr ""
|
|||||||
msgid "Welcome"
|
msgid "Welcome"
|
||||||
msgstr "Bienvenue"
|
msgstr "Bienvenue"
|
||||||
|
|
||||||
|
#~ msgid "Done editing."
|
||||||
|
#~ msgstr "Edition terminée."
|
||||||
|
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#~ msgid "Confirm"
|
#~ msgid "Confirm"
|
||||||
#~ msgstr "Conflits"
|
#~ msgstr "Conflits"
|
||||||
|
@ -39,6 +39,9 @@ msgstr ""
|
|||||||
msgid "Maximise/minimise the console"
|
msgid "Maximise/minimise the console"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Press Ctrl+D or type \"exit\" to exit the application"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "[Cancel]"
|
msgid "[Cancel]"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -172,9 +175,6 @@ msgstr ""
|
|||||||
msgid "Edit note."
|
msgid "Edit note."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Done editing."
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"No text editor is defined. Please set it using `config editor <editor-path>`"
|
"No text editor is defined. Please set it using `config editor <editor-path>`"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -136,11 +136,20 @@ class Synchronizer {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
async cancel() {
|
||||||
if (this.cancelling_ || this.state() == 'idle') return;
|
if (this.cancelling_ || this.state() == 'idle') return;
|
||||||
|
|
||||||
this.logSyncOperation('cancelling', null, null, '');
|
this.logSyncOperation('cancelling', null, null, '');
|
||||||
this.cancelling_ = true;
|
this.cancelling_ = true;
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const iid = setInterval(() => {
|
||||||
|
if (this.state() == 'idle') {
|
||||||
|
clearInterval(iid);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
cancelling() {
|
cancelling() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user