mirror of
https://github.com/frappe/books.git
synced 2024-11-08 14:50:56 +00:00
incr: move pdf printer to main
- fix pdf printing
This commit is contained in:
parent
4810396434
commit
0951e11cb1
@ -4,12 +4,12 @@ import fs from 'fs/promises';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import databaseManager from '../backend/database/manager';
|
import databaseManager from '../backend/database/manager';
|
||||||
import { Main } from '../main';
|
import { Main } from '../main';
|
||||||
import saveHtmlAsPdf from '../src/saveHtmlAsPdf';
|
|
||||||
import { DatabaseMethod } from '../utils/db/types';
|
import { DatabaseMethod } from '../utils/db/types';
|
||||||
import { DatabaseResponse } from '../utils/ipc/types';
|
import { DatabaseResponse } from '../utils/ipc/types';
|
||||||
import { IPC_ACTIONS } from '../utils/messages';
|
import { IPC_ACTIONS } from '../utils/messages';
|
||||||
import { getUrlAndTokenString, sendError } from './contactMothership';
|
import { getUrlAndTokenString, sendError } from './contactMothership';
|
||||||
import { getLanguageMap } from './getLanguageMap';
|
import { getLanguageMap } from './getLanguageMap';
|
||||||
|
import { saveHtmlAsPdf } from './saveHtmlAsPdf';
|
||||||
|
|
||||||
export default function registerIpcMainActionListeners(main: Main) {
|
export default function registerIpcMainActionListeners(main: Main) {
|
||||||
ipcMain.handle(IPC_ACTIONS.TOGGLE_MAXIMIZE_CURRENT_WINDOW, (event) => {
|
ipcMain.handle(IPC_ACTIONS.TOGGLE_MAXIMIZE_CURRENT_WINDOW, (event) => {
|
||||||
@ -46,7 +46,7 @@ export default function registerIpcMainActionListeners(main: Main) {
|
|||||||
ipcMain.handle(
|
ipcMain.handle(
|
||||||
IPC_ACTIONS.SAVE_HTML_AS_PDF,
|
IPC_ACTIONS.SAVE_HTML_AS_PDF,
|
||||||
async (event, html, savePath) => {
|
async (event, html, savePath) => {
|
||||||
return await saveHtmlAsPdf(html, savePath);
|
return await saveHtmlAsPdf(html, savePath, app);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
56
main/saveHtmlAsPdf.ts
Normal file
56
main/saveHtmlAsPdf.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { App, BrowserWindow } from 'electron';
|
||||||
|
import fs from 'fs/promises';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
const PRINT_OPTIONS = {
|
||||||
|
marginsType: 1, // no margin
|
||||||
|
pageSize: 'A4',
|
||||||
|
printBackground: true,
|
||||||
|
printBackgrounds: true,
|
||||||
|
printSelectionOnly: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function saveHtmlAsPdf(
|
||||||
|
html: string,
|
||||||
|
savePath: string,
|
||||||
|
app: App
|
||||||
|
): Promise<boolean> {
|
||||||
|
/**
|
||||||
|
* Store received html as a file in a tempdir,
|
||||||
|
* this will be loaded into the print view
|
||||||
|
*/
|
||||||
|
const tempRoot = app.getPath('temp');
|
||||||
|
const filename = path.parse(savePath).name;
|
||||||
|
const htmlPath = path.join(tempRoot, `${filename}.html`);
|
||||||
|
await fs.writeFile(htmlPath, html, { encoding: 'utf-8' });
|
||||||
|
|
||||||
|
const printWindow = getInitializedPrintWindow(htmlPath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After the printWindow content is ready, save as pdf and
|
||||||
|
* then close the window and delete the temp html file.
|
||||||
|
*/
|
||||||
|
return await new Promise((resolve) => {
|
||||||
|
printWindow.webContents.once('did-finish-load', () => {
|
||||||
|
printWindow.webContents.printToPDF(PRINT_OPTIONS).then((data) => {
|
||||||
|
fs.writeFile(savePath, data).then(() => {
|
||||||
|
printWindow.close();
|
||||||
|
fs.unlink(htmlPath).then(() => {
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInitializedPrintWindow(printFilePath: string) {
|
||||||
|
const printWindow = new BrowserWindow({
|
||||||
|
width: 595,
|
||||||
|
height: 842,
|
||||||
|
show: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
printWindow.loadFile(printFilePath);
|
||||||
|
return printWindow;
|
||||||
|
}
|
@ -115,23 +115,19 @@
|
|||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"options": [
|
"options": [
|
||||||
{
|
{
|
||||||
"value": "Inter",
|
"value": "Arial",
|
||||||
"label": "Inter"
|
"label": "Arial"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"value": "Times New Roman",
|
"value": "Times New Roman",
|
||||||
"label": "Times New Roman"
|
"label": "Times New Roman"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"value": "Arial",
|
|
||||||
"label": "Arial"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"value": "Courier",
|
"value": "Courier",
|
||||||
"label": "Courier"
|
"label": "Courier"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"default": "Inter"
|
"default": "Arial"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"quickEditFields": [
|
"quickEditFields": [
|
||||||
|
@ -56,6 +56,7 @@ import Button from 'src/components/Button.vue';
|
|||||||
import PageHeader from 'src/components/PageHeader.vue';
|
import PageHeader from 'src/components/PageHeader.vue';
|
||||||
import InvoiceTemplate from 'src/components/SalesInvoice/InvoiceTemplate.vue';
|
import InvoiceTemplate from 'src/components/SalesInvoice/InvoiceTemplate.vue';
|
||||||
import TwoColumnForm from 'src/components/TwoColumnForm.vue';
|
import TwoColumnForm from 'src/components/TwoColumnForm.vue';
|
||||||
|
import { fyo } from 'src/initFyo';
|
||||||
import { makePDF } from 'src/utils/ipcCalls';
|
import { makePDF } from 'src/utils/ipcCalls';
|
||||||
import { IPC_ACTIONS } from 'utils/messages';
|
import { IPC_ACTIONS } from 'utils/messages';
|
||||||
|
|
||||||
@ -77,6 +78,10 @@ export default {
|
|||||||
async mounted() {
|
async mounted() {
|
||||||
this.doc = await fyo.doc.getDoc(this.schemaName, this.name);
|
this.doc = await fyo.doc.getDoc(this.schemaName, this.name);
|
||||||
this.printSettings = await fyo.doc.getSingle('PrintSettings');
|
this.printSettings = await fyo.doc.getSingle('PrintSettings');
|
||||||
|
|
||||||
|
if (fyo.store.isDevelopment) {
|
||||||
|
window.pv = this;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
printTemplate() {
|
printTemplate() {
|
||||||
@ -84,13 +89,33 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
constructPrintDocument() {
|
||||||
|
const html = document.createElement('html');
|
||||||
|
const head = document.createElement('head');
|
||||||
|
const body = document.createElement('body');
|
||||||
|
const style = document.getElementsByTagName('style');
|
||||||
|
const styleTags = Array.from(style)
|
||||||
|
.map((s) => s.outerHTML)
|
||||||
|
.join('\n');
|
||||||
|
|
||||||
|
head.innerHTML = [
|
||||||
|
'<meta charset="UTF-8">',
|
||||||
|
'<title>Print Window</title>',
|
||||||
|
styleTags,
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
body.innerHTML = this.$refs.printContainer.innerHTML;
|
||||||
|
html.append(head, body);
|
||||||
|
return html.outerHTML;
|
||||||
|
},
|
||||||
async makePDF() {
|
async makePDF() {
|
||||||
const savePath = await this.getSavePath();
|
const savePath = await this.getSavePath();
|
||||||
if (!savePath) return;
|
if (!savePath) return;
|
||||||
|
|
||||||
const html = this.$refs.printContainer.innerHTML;
|
|
||||||
fyo.telemetry.log(Verb.Exported, 'SalesInvoice', { extension: 'pdf' });
|
const html = this.constructPrintDocument()
|
||||||
await makePDF(html, savePath);
|
await makePDF(html, savePath);
|
||||||
|
fyo.telemetry.log(Verb.Exported, 'SalesInvoice', { extension: 'pdf' });
|
||||||
},
|
},
|
||||||
async getSavePath() {
|
async getSavePath() {
|
||||||
const options = {
|
const options = {
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Print</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="printTarget"></div>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
@ -1 +0,0 @@
|
|||||||
import './styles/index.css';
|
|
@ -1,59 +0,0 @@
|
|||||||
import { BrowserWindow } from 'electron';
|
|
||||||
import fs from 'fs/promises';
|
|
||||||
import { sleep } from 'utils';
|
|
||||||
|
|
||||||
const PRINT_OPTIONS = {
|
|
||||||
marginsType: 1, // no margin
|
|
||||||
pageSize: 'A4',
|
|
||||||
printBackground: true,
|
|
||||||
printBackgrounds: true,
|
|
||||||
printSelectionOnly: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default async function saveHtmlAsPdf(
|
|
||||||
html: string,
|
|
||||||
savePath: string
|
|
||||||
): Promise<void> {
|
|
||||||
const printWindow = getInitializedPrintWindow();
|
|
||||||
|
|
||||||
printWindow.webContents.executeJavaScript(`
|
|
||||||
document.body.innerHTML = \`${html}\`;
|
|
||||||
`);
|
|
||||||
|
|
||||||
return await new Promise((resolve) => {
|
|
||||||
printWindow.webContents.on('did-finish-load', async () => {
|
|
||||||
await sleep(1); // Required else pdf'll be blank.
|
|
||||||
|
|
||||||
const data = await printWindow.webContents.printToPDF(PRINT_OPTIONS);
|
|
||||||
await fs.writeFile(savePath, data);
|
|
||||||
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getInitializedPrintWindow() {
|
|
||||||
const printWindow = new BrowserWindow({
|
|
||||||
width: 595,
|
|
||||||
height: 842,
|
|
||||||
show: false,
|
|
||||||
webPreferences: {
|
|
||||||
contextIsolation: false,
|
|
||||||
nodeIntegration: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const printWindowUrl = getPrintWindowUrl();
|
|
||||||
printWindow.loadURL(printWindowUrl);
|
|
||||||
return printWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPrintWindowUrl() {
|
|
||||||
// @ts-ignore
|
|
||||||
let url = global.WEBPACK_DEV_SERVER_URL as string | undefined;
|
|
||||||
if (url) {
|
|
||||||
url = url + 'print';
|
|
||||||
} else {
|
|
||||||
url = 'app://./print.html';
|
|
||||||
}
|
|
||||||
return url;
|
|
||||||
}
|
|
@ -26,8 +26,17 @@ export async function showItemInFolder(filePath: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function makePDF(html: string, savePath: string) {
|
export async function makePDF(html: string, savePath: string) {
|
||||||
await ipcRenderer.invoke(IPC_ACTIONS.SAVE_HTML_AS_PDF, html, savePath);
|
const success = await ipcRenderer.invoke(
|
||||||
showExportInFolder(t`Save as PDF Successful`, savePath);
|
IPC_ACTIONS.SAVE_HTML_AS_PDF,
|
||||||
|
html,
|
||||||
|
savePath
|
||||||
|
);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
showExportInFolder(t`Save as PDF Successful`, savePath);
|
||||||
|
} else {
|
||||||
|
showToast({ message: t`Export Failed`, type: 'error' });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function runWindowAction(name: WindowAction) {
|
export async function runWindowAction(name: WindowAction) {
|
||||||
|
@ -32,10 +32,6 @@ module.exports = {
|
|||||||
entry: 'src/renderer.ts',
|
entry: 'src/renderer.ts',
|
||||||
filename: 'index.html',
|
filename: 'index.html',
|
||||||
},
|
},
|
||||||
print: {
|
|
||||||
entry: 'src/print.ts',
|
|
||||||
filename: 'print.html',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
runtimeCompiler: true,
|
runtimeCompiler: true,
|
||||||
lintOnSave: process.env.NODE_ENV !== 'production',
|
lintOnSave: process.env.NODE_ENV !== 'production',
|
||||||
|
Loading…
Reference in New Issue
Block a user