mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-06-24 17:05:47 +02:00
Add a 'supportsDownloading' browser option to gate saving/downloading
Introduces a 'supportsDownloading' browser option (defaulting to false)
that lets embedders disable the save/download paths entirely. When
disabled:
- the toolbar and secondary-toolbar download buttons are hidden;
- PDFViewerApplication.{download,save,downloadOrSave} and the
"beforeunload" save prompt bail out early;
- the BaseDownloadManager helpers (download, downloadData,
openOrDownloadData) and the Firefox/generic _triggerDownload
implementations no-op.
This commit is contained in:
parent
2ed018ec2d
commit
ece1e2ed0c
@ -1455,6 +1455,72 @@ describe("PDF viewer", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("Save/download disabled when supportsDownloading is false", () => {
|
||||||
|
let pages;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
pages = await loadAndWait(
|
||||||
|
"tracemonkey.pdf",
|
||||||
|
".textLayer .endOfContent",
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
{ supportsDownloading: false }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await closePages(pages);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("must hide the download buttons and skip save/download", async () => {
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async ([browserName, page]) => {
|
||||||
|
await page.waitForSelector("#downloadButton", { hidden: true });
|
||||||
|
await waitAndClick(page, "#secondaryToolbarToggleButton");
|
||||||
|
await page.waitForSelector("#secondaryDownload", { hidden: true });
|
||||||
|
|
||||||
|
const triggered = await page.evaluate(async () => {
|
||||||
|
const app = window.PDFViewerApplication;
|
||||||
|
const calls = [];
|
||||||
|
const saveDocument = app.pdfDocument.saveDocument.bind(
|
||||||
|
app.pdfDocument
|
||||||
|
);
|
||||||
|
app.pdfDocument.saveDocument = (...args) => {
|
||||||
|
calls.push("saveDocument");
|
||||||
|
return saveDocument(...args);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Each bail-out path dispatches a TESTING-only "downloadskipped"
|
||||||
|
// event, so we can deterministically wait for all four attempts to
|
||||||
|
// run to completion.
|
||||||
|
let skipped = 0;
|
||||||
|
const allSkipped = new Promise(resolve => {
|
||||||
|
app.eventBus.on("downloadskipped", function listener() {
|
||||||
|
if (++skipped === 4) {
|
||||||
|
app.eventBus.off("downloadskipped", listener);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await app.download();
|
||||||
|
await app.save();
|
||||||
|
await app.downloadOrSave();
|
||||||
|
app.eventBus.dispatch("download", { source: null });
|
||||||
|
await allSkipped;
|
||||||
|
|
||||||
|
return { calls, skipped, downloadManager: app.downloadManager };
|
||||||
|
});
|
||||||
|
expect(triggered.downloadManager)
|
||||||
|
.withContext(`In ${browserName}`)
|
||||||
|
.toBeNull();
|
||||||
|
expect(triggered.calls).withContext(`In ${browserName}`).toEqual([]);
|
||||||
|
expect(triggered.skipped).withContext(`In ${browserName}`).toBe(4);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("Pinch-zoom", () => {
|
describe("Pinch-zoom", () => {
|
||||||
let pages;
|
let pages;
|
||||||
|
|
||||||
|
|||||||
36
web/app.js
36
web/app.js
@ -385,6 +385,7 @@ const PDFViewerApplication = {
|
|||||||
maxCanvasPixels: x => parseInt(x, 10),
|
maxCanvasPixels: x => parseInt(x, 10),
|
||||||
spreadModeOnLoad: x => parseInt(x, 10),
|
spreadModeOnLoad: x => parseInt(x, 10),
|
||||||
supportsCaretBrowsingMode: x => x === "true",
|
supportsCaretBrowsingMode: x => x === "true",
|
||||||
|
supportsDownloading: x => x === "true",
|
||||||
viewerCssTheme: x => parseInt(x, 10),
|
viewerCssTheme: x => parseInt(x, 10),
|
||||||
forcePageColors: x => x === "true",
|
forcePageColors: x => x === "true",
|
||||||
pageColorsBackground: x => x,
|
pageColorsBackground: x => x,
|
||||||
@ -434,7 +435,16 @@ const PDFViewerApplication = {
|
|||||||
ignoreDestinationZoom: AppOptions.get("ignoreDestinationZoom"),
|
ignoreDestinationZoom: AppOptions.get("ignoreDestinationZoom"),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const downloadManager = (this.downloadManager = new DownloadManager());
|
const supportsDownloading = AppOptions.get("supportsDownloading");
|
||||||
|
const downloadManager = (this.downloadManager = supportsDownloading
|
||||||
|
? new DownloadManager()
|
||||||
|
: null);
|
||||||
|
if (appConfig.secondaryToolbar?.downloadButton) {
|
||||||
|
appConfig.secondaryToolbar.downloadButton.hidden = !supportsDownloading;
|
||||||
|
}
|
||||||
|
if (appConfig.toolbar?.download) {
|
||||||
|
appConfig.toolbar.download.hidden = !supportsDownloading;
|
||||||
|
}
|
||||||
|
|
||||||
const findController = (this.findController = new PDFFindController({
|
const findController = (this.findController = new PDFFindController({
|
||||||
linkService,
|
linkService,
|
||||||
@ -1311,6 +1321,13 @@ const PDFViewerApplication = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async download() {
|
async download() {
|
||||||
|
if (!this.downloadManager) {
|
||||||
|
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
|
||||||
|
this.eventBus.dispatch("downloadskipped", { source: this });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let data;
|
let data;
|
||||||
try {
|
try {
|
||||||
data = await (this.pdfDocument
|
data = await (this.pdfDocument
|
||||||
@ -1323,6 +1340,13 @@ const PDFViewerApplication = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async save() {
|
async save() {
|
||||||
|
if (!this.downloadManager) {
|
||||||
|
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
|
||||||
|
this.eventBus.dispatch("downloadskipped", { source: this });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._saveInProgress) {
|
if (this._saveInProgress) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1354,6 +1378,13 @@ const PDFViewerApplication = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async downloadOrSave() {
|
async downloadOrSave() {
|
||||||
|
if (!this.downloadManager) {
|
||||||
|
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
|
||||||
|
this.eventBus.dispatch("downloadskipped", { source: this });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// In the Firefox case, this method MUST always trigger a download.
|
// In the Firefox case, this method MUST always trigger a download.
|
||||||
// When the user is closing a modified and unsaved document, we display a
|
// When the user is closing a modified and unsaved document, we display a
|
||||||
// prompt asking for saving or not. In case they save, we must wait for
|
// prompt asking for saving or not. In case they save, we must wait for
|
||||||
@ -2442,6 +2473,9 @@ const PDFViewerApplication = {
|
|||||||
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
|
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!this.downloadManager) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!this.pdfDocument) {
|
if (!this.pdfDocument) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -102,6 +102,11 @@ const defaultOptions = {
|
|||||||
value: true,
|
value: true,
|
||||||
kind: OptionKind.BROWSER,
|
kind: OptionKind.BROWSER,
|
||||||
},
|
},
|
||||||
|
supportsDownloading: {
|
||||||
|
/** @type {boolean} */
|
||||||
|
value: true,
|
||||||
|
kind: OptionKind.BROWSER,
|
||||||
|
},
|
||||||
supportsIntegratedFind: {
|
supportsIntegratedFind: {
|
||||||
/** @type {boolean} */
|
/** @type {boolean} */
|
||||||
value: false,
|
value: false,
|
||||||
|
|||||||
@ -126,7 +126,7 @@ class PDFAttachmentViewer extends BaseTreeViewer {
|
|||||||
: fallbackContent;
|
: fallbackContent;
|
||||||
|
|
||||||
if (content) {
|
if (content) {
|
||||||
this.downloadManager.openOrDownloadData(content, filename);
|
this.downloadManager?.openOrDownloadData(content, filename);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -155,7 +155,10 @@ class PDFOutlineViewer extends BaseTreeViewer {
|
|||||||
const content = await linkService.getAttachmentContent(attachmentId);
|
const content = await linkService.getAttachmentContent(attachmentId);
|
||||||
|
|
||||||
if (content) {
|
if (content) {
|
||||||
this.downloadManager.openOrDownloadData(content, attachment.filename);
|
this.downloadManager?.openOrDownloadData(
|
||||||
|
content,
|
||||||
|
attachment.filename
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user