1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-15 09:04:04 +02:00
joplin/ElectronClient/InteropServiceHelper.js
Laurent Cozic 51732a5adb Desktop: Fixed various bugs and regressions following note editor refactoring
Squashed commit of the following:

commit 5fde36f5c3fa7c7efbce6d81f48fe841c823e88c
Author: Laurent Cozic <laurent@cozic.net>
Date:   Sun May 3 18:43:20 2020 +0100

    Cannot fix for now

commit 251284db3c8b7da6db83f3e06fd19bfdc8b8dd3f
Author: Laurent Cozic <laurent@cozic.net>
Date:   Sun May 3 18:31:08 2020 +0100

    Fixed print to multiple PDFs logic

commit 00d9557996fb984b400fe650594150ae2681e03f
Author: Laurent Cozic <laurent@cozic.net>
Date:   Sun May 3 17:49:20 2020 +0100

    Fixed local search in TinyMCE

commit 46778bf0a79f3bba9ddbc27389fadce4f8944507
Author: Laurent Cozic <laurent@cozic.net>
Date:   Sun May 3 17:37:31 2020 +0100

    Restored note toolbar buttons

commit 3e623c98f0a1cf08bf7d0136f0c8982c5e1ddcd8
Author: Laurent Cozic <laurent@cozic.net>
Date:   Sun May 3 12:30:57 2020 +0100

    Various fixes and moved note toolbar to left of title

commit 790262fe9df5b08d4a619e5244d2906047b39855
Author: Laurent Cozic <laurent@cozic.net>
Date:   Sun May 3 11:21:11 2020 +0100

    Clean up

commit cea30f42e69014ecabda6fa5083199a1ba7b7510
Author: Laurent Cozic <laurent@cozic.net>
Date:   Sun May 3 11:08:23 2020 +0100

    Fixed note loading in TinyMCE
2020-05-03 18:44:49 +01:00

172 lines
5.0 KiB
JavaScript

const { _ } = require('lib/locale');
const { bridge } = require('electron').remote.require('./bridge');
const InteropService = require('lib/services/InteropService');
const Setting = require('lib/models/Setting');
const Note = require('lib/models/Note.js');
const { friendlySafeFilename } = require('lib/path-utils');
const md5 = require('md5');
const url = require('url');
const { shim } = require('lib/shim');
class InteropServiceHelper {
static async exportNoteToHtmlFile(noteId, exportOptions) {
const tempFile = `${Setting.value('tempDir')}/${md5(Date.now() + Math.random())}.html`;
exportOptions = Object.assign({}, {
path: tempFile,
format: 'html',
target: 'file',
sourceNoteIds: [noteId],
customCss: '',
}, exportOptions);
const service = new InteropService();
const result = await service.export(exportOptions);
console.info('Export HTML result: ', result);
return tempFile;
}
static async exportNoteTo_(target, noteId, options = {}) {
let win = null;
let htmlFile = null;
const cleanup = () => {
if (win) win.destroy();
if (htmlFile) shim.fsDriver().remove(htmlFile);
};
try {
const exportOptions = {
customCss: options.customCss ? options.customCss : '',
};
htmlFile = await this.exportNoteToHtmlFile(noteId, exportOptions);
const windowOptions = {
show: false,
};
win = bridge().newBrowserWindow(windowOptions);
return new Promise((resolve, reject) => {
win.webContents.on('did-finish-load', () => {
// did-finish-load will trigger when most assets are done loading, probably
// images, JavaScript and CSS. However it seems it might trigger *before*
// all fonts are loaded, which will break for example Katex rendering.
// So we need to add an additional timer to make sure fonts are loaded
// as it doesn't seem there's any easy way to figure that out.
setTimeout(async () => {
if (target === 'pdf') {
try {
const data = await win.webContents.printToPDF(options);
resolve(data);
} catch (error) {
reject(error);
} finally {
cleanup();
}
} else {
// TODO: it is crashing at this point :(
// Appears to be a Chromium bug: https://github.com/electron/electron/issues/19946
// Maybe can be fixed by doing everything from main process?
// i.e. creating a function `print()` that takes the `htmlFile` variable as input.
win.webContents.print(options, (success, reason) => {
// TODO: This is correct but broken in Electron 4. Need to upgrade to 5+
// It calls the callback right away with "false" even if the document hasn't be print yet.
cleanup();
if (!success && reason !== 'cancelled') reject(new Error(`Could not print: ${reason}`));
resolve();
});
}
}, 2000);
});
win.loadURL(url.format({
pathname: htmlFile,
protocol: 'file:',
slashes: true,
}));
});
} catch (error) {
cleanup();
throw error;
}
}
static async exportNoteToPdf(noteId, options = {}) {
return this.exportNoteTo_('pdf', noteId, options);
}
static async printNote(noteId, options = {}) {
return this.exportNoteTo_('printer', noteId, options);
}
static async defaultFilename(noteId, fileExtension) {
if (!noteId) return '';
const note = await Note.load(noteId);
// In a rare case the passed not will be null, use the id for filename
const filename = friendlySafeFilename(note ? note.title : noteId, 100);
return `${filename}.${fileExtension}`;
}
static async export(dispatch, module, options = null) {
if (!options) options = {};
let path = null;
if (module.target === 'file') {
const noteId = options.sourceNoteIds && options.sourceNoteIds.length ? options.sourceNoteIds[0] : null;
path = bridge().showSaveDialog({
filters: [{ name: module.description, extensions: module.fileExtensions }],
defaultPath: await this.defaultFilename(noteId, module.fileExtensions[0]),
});
} else {
path = bridge().showOpenDialog({
properties: ['openDirectory', 'createDirectory'],
});
}
if (!path || (Array.isArray(path) && !path.length)) return;
if (Array.isArray(path)) path = path[0];
dispatch({
type: 'WINDOW_COMMAND',
name: 'showModalMessage',
message: _('Exporting to "%s" as "%s" format. Please wait...', path, module.format),
});
const exportOptions = {};
exportOptions.path = path;
exportOptions.format = module.format;
exportOptions.modulePath = module.path;
exportOptions.target = module.target;
if (options.sourceFolderIds) exportOptions.sourceFolderIds = options.sourceFolderIds;
if (options.sourceNoteIds) exportOptions.sourceNoteIds = options.sourceNoteIds;
const service = new InteropService();
try {
const result = await service.export(exportOptions);
console.info('Export result: ', result);
} catch (error) {
console.error(error);
bridge().showErrorMessageBox(_('Could not export notes: %s', error.message));
}
dispatch({
type: 'WINDOW_COMMAND',
name: 'hideModalMessage',
});
}
}
module.exports = InteropServiceHelper;