You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-07-16 00:14:34 +02:00
All: Add support for application plugins (#3257)
This commit is contained in:
181
ElectronClient/InteropServiceHelper.ts
Normal file
181
ElectronClient/InteropServiceHelper.ts
Normal file
@ -0,0 +1,181 @@
|
||||
import InteropService from 'lib/services/interop/InteropService';
|
||||
import CommandService from 'lib/services/CommandService';
|
||||
import shim from 'lib/shim';
|
||||
import { ExportOptions, FileSystemItem, Module } from 'lib/services/interop/types';
|
||||
|
||||
import { _ } from 'lib/locale';
|
||||
const bridge = require('electron').remote.require('./bridge').default;
|
||||
const Setting = require('lib/models/Setting').default;
|
||||
const Note = require('lib/models/Note.js');
|
||||
const { friendlySafeFilename } = require('lib/path-utils');
|
||||
const { time } = require('lib/time-utils.js');
|
||||
const md5 = require('md5');
|
||||
const url = require('url');
|
||||
|
||||
interface ExportNoteOptions {
|
||||
customCss?: string,
|
||||
sourceNoteIds?: string[],
|
||||
sourceFolderIds?: string[],
|
||||
printBackground?: boolean,
|
||||
pageSize?: string,
|
||||
landscape?: boolean,
|
||||
}
|
||||
|
||||
export default class InteropServiceHelper {
|
||||
|
||||
private static async exportNoteToHtmlFile(noteId:string, exportOptions:ExportNoteOptions) {
|
||||
const tempFile = `${Setting.value('tempDir')}/${md5(Date.now() + Math.random())}.html`;
|
||||
|
||||
const fullExportOptions:ExportOptions = Object.assign({}, {
|
||||
path: tempFile,
|
||||
format: 'html',
|
||||
target: FileSystemItem.File,
|
||||
sourceNoteIds: [noteId],
|
||||
customCss: '',
|
||||
}, exportOptions);
|
||||
|
||||
const service = InteropService.instance();
|
||||
|
||||
const result = await service.export(fullExportOptions);
|
||||
console.info('Export HTML result: ', result);
|
||||
return tempFile;
|
||||
}
|
||||
|
||||
private static async exportNoteTo_(target:string, noteId:string, options:ExportNoteOptions = {}) {
|
||||
let win:any = null;
|
||||
let htmlFile:string = 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.
|
||||
shim.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:boolean, reason:string) => {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
public static async exportNoteToPdf(noteId:string, options:ExportNoteOptions = {}) {
|
||||
return this.exportNoteTo_('pdf', noteId, options);
|
||||
}
|
||||
|
||||
public static async printNote(noteId:string, options:ExportNoteOptions = {}) {
|
||||
return this.exportNoteTo_('printer', noteId, options);
|
||||
}
|
||||
|
||||
public static async defaultFilename(noteId:string, fileExtension:string) {
|
||||
// Default filename is just the date
|
||||
const date = time.formatMsToLocal(new Date().getTime(), time.dateFormat());
|
||||
let filename = friendlySafeFilename(`${date}`, 100);
|
||||
|
||||
if (noteId) {
|
||||
const note = await Note.load(noteId);
|
||||
// In a rare case the passed note will be null, use the id for filename
|
||||
filename = friendlySafeFilename(note ? note.title : noteId, 100);
|
||||
}
|
||||
|
||||
return `${filename}.${fileExtension}`;
|
||||
}
|
||||
|
||||
public static async export(_dispatch:Function, module:Module, options:ExportNoteOptions = 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];
|
||||
|
||||
CommandService.instance().execute('showModalMessage', { message: _('Exporting to "%s" as "%s" format. Please wait...', path, module.format) });
|
||||
|
||||
const exportOptions: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 = InteropService.instance();
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
CommandService.instance().execute('hideModalMessage');
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user