diff --git a/src/index.d.ts b/src/index.d.ts index 5c5d325..c6b87e0 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -9,6 +9,7 @@ declare namespace printJS { fallbackPrintable?: string; type?: PrintTypes; documentTitle?: string; + documentTitleHoldMs?: number; header?: any; headerStyle?: string; footer?: any; diff --git a/src/js/init.js b/src/js/init.js index 8d2515e..b0b7978 100644 --- a/src/js/init.js +++ b/src/js/init.js @@ -35,6 +35,7 @@ export default { frameRemoveDelay: null, printableElement: null, documentTitle: 'Document', + documentTitleHoldMs: 3000, targetStyle: ['clear', 'display', 'width', 'min-width', 'height', 'min-height', 'max-height'], targetStyles: ['border', 'box', 'break', 'text-decoration'], ignoreElements: [], diff --git a/src/js/print.js b/src/js/print.js index 40f9629..cdf6572 100644 --- a/src/js/print.js +++ b/src/js/print.js @@ -1,6 +1,29 @@ import Browser from './browser' import { cleanUp } from './functions' +function guardDocumentTitle (title, holdMs, onDone) { + if (!title) { onDone(); return } + + var originalTitle = document.title + document.title = title + + var titleEl = document.querySelector('title') + var observer = null + + if (titleEl && typeof MutationObserver !== 'undefined') { + observer = new MutationObserver(function () { + if (document.title !== title) document.title = title + }) + observer.observe(titleEl, { characterData: true, childList: true, subtree: true }) + } + + setTimeout(function () { + if (observer) observer.disconnect() + document.title = originalTitle + onDone() + }, holdMs) +} + const Print = { send: (params, printFrame) => { // Append iframe element to document body @@ -51,6 +74,16 @@ const Print = { } function performPrint (iframeElement, params) { + var isPdfWithTitle = params.type === 'pdf' && + params.documentTitle && + params.documentTitle !== 'Document' + + if (isPdfWithTitle) { + guardDocumentTitle(params.documentTitle, params.documentTitleHoldMs || 3000, function () { + cleanUp(params) + }) + } + try { iframeElement.focus() @@ -59,15 +92,15 @@ function performPrint (iframeElement, params) { try { iframeElement.contentWindow.document.execCommand('print', false, null) } catch (e) { - setTimeout(function(){ + setTimeout(function () { iframeElement.contentWindow.print() - },1000) + }, 1000) } } else { // Other browsers - setTimeout(function(){ + setTimeout(function () { iframeElement.contentWindow.print() - },1000) + }, 1000) } } catch (error) { params.onError(error) @@ -78,7 +111,9 @@ function performPrint (iframeElement, params) { iframeElement.style.left = '-1px' } - cleanUp(params) + if (!isPdfWithTitle) { + cleanUp(params) + } } } diff --git a/test/manual/index.html b/test/manual/index.html index 56f154e..5efb031 100644 --- a/test/manual/index.html +++ b/test/manual/index.html @@ -14,6 +14,30 @@ }) } + function printPdfWithDocumentTitle() { + printJS({ + printable: '/test/manual/test.pdf', + type: 'pdf', + documentTitle: 'My Custom Report' + }) + } + + function printPdfWithDocumentTitleAndSimulatedReset() { + // Simulate a framework (React, Vue, etc.) aggressively resetting document.title + var interval = setInterval(function () { + document.title = 'RESET BY FRAMEWORK' + }, 50) + + // Stop the simulation after 5s so it doesn't run forever + setTimeout(function () { clearInterval(interval) }, 5000) + + printJS({ + printable: '/test/manual/test.pdf', + type: 'pdf', + documentTitle: 'Guarded Title Test' + }) + } + function printPdfWithModal() { printJS({ printable: '/test/manual/test.pdf', @@ -288,7 +312,13 @@