diff --git a/ElectronClient/app/InteropServiceHelper.js b/ElectronClient/app/InteropServiceHelper.js
index af0d788e8..91417327a 100644
--- a/ElectronClient/app/InteropServiceHelper.js
+++ b/ElectronClient/app/InteropServiceHelper.js
@@ -1,9 +1,88 @@
const { _ } = require('lib/locale');
const { bridge } = require('electron').remote.require('./bridge');
const InteropService = require('lib/services/InteropService');
+const Setting = require('lib/models/Setting');
+const md5 = require('md5');
+const url = require('url');
+const { shim } = require('lib/shim');
+// const { BrowserWindow } = require('electron');
class InteropServiceHelper {
+ static async exportNoteToHtmlFile(noteId) {
+ const tempFile = `${Setting.value('tempDir')}/${md5(Date.now() + Math.random())}.html`;
+ const exportOptions = {};
+ exportOptions.path = tempFile;
+ exportOptions.format = 'html';
+ exportOptions.target = 'file';
+ exportOptions.sourceNoteIds = [noteId];
+
+ 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 {
+ htmlFile = await this.exportNoteToHtmlFile(noteId);
+
+ const windowOptions = {
+ show: true,
+ };
+
+ win = bridge().newBrowserWindow(windowOptions);
+
+ return new Promise((resolve, reject) => {
+ win.webContents.on('did-finish-load', () => {
+
+ if (target === 'pdf') {
+ win.webContents.printToPDF(options, (error, data) => {
+ cleanup();
+ if (error) reject(error);
+ resolve(data);
+ });
+ } else {
+ win.webContents.print(options, (success) => {
+ // 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) reject(new Error('Could not print'));
+ resolve();
+ });
+ }
+ });
+
+ 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 export(dispatch, module, options = null) {
if (!options) options = {};
diff --git a/ElectronClient/app/bridge.js b/ElectronClient/app/bridge.js
index 4a42a61ea..92f62328b 100644
--- a/ElectronClient/app/bridge.js
+++ b/ElectronClient/app/bridge.js
@@ -1,5 +1,6 @@
const { _, setLocale } = require('lib/locale.js');
const { dirname } = require('lib/path-utils.js');
+const { BrowserWindow } = require('electron');
class Bridge {
@@ -21,6 +22,10 @@ class Bridge {
return this.electronWrapper_.window();
}
+ newBrowserWindow(options) {
+ return new BrowserWindow(options);
+ }
+
windowContentSize() {
if (!this.window()) return { width: 0, height: 0 };
const s = this.window().getContentSize();
diff --git a/ElectronClient/app/gui/NoteText.jsx b/ElectronClient/app/gui/NoteText.jsx
index 7d4843479..3cf078cbc 100644
--- a/ElectronClient/app/gui/NoteText.jsx
+++ b/ElectronClient/app/gui/NoteText.jsx
@@ -7,6 +7,7 @@ const Folder = require('lib/models/Folder.js');
const Tag = require('lib/models/Tag.js');
const { time } = require('lib/time-utils.js');
const Setting = require('lib/models/Setting.js');
+const InteropServiceHelper = require('../InteropServiceHelper.js');
const { IconButton } = require('./IconButton.min.js');
const { urlDecode, substrWithEllipsis } = require('lib/string-utils');
const Toolbar = require('./Toolbar.min.js');
@@ -942,6 +943,8 @@ class NoteTextComponent extends React.Component {
}
webview_domReady() {
+
+ console.info('webview_domReady', this.webviewRef_.current);
if (!this.webviewRef_.current) return;
this.setState({
@@ -1224,11 +1227,6 @@ class NoteTextComponent extends React.Component {
});
}
- // helper function to style the title for printing
- title_(title) {
- return `
${title}
`;
- }
-
async printTo_(target, options) {
if (this.props.selectedNoteIds.length !== 1 || !this.webviewRef_.current) {
throw new Error(_('Only one note can be printed or exported to PDF at a time.'));
@@ -1240,36 +1238,50 @@ class NoteTextComponent extends React.Component {
}
this.isPrinting_ = true;
- const previousBody = this.state.note.body;
- const tempBody = `${this.title_(this.state.note.title)}\n\n${previousBody}`;
- const previousTheme = Setting.value('theme');
- Setting.setValue('theme', Setting.THEME_LIGHT);
- this.lastSetHtml_ = '';
- await this.updateHtml(this.state.note.markup_language, tempBody, { useCustomCss: true });
- this.forceUpdate();
+ // const previousBody = this.state.note.body;
+ // const tempBody = `${this.state.note.title}\n\n${previousBody}`;
- const restoreSettings = async () => {
- Setting.setValue('theme', previousTheme);
- this.lastSetHtml_ = '';
- await this.updateHtml(this.state.note.markup_language, previousBody);
- this.forceUpdate();
- };
+ // const previousTheme = Setting.value('theme');
+ // Setting.setValue('theme', Setting.THEME_LIGHT);
+ // this.lastSetHtml_ = '';
+ // await this.updateHtml(this.state.note.markup_language, tempBody, { useCustomCss: true });
+ // this.forceUpdate();
- setTimeout(() => {
+ // const restoreSettings = async () => {
+ // Setting.setValue('theme', previousTheme);
+ // this.lastSetHtml_ = '';
+ // await this.updateHtml(this.state.note.markup_language, previousBody);
+ // this.forceUpdate();
+ // };
+
+ // Need to save because the interop service reloads the note from the database
+ await this.saveIfNeeded();
+
+ setTimeout(async () => {
if (target === 'pdf') {
- this.webviewRef_.current.wrappedInstance.printToPDF({ printBackground: true, pageSize: Setting.value('export.pdfPageSize'), landscape: Setting.value('export.pdfPageOrientation') === 'landscape' }, (error, data) => {
- restoreSettings();
-
- if (error) {
- bridge().showErrorMessageBox(error.message);
- } else {
- shim.fsDriver().writeFile(options.path, data, 'buffer');
- }
- });
+ try {
+ const pdfData = await InteropServiceHelper.exportNoteToPdf(this.state.note.id, {
+ printBackground: true,
+ pageSize: Setting.value('export.pdfPageSize'),
+ landscape: Setting.value('export.pdfPageOrientation') === 'landscape',
+ });
+ shim.fsDriver().writeFile(options.path, pdfData, 'buffer');
+ } catch (error) {
+ console.error(error);
+ bridge().showErrorMessageBox(error.message);
+ }
} else if (target === 'printer') {
- this.webviewRef_.current.wrappedInstance.print({ printBackground: true });
- restoreSettings();
+ try {
+ await InteropServiceHelper.printNote(this.state.note.id, {
+ printBackground: true,
+ });
+ } catch (error) {
+ console.error(error);
+ bridge().showErrorMessageBox(error.message);
+ }
+
+ // restoreSettings();
}
this.isPrinting_ = false;
}, 100);
diff --git a/ElectronClient/app/gui/NoteTextViewer.jsx b/ElectronClient/app/gui/NoteTextViewer.jsx
index a8325a8f7..ce37a9fcb 100644
--- a/ElectronClient/app/gui/NoteTextViewer.jsx
+++ b/ElectronClient/app/gui/NoteTextViewer.jsx
@@ -5,10 +5,6 @@ class NoteTextViewerComponent extends React.Component {
constructor() {
super();
- this.state = {
- 'html': '',
- };
-
this.initialized_ = false;
this.domReady_ = false;
diff --git a/ReactNativeClient/lib/services/InteropService_Exporter_Html.js b/ReactNativeClient/lib/services/InteropService_Exporter_Html.js
index 1b61ba6ff..6fdb78ca4 100644
--- a/ReactNativeClient/lib/services/InteropService_Exporter_Html.js
+++ b/ReactNativeClient/lib/services/InteropService_Exporter_Html.js
@@ -10,6 +10,7 @@ const MarkupToHtml = require('lib/renderers/MarkupToHtml.js');
const dataurl = require('dataurl');
const { themeStyle } = require('../../theme.js');
const { dirname } = require('lib/path-utils.js');
+const { escapeHtml } = require('lib/string-utils.js');
class InteropService_Exporter_Html extends InteropService_Exporter_Base {
@@ -104,10 +105,23 @@ class InteropService_Exporter_Html extends InteropService_Exporter_Base {
const bodyMd = await this.processNoteResources_(item);
const result = this.markupToHtml_.render(item.markup_language, bodyMd, this.style_, { resources: this.resources_, plainResourceRendering: true });
const noteContent = [];
- if (item.title) noteContent.push(`${item.title}
`);
+ if (item.title) noteContent.push(`${escapeHtml(item.title)}
`);
if (result.html) noteContent.push(result.html);
- await shim.fsDriver().writeFile(noteFilePath, `${noteContent.join('\n\n')}
`, 'utf-8');
+ const fullHtml = `
+
+
+
+
+ ${escapeHtml(item.title)}
+
+
+ ${noteContent.join('\n\n')}
+
+
+ `;
+
+ await shim.fsDriver().writeFile(noteFilePath, fullHtml, 'utf-8');
}
}