Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

client for JasperReport PDF downloading and embedding #5

Merged
merged 5 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,26 @@ cadenzaClient.show('{embeddingTargetId}', {
- If the embedding target cannot be resolved, a 404 page is shown to the user.
- Cadenza JS does not handle user authentication: If the user is not already logged in, the normal authentication flow of Cadenza will run. By default, the login page would be shown to the user.

#### Show the Generated PDF of a Jasper Report View Directly
Views of type "JasperReports report" can be shown in an iFrame like any other view.
jkissel marked this conversation as resolved.
Show resolved Hide resolved
But there is an additional option to show only the generated PDF without any Cadenza footers or headers.
This is done by setting the "mediaType" option to "application/pdf".

```javascript
cadenzaClient.show('{embeddingTargetId}', {
mediaType: 'application/pdf'
});
```

### Abort (Iframe) Loading

Cadenza JS uses the [AbortController Web API](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) for aborting requests. This is supported by most of the public methods.

```javascript
const abortController = new AbortController();
try {
await cadenzaClient.show('{embeddingTargetId}', { signal: abortController.signal });
catch (error) {
await cadenzaClient.show('{embeddingTargetId}', { signal: abortController.signal });
} catch (error) {
if (error.name === 'AbortError') {
console.log('Iframe loading was aborted');
}
Expand Down Expand Up @@ -205,7 +216,7 @@ const text = await response.text();

<small>API: [CadenzaClient#downloadData](./classes/CadenzaClient.html#downloadData)</small>

Download data from a workbook view in Excel format. This triggers the browser's download dialog.
Download data from a workbook view in Excel, CSV or PDF format. This triggers the browser's download dialog.

```javascript
const button = document.createElement('button');
Expand Down
11 changes: 9 additions & 2 deletions sandbox.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@

const cadenzaClient = cadenza(location.origin + '/trunk', { iframe: 'iframe', debug: true });
const actionHandlers = {
show ({ embeddingTargetId, hideMainHeaderAndFooter, hideWorkbookToolBar }) {
show ({ embeddingTargetId, hideMainHeaderAndFooter, hideWorkbookToolBar, jasperReportAsPdf }) {
cadenzaClient.show(embeddingTargetId, {
hideMainHeaderAndFooter: (hideMainHeaderAndFooter === 'on'),
hideWorkbookToolBar: (hideWorkbookToolBar === 'on')
hideWorkbookToolBar: (hideWorkbookToolBar === 'on'),
...(jasperReportAsPdf === 'on' && { mediaType: 'application/pdf' })
});
},
showMap ({ embeddingTargetId, useMapSrs, geometry, mapExtent, locationFinder }) {
Expand Down Expand Up @@ -163,6 +164,12 @@
<label for="embeddingTargetId">Embedding target ID *</label>
<input name="embeddingTargetId" id="embeddingTargetId" required>
</div>
<div>
<label>
<input type="checkbox" name="jasperReportAsPdf" id="jasperReportAsPdf"/>
Show Jasper Report as PDF
</label>
</div>
<div>
<label>
<input type="checkbox" name="hideMainHeaderAndFooter">
Expand Down
56 changes: 45 additions & 11 deletions src/cadenza.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,16 +162,25 @@ export class CadenzaClient {
* @param {object} [options]
* @param {boolean} [options.hideMainHeaderAndFooter] - Whether to hide the main Cadenza header and footer.
* @param {boolean} [options.hideWorkbookToolBar] - Whether to hide the workbook toolbar.
* @param {string} [options.mediaType] - Set to "application/pdf" for Jasper Report views
* to show the PDF directly, without any Cadenza headers or footers.
* @param {AbortSignal} [options.signal] - A signal to abort the iframe loading
* @return {Promise<void>} A Promise for when the iframe is loaded
* @throws For an invalid source
*/
show(source, { hideMainHeaderAndFooter, hideWorkbookToolBar, signal } = {}) {
show(
source,
{ hideMainHeaderAndFooter, hideWorkbookToolBar, signal, mediaType } = {},
) {
this.#log('CadenzaClient#show', source);
if (mediaType) {
assertSupportedMediaType(mediaType, [MediaType.PDF]);
}
const params = createParams({
hideMainHeaderAndFooter,
hideWorkbookToolBar,
webApplication: this.#webApplication,
mediaType,
});
return this.#show(resolvePath(source), { params, signal });
}
Expand Down Expand Up @@ -421,15 +430,19 @@ export class CadenzaClient {
* Fetch data from a workbook view.
*
* @param {WorkbookViewSource} source - The workbook view to fetch data from
* @param {string} mediaType - The media type to use for the data
* @param {MediaType} mediaType - The media type to use for the data
* @param {object} options - Options
* @param {AbortSignal} [options.signal] - A signal to abort the data fetching
* @return {Promise<Response>} A Promise for the fetch response
* @throws For an invalid workbook view source or media type
*/
fetchData(source, mediaType, { signal } = {}) {
this.#log('CadenzaClient#fetchData', source, mediaType);
assert(validMediaType(mediaType), `Invalid media type: ${mediaType}`);
assertSupportedMediaType(mediaType, [
MediaType.CSV,
MediaType.EXCEL,
MediaType.PDF,
]);
const params = createParams({ mediaType });
return this.#fetch(resolvePath(source), { params, signal });
}
Expand Down Expand Up @@ -462,14 +475,21 @@ export class CadenzaClient {
* _Note:_ The file name, if not provided, is generated from the name of the workbook view and the current date.
*
* @param {WorkbookViewSource} source - The workbook view to download data from
* @param {string} mediaType - The media type to use for the data
* @param {MediaType} mediaType - The media type to use for the data. Allowed are:
* * 'text/csv'
* * 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' (Excel)
* * 'application/pdf' (for Jasper Report views)
jkissel marked this conversation as resolved.
Show resolved Hide resolved
* @param {object} options - Options
* @param {string} [options.fileName] - The file name to use; The file extension is appended by Cadenza.
* @throws For an invalid workbook view source or media type
*/
downloadData(source, mediaType, { fileName }) {
this.#log('CadenzaClient#downloadData', source, mediaType);
assert(validMediaType(mediaType), `Invalid media type: ${mediaType}`);
assertSupportedMediaType(mediaType, [
MediaType.CSV,
MediaType.EXCEL,
MediaType.PDF,
]);
const params = createParams({ fileName, mediaType });
this.#download(resolvePath(source), { params });
}
Expand All @@ -483,6 +503,8 @@ export class CadenzaClient {
const url = this.#createUrl(path, params);
const a = document.createElement('a');
a.href = url.toString();
// causes the file to be downloaded even if the server sends a "Content-disposition: inline" header
a.download = '';
jkissel marked this conversation as resolved.
Show resolved Hide resolved
a.hidden = true;
document.body.append(a);
a.click();
Expand Down Expand Up @@ -611,12 +633,24 @@ function validGeometryType(value) {
].includes(value);
}

/** @param {string} [value] */
function validMediaType(value) {
const CSV = 'text/csv';
const MS_EXCEL_2007 =
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
return value === CSV || value === MS_EXCEL_2007;
/**
* @typedef {string} MediaType - A media type
*
* See {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types}
*/

const MediaType = /** @type {Record<string, MediaType>} */ {
CSV: 'text/csv',
EXCEL: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
PDF: 'application/pdf',
};

/**
* @param {MediaType} type
* @param {MediaType[]} supportedTypes
*/
function assertSupportedMediaType(type, supportedTypes) {
return assert(supportedTypes.includes(type), `Invalid media type: ${type}`);
}

/**
Expand Down