2018-03-01 22:14:06 +02:00
|
|
|
const { _ } = require('lib/locale');
|
|
|
|
const { bridge } = require('electron').remote.require('./bridge');
|
|
|
|
const InteropService = require('lib/services/InteropService');
|
2019-12-17 11:44:48 +02:00
|
|
|
const Setting = require('lib/models/Setting');
|
2020-04-03 01:24:33 +02:00
|
|
|
const Note = require('lib/models/Note.js');
|
|
|
|
const { friendlySafeFilename } = require('lib/path-utils');
|
2019-12-17 11:44:48 +02:00
|
|
|
const md5 = require('md5');
|
|
|
|
const url = require('url');
|
|
|
|
const { shim } = require('lib/shim');
|
2018-03-01 22:14:06 +02:00
|
|
|
|
|
|
|
class InteropServiceHelper {
|
|
|
|
|
2020-01-24 23:46:48 +02:00
|
|
|
static async exportNoteToHtmlFile(noteId, exportOptions) {
|
2019-12-17 11:44:48 +02:00
|
|
|
const tempFile = `${Setting.value('tempDir')}/${md5(Date.now() + Math.random())}.html`;
|
2020-01-24 23:46:48 +02:00
|
|
|
|
|
|
|
exportOptions = Object.assign({}, {
|
|
|
|
path: tempFile,
|
|
|
|
format: 'html',
|
|
|
|
target: 'file',
|
|
|
|
sourceNoteIds: [noteId],
|
|
|
|
customCss: '',
|
|
|
|
}, exportOptions);
|
2019-12-17 11:44:48 +02:00
|
|
|
|
|
|
|
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 {
|
2020-01-24 23:46:48 +02:00
|
|
|
const exportOptions = {
|
|
|
|
customCss: options.customCss ? options.customCss : '',
|
|
|
|
};
|
|
|
|
|
|
|
|
htmlFile = await this.exportNoteToHtmlFile(noteId, exportOptions);
|
2019-12-17 11:44:48 +02:00
|
|
|
|
|
|
|
const windowOptions = {
|
2019-12-30 21:44:15 +02:00
|
|
|
show: false,
|
2019-12-17 11:44:48 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
win = bridge().newBrowserWindow(windowOptions);
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
2020-04-15 00:58:23 +02:00
|
|
|
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 {
|
2020-05-03 19:44:49 +02:00
|
|
|
// 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.
|
2020-05-02 17:41:07 +02:00
|
|
|
|
2020-04-15 00:58:23 +02:00
|
|
|
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();
|
|
|
|
});
|
2019-12-17 13:08:55 +02:00
|
|
|
}
|
2020-04-15 00:58:23 +02:00
|
|
|
}, 2000);
|
|
|
|
|
2019-12-17 11:44:48 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-05-03 19:44:49 +02:00
|
|
|
static async defaultFilename(noteId, fileExtension) {
|
|
|
|
if (!noteId) return '';
|
|
|
|
const note = await Note.load(noteId);
|
2020-04-03 01:24:33 +02:00
|
|
|
// In a rare case the passed not will be null, use the id for filename
|
2020-05-03 19:44:49 +02:00
|
|
|
const filename = friendlySafeFilename(note ? note.title : noteId, 100);
|
|
|
|
return `${filename}.${fileExtension}`;
|
2020-04-03 01:24:33 +02:00
|
|
|
}
|
|
|
|
|
2018-03-01 22:14:06 +02:00
|
|
|
static async export(dispatch, module, options = null) {
|
|
|
|
if (!options) options = {};
|
|
|
|
|
|
|
|
let path = null;
|
|
|
|
|
|
|
|
if (module.target === 'file') {
|
2020-05-03 19:44:49 +02:00
|
|
|
const noteId = options.sourceNoteIds && options.sourceNoteIds.length ? options.sourceNoteIds[0] : null;
|
2018-03-01 22:14:06 +02:00
|
|
|
path = bridge().showSaveDialog({
|
2020-02-05 00:09:34 +02:00
|
|
|
filters: [{ name: module.description, extensions: module.fileExtensions }],
|
2020-05-03 19:44:49 +02:00
|
|
|
defaultPath: await this.defaultFilename(noteId, module.fileExtensions[0]),
|
2018-03-01 22:14:06 +02:00
|
|
|
});
|
|
|
|
} 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;
|
2019-12-15 20:41:13 +02:00
|
|
|
exportOptions.modulePath = module.path;
|
|
|
|
exportOptions.target = module.target;
|
2018-03-01 22:14:06 +02:00
|
|
|
if (options.sourceFolderIds) exportOptions.sourceFolderIds = options.sourceFolderIds;
|
|
|
|
if (options.sourceNoteIds) exportOptions.sourceNoteIds = options.sourceNoteIds;
|
|
|
|
|
|
|
|
const service = new InteropService();
|
|
|
|
|
2019-10-11 20:20:12 +02:00
|
|
|
try {
|
|
|
|
const result = await service.export(exportOptions);
|
|
|
|
console.info('Export result: ', result);
|
|
|
|
} catch (error) {
|
2019-12-17 02:40:25 +02:00
|
|
|
console.error(error);
|
2019-10-11 20:20:12 +02:00
|
|
|
bridge().showErrorMessageBox(_('Could not export notes: %s', error.message));
|
|
|
|
}
|
2018-03-01 22:14:06 +02:00
|
|
|
|
|
|
|
dispatch({
|
|
|
|
type: 'WINDOW_COMMAND',
|
|
|
|
name: 'hideModalMessage',
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-07-30 09:35:42 +02:00
|
|
|
module.exports = InteropServiceHelper;
|