@sapui5/sap.ui.export 1.132.1 → 1.134.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/sap/ui/export/.library +1 -1
- package/src/sap/ui/export/ExportBase.js +1 -1
- package/src/sap/ui/export/ExportHandler.js +1 -1
- package/src/sap/ui/export/ExportUtils.js +10 -20
- package/src/sap/ui/export/PortableDocument.js +299 -50
- package/src/sap/ui/export/Spreadsheet.js +3 -3
- package/src/sap/ui/export/SpreadsheetExport.js +1 -1
- package/src/sap/ui/export/library.js +2 -2
- package/src/sap/ui/export/provider/DataProviderBase.js +1 -1
- package/src/sap/ui/export/util/Filter.js +1 -1
package/package.json
CHANGED
|
@@ -27,7 +27,7 @@ sap.ui.define([
|
|
|
27
27
|
* @class The <code>sap.ui.export.ExportBase</code> class allows you to export table data from a UI5 application to certain formats. This class is an abstract class that requires specific implementations for each file format.
|
|
28
28
|
*
|
|
29
29
|
* @author SAP SE
|
|
30
|
-
* @version 1.
|
|
30
|
+
* @version 1.134.0
|
|
31
31
|
*
|
|
32
32
|
* @since 1.96
|
|
33
33
|
* @alias sap.ui.export.ExportBase
|
|
@@ -28,7 +28,7 @@ sap.ui.define([
|
|
|
28
28
|
* @class The <code>sap.ui.export.ExportHandler</code> class allows you to export table data from an SAPUI5 application.
|
|
29
29
|
*
|
|
30
30
|
* @author SAP SE
|
|
31
|
-
* @version 1.
|
|
31
|
+
* @version 1.134.0
|
|
32
32
|
*
|
|
33
33
|
* @since 1.102
|
|
34
34
|
* @alias sap.ui.export.ExportHandler
|
|
@@ -9,6 +9,7 @@ sap.ui.define([
|
|
|
9
9
|
"sap/base/Log",
|
|
10
10
|
"sap/base/i18n/Formatting",
|
|
11
11
|
"sap/base/i18n/Localization",
|
|
12
|
+
"sap/base/i18n/date/CalendarType",
|
|
12
13
|
"sap/ui/core/Element",
|
|
13
14
|
"sap/ui/core/Fragment",
|
|
14
15
|
"sap/ui/core/InvisibleMessage",
|
|
@@ -23,7 +24,7 @@ sap.ui.define([
|
|
|
23
24
|
"sap/ui/performance/trace/FESRHelper",
|
|
24
25
|
"sap/ui/util/openWindow",
|
|
25
26
|
"sap/ui/VersionInfo"
|
|
26
|
-
], function(library, Filter, BaseConfig, Log, Formatting, Localization, Element, Fragment, InvisibleMessage, Library, Locale, DateFormat, coreLibrary, syncStyleClass, LocaleData, JSONModel, ResourceModel, FESRHelper, openWindow, VersionInfo) {
|
|
27
|
+
], function(library, Filter, BaseConfig, Log, Formatting, Localization, CalendarType, Element, Fragment, InvisibleMessage, Library, Locale, DateFormat, coreLibrary, syncStyleClass, LocaleData, JSONModel, ResourceModel, FESRHelper, openWindow, VersionInfo) {
|
|
27
28
|
"use strict";
|
|
28
29
|
|
|
29
30
|
// eslint-disable-next-line
|
|
@@ -31,7 +32,6 @@ sap.ui.define([
|
|
|
31
32
|
|
|
32
33
|
// Shortcuts
|
|
33
34
|
const ValueState = coreLibrary.ValueState;
|
|
34
|
-
const CalendarType = coreLibrary.CalendarType;
|
|
35
35
|
const FileType = library.FileType;
|
|
36
36
|
const EdmType = library.EdmType;
|
|
37
37
|
const Destination = library.Destination;
|
|
@@ -75,7 +75,7 @@ sap.ui.define([
|
|
|
75
75
|
fileTypeCollection: [],
|
|
76
76
|
fileType: "XLSX",
|
|
77
77
|
destinationCollection: [
|
|
78
|
-
{key: Destination.LOCAL, text: oResourceBundle.getText("DESTINATION_LOCAL")}
|
|
78
|
+
{ key: Destination.LOCAL, text: oResourceBundle.getText("DESTINATION_LOCAL") }
|
|
79
79
|
],
|
|
80
80
|
destination: Destination.LOCAL,
|
|
81
81
|
paperSize: "DIN_A4",
|
|
@@ -88,12 +88,12 @@ sap.ui.define([
|
|
|
88
88
|
capabilities: oExportCapabilities,
|
|
89
89
|
fitToPage: false,
|
|
90
90
|
paperSizeCollection: [
|
|
91
|
-
{key: "DIN_A4", text: oResourceBundle.getText("PAPER_SIZE_A4")},
|
|
92
|
-
{key: "US_LETTER", text: oResourceBundle.getText("PAPER_SIZE_US_LETTER")}
|
|
91
|
+
{ key: "DIN_A4", text: oResourceBundle.getText("PAPER_SIZE_A4") },
|
|
92
|
+
{ key: "US_LETTER", text: oResourceBundle.getText("PAPER_SIZE_US_LETTER") }
|
|
93
93
|
],
|
|
94
94
|
orientationCollection: [
|
|
95
|
-
{key:"LANDSCAPE", text: oResourceBundle.getText("ORIENTATION_LAND")},
|
|
96
|
-
{key:"PORTRAIT", text: oResourceBundle.getText("ORIENTATION_PORT")}
|
|
95
|
+
{ key:"LANDSCAPE", text: oResourceBundle.getText("ORIENTATION_LAND") },
|
|
96
|
+
{ key:"PORTRAIT", text: oResourceBundle.getText("ORIENTATION_PORT") }
|
|
97
97
|
],
|
|
98
98
|
fontSize: 10,
|
|
99
99
|
signature: false,
|
|
@@ -144,7 +144,7 @@ sap.ui.define([
|
|
|
144
144
|
* @class Utilities related to export to enable reuse in integration scenarios (e.g. tables).
|
|
145
145
|
*
|
|
146
146
|
* @author SAP SE
|
|
147
|
-
* @version 1.
|
|
147
|
+
* @version 1.134.0
|
|
148
148
|
*
|
|
149
149
|
* @since 1.59
|
|
150
150
|
* @alias sap.ui.export.ExportUtils
|
|
@@ -246,10 +246,6 @@ sap.ui.define([
|
|
|
246
246
|
* @private
|
|
247
247
|
*/
|
|
248
248
|
getExportSettingsViaDialog: function(mCustomConfig, oExportCapabilities, bRemoteDestination, oOpener, fnCallback) {
|
|
249
|
-
function isPDFFileShareExportEnabled() {
|
|
250
|
-
return document.location.search.includes("sap-ui-xx-pdfFileShareExport=true") && oExportCapabilities?.PDF?.UploadToFileShare;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
249
|
return new Promise(function (fnResolve, fnReject) {
|
|
254
250
|
let oExportSettingsDialog;
|
|
255
251
|
|
|
@@ -306,8 +302,7 @@ sap.ui.define([
|
|
|
306
302
|
return sValue === FileType.XLSX || sValue === FileType.GSHEET;
|
|
307
303
|
},
|
|
308
304
|
isDestinationEnabled: function(sFileType) {
|
|
309
|
-
|
|
310
|
-
return isPDFFileShareExportEnabled() ? sFileType !== FileType.GSHEET : sFileType === FileType.XLSX;
|
|
305
|
+
return oExportCapabilities?.PDF?.UploadToFileShare ? sFileType !== FileType.GSHEET : sFileType === FileType.XLSX;
|
|
311
306
|
},
|
|
312
307
|
hasDestinations: function(aDestinationCollection) {
|
|
313
308
|
return aDestinationCollection.length > 1;
|
|
@@ -357,11 +352,6 @@ sap.ui.define([
|
|
|
357
352
|
|
|
358
353
|
switch (oSelectedItem.getKey()) {
|
|
359
354
|
case FileType.PDF:
|
|
360
|
-
// URL Parameter dependend activation of PDF File Share Export
|
|
361
|
-
if (!isPDFFileShareExportEnabled()) {
|
|
362
|
-
oExportConfigModel.setProperty("/destination", Destination.LOCAL);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
355
|
oExportConfigModel.setProperty("/includeFilterSettings", false);
|
|
366
356
|
fnSetSemanticStepName(oExportConfigModel, oExportSettingsDialog.getBeginButton());
|
|
367
357
|
break;
|
|
@@ -1218,7 +1208,7 @@ sap.ui.define([
|
|
|
1218
1208
|
*
|
|
1219
1209
|
* @param {object} oContext Context object
|
|
1220
1210
|
* @param {string} [oContext.application] Name of the application (default: "SAP UI5")
|
|
1221
|
-
* @param {string} [oContext.version] Application version (default: "1.
|
|
1211
|
+
* @param {string} [oContext.version] Application version (default: "1.134.0")
|
|
1222
1212
|
* @param {string} [oContext.title] Title that will be written to the file (NOT the filename)
|
|
1223
1213
|
* @param {string} [oContext.modifiedBy] Optional user context that will be written to the file
|
|
1224
1214
|
* @param {string} [oContext.sheetName] Name of the data sheet - Maximum length of 31 characters
|
|
@@ -22,11 +22,13 @@ sap.ui.define([
|
|
|
22
22
|
const EdmType = Library.EdmType;
|
|
23
23
|
const Status = Library.Status;
|
|
24
24
|
|
|
25
|
+
const MIME_TYPE = "application/pdf";
|
|
26
|
+
|
|
25
27
|
/**
|
|
26
28
|
* @class The <code>sap.ui.export.PortableDocument</code> class allows you to export table data from a UI5 application to a Portable Document Format (*.PDF) file.
|
|
27
29
|
*
|
|
28
30
|
* @author SAP SE
|
|
29
|
-
* @version 1.
|
|
31
|
+
* @version 1.134.0
|
|
30
32
|
*
|
|
31
33
|
* @since 1.96
|
|
32
34
|
* @alias sap.ui.export.PortableDocument
|
|
@@ -130,9 +132,11 @@ sap.ui.define([
|
|
|
130
132
|
type: "odata",
|
|
131
133
|
version: bV4ODataModel ? 4 : 2,
|
|
132
134
|
dataUrl: oDataUrl.toString(),
|
|
133
|
-
|
|
135
|
+
commonServiceUrl: this._resolveCommonServiceUrl(sServiceUrl),
|
|
136
|
+
serviceUrl: PortableDocument.harmonizeUrl(sServiceUrl),
|
|
134
137
|
headers: bV4ODataModel ? oModel.getHttpHeaders(true) : oModel.getHeaders(),
|
|
135
|
-
count: ExportUtils.getCountFromBinding(oBinding)
|
|
138
|
+
count: ExportUtils.getCountFromBinding(oBinding),
|
|
139
|
+
useBatch: bV4ODataModel || oModel.bUseBatch
|
|
136
140
|
};
|
|
137
141
|
}
|
|
138
142
|
|
|
@@ -149,10 +153,8 @@ sap.ui.define([
|
|
|
149
153
|
*
|
|
150
154
|
* @private
|
|
151
155
|
*/
|
|
152
|
-
PortableDocument.prototype.
|
|
153
|
-
|
|
154
|
-
sCurrentServiceUrl += "/";
|
|
155
|
-
}
|
|
156
|
+
PortableDocument.prototype._resolveCommonServiceUrl = function(sCurrentServiceUrl) {
|
|
157
|
+
sCurrentServiceUrl = PortableDocument.harmonizeUrl(sCurrentServiceUrl);
|
|
156
158
|
|
|
157
159
|
const isRelative = /^[\./]/.test(sCurrentServiceUrl);
|
|
158
160
|
let sReference = this._mCapabilities.DocumentDescriptionReference;
|
|
@@ -241,7 +243,7 @@ sap.ui.define([
|
|
|
241
243
|
if (this._mCapabilities.FitToPage) {
|
|
242
244
|
oDocumentDescription.Format.FitToPage = {
|
|
243
245
|
IsEnabled: mSettings.fitToPage,
|
|
244
|
-
MinimumFontSize:
|
|
246
|
+
MinimumFontSize: 1
|
|
245
247
|
};
|
|
246
248
|
}
|
|
247
249
|
|
|
@@ -284,12 +286,14 @@ sap.ui.define([
|
|
|
284
286
|
}
|
|
285
287
|
}
|
|
286
288
|
|
|
289
|
+
/* FileShare */
|
|
287
290
|
if (this._mCapabilities.UploadToFileShare && this._mCloudFileInfo) {
|
|
288
291
|
oDocumentDescription.FileName = this._mCloudFileInfo.FileShareItemName;
|
|
289
292
|
oDocumentDescription.FileShare = {
|
|
290
293
|
Repository: this._mCloudFileInfo.FileShare,
|
|
291
294
|
Folder: this._mCloudFileInfo.ParentFileShareItem
|
|
292
295
|
};
|
|
296
|
+
mSettings.dataSource.headers["SAP-Upload-To-File-Share"] = true;
|
|
293
297
|
}
|
|
294
298
|
|
|
295
299
|
/* Eliminate duplicate or unknown columns before adding them to the DocumentDescription */
|
|
@@ -360,7 +364,7 @@ sap.ui.define([
|
|
|
360
364
|
const iVersion = oDataSource.version || 2;
|
|
361
365
|
|
|
362
366
|
return iVersion === 4 ? new ODataModel({
|
|
363
|
-
serviceUrl: oDataSource.
|
|
367
|
+
serviceUrl: oDataSource.commonServiceUrl
|
|
364
368
|
}) : this._oModel;
|
|
365
369
|
};
|
|
366
370
|
|
|
@@ -481,40 +485,26 @@ sap.ui.define([
|
|
|
481
485
|
const oModel = this._getModel(oDataSource);
|
|
482
486
|
const sPath = "/" + this._getEntitySetName(oDataSource);
|
|
483
487
|
|
|
484
|
-
if (!oModel
|
|
485
|
-
|
|
488
|
+
if (!oModel?.isA(["sap.ui.model.odata.v4.ODataModel", "sap.ui.model.odata.v2.ODataModel"])) {
|
|
489
|
+
throw new Error("Unsupported Model");
|
|
486
490
|
}
|
|
487
491
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
const oBinding = oModel.bindList(sPath);
|
|
492
|
-
|
|
493
|
-
oBinding.attachCreateCompleted((oEvent) => {
|
|
494
|
-
if (oEvent.getParameter("success")) {
|
|
495
|
-
fnResolve(oEvent.getParameter("context").getObject()["Id"]);
|
|
496
|
-
} else {
|
|
497
|
-
fnReject();
|
|
498
|
-
}
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
oBinding.create(oDocumentDescription);
|
|
502
|
-
} else {
|
|
503
|
-
const bUseBatch = oModel.bUseBatch;
|
|
492
|
+
if (oModel.isA("sap.ui.model.odata.v4.ODataModel")) {
|
|
493
|
+
const oBinding = oModel.bindList(sPath);
|
|
494
|
+
const oContext = oBinding.create(oDocumentDescription);
|
|
504
495
|
|
|
505
|
-
|
|
496
|
+
return oContext.created().then(() => oContext.getObject()["Id"]);
|
|
497
|
+
} else {
|
|
498
|
+
return new Promise((fnResolve, fnReject) => {
|
|
506
499
|
oModel.create(sPath, oDocumentDescription, {
|
|
500
|
+
groupId: "documentDescription",
|
|
507
501
|
success: (oData) => {
|
|
508
|
-
oModel.setUseBatch(bUseBatch);
|
|
509
502
|
fnResolve(oData["Id"]);
|
|
510
503
|
},
|
|
511
|
-
error:
|
|
512
|
-
oModel.setUseBatch(bUseBatch);
|
|
513
|
-
fnReject(oError);
|
|
514
|
-
}
|
|
504
|
+
error: fnReject
|
|
515
505
|
});
|
|
516
|
-
}
|
|
517
|
-
}
|
|
506
|
+
});
|
|
507
|
+
}
|
|
518
508
|
};
|
|
519
509
|
|
|
520
510
|
/**
|
|
@@ -551,9 +541,9 @@ sap.ui.define([
|
|
|
551
541
|
this._request = new AbortController();
|
|
552
542
|
|
|
553
543
|
const sDocumentDescriptionId = await this.postDocumentDescription(oDocumentDescription, mSettings.dataSource);
|
|
554
|
-
const
|
|
544
|
+
const oPDFBlob = await this.sendRequest(mSettings.dataSource, sDocumentDescriptionId);
|
|
555
545
|
|
|
556
|
-
ExportUtils.saveAsFile(
|
|
546
|
+
ExportUtils.saveAsFile(oPDFBlob, mSettings.fileName);
|
|
557
547
|
ExportUtils.announceExportStatus(Status.FINISHED, { assertive: true });
|
|
558
548
|
} catch (oError) {
|
|
559
549
|
PortableDocument.showErrorMessage(oError);
|
|
@@ -565,30 +555,31 @@ sap.ui.define([
|
|
|
565
555
|
/**
|
|
566
556
|
* Requests the generated PDF via HTTP GET from the OData service.
|
|
567
557
|
*
|
|
568
|
-
* @param {
|
|
558
|
+
* @param {object} oDataSource DataSource settings of the export configuration
|
|
559
|
+
* @param {string} oDataSource.dataUrl Absolute data URL of the OData entity that should be exported as PDF
|
|
569
560
|
* @param {string} sDocumentDescriptionId GUID of the DocumentDescription that should be used for creating the PDF
|
|
570
561
|
* @returns {Promise} A Promise that gets resolved after the XHR request
|
|
571
562
|
*
|
|
572
563
|
* @private
|
|
573
564
|
*/
|
|
574
|
-
PortableDocument.prototype.sendRequest = async function(
|
|
565
|
+
PortableDocument.prototype.sendRequest = async function(oDataSource, sDocumentDescriptionId) {
|
|
575
566
|
if (this._request?.signal.aborted) {
|
|
576
567
|
throw null; // Explicitly reject the Promise without an error to indicate prior user cancellation
|
|
577
568
|
}
|
|
578
569
|
|
|
579
|
-
|
|
570
|
+
oDataSource.dataUrl = this._applyResultSize(oDataSource.dataUrl);
|
|
571
|
+
|
|
572
|
+
const oRequest = oDataSource.useBatch ? PortableDocument.createBatchRequest(oDataSource, sDocumentDescriptionId, this._request) : PortableDocument.createGetRequest(oDataSource, sDocumentDescriptionId, this._request);
|
|
580
573
|
|
|
581
574
|
try {
|
|
582
|
-
|
|
583
|
-
signal: this._request?.signal,
|
|
584
|
-
headers: {
|
|
585
|
-
"Accept": this.getMimeType(),
|
|
586
|
-
"SAP-Document-Description-Id": sDocumentDescriptionId
|
|
587
|
-
}
|
|
588
|
-
});
|
|
575
|
+
let response = await fetch(oRequest);
|
|
589
576
|
|
|
590
|
-
if (
|
|
591
|
-
|
|
577
|
+
if (oDataSource.useBatch) {
|
|
578
|
+
response = await PortableDocument.getBatchResponse(response);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if (response.status === 301 && response.headers.has("Location")) {
|
|
582
|
+
openWindow(response.headers.get("Location"), "_blank");
|
|
592
583
|
return undefined;
|
|
593
584
|
}
|
|
594
585
|
|
|
@@ -606,6 +597,264 @@ sap.ui.define([
|
|
|
606
597
|
}
|
|
607
598
|
};
|
|
608
599
|
|
|
600
|
+
/**
|
|
601
|
+
* Ensures that the given URL ends with a forward slash.
|
|
602
|
+
*
|
|
603
|
+
* @param {string} sUrl URL that is harmonized
|
|
604
|
+
*
|
|
605
|
+
* @returns {string} URL that ends with a forward slash
|
|
606
|
+
* @static
|
|
607
|
+
* @private
|
|
608
|
+
*/
|
|
609
|
+
PortableDocument.harmonizeUrl = function(sUrl) {
|
|
610
|
+
return sUrl.endsWith("/") ? sUrl : sUrl + "/";
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Creates <code>Request</code> with method GET for the given <code>dataSource</code> and <code>SAP-Document-Description-Id</code>.
|
|
615
|
+
*
|
|
616
|
+
* @param {object} oDataSource <code>DataSource</code> settings of the export configuration
|
|
617
|
+
* @param {string} sDocumentDescriptionId GUID of the <code>DocumentDescription</code> that is used for creating the PDF
|
|
618
|
+
* @param {AbortController} oAbortController <code>AbortController</code> instance that is used to cancel the request
|
|
619
|
+
*
|
|
620
|
+
* @returns {Request} Request object that is used to fetch the PDF document
|
|
621
|
+
* @static
|
|
622
|
+
* @private
|
|
623
|
+
*/
|
|
624
|
+
PortableDocument.createGetRequest = function(oDataSource, sDocumentDescriptionId, oAbortController) {
|
|
625
|
+
const oHeaders = new Headers(oDataSource.headers);
|
|
626
|
+
|
|
627
|
+
oHeaders.set("Accept", MIME_TYPE);
|
|
628
|
+
oHeaders.set("SAP-Document-Description-Id", sDocumentDescriptionId);
|
|
629
|
+
|
|
630
|
+
return new Request(oDataSource.dataUrl, {
|
|
631
|
+
signal: oAbortController.signal,
|
|
632
|
+
headers: oHeaders
|
|
633
|
+
});
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Creates a $batch request with a single GET request for the given <code>dataSource</code> and <code>SAP-Document-Description-Id</code>.
|
|
638
|
+
*
|
|
639
|
+
* @param {object} oDataSource DataSource settings of the export configuration
|
|
640
|
+
* @param {string} sDocumentDescriptionId GUID of the DocumentDescription that is used for creating the PDF
|
|
641
|
+
* @param {AbortController} oAbortController AbortController instance that is used to cancel the request
|
|
642
|
+
*
|
|
643
|
+
* @returns {Request} Request object that is used to fetch the PDF document
|
|
644
|
+
* @static
|
|
645
|
+
* @private
|
|
646
|
+
*/
|
|
647
|
+
PortableDocument.createBatchRequest = function(oDataSource, sDocumentDescriptionId, oAbortController) {
|
|
648
|
+
const sUrl = oDataSource.dataUrl.split(oDataSource.serviceUrl)[1];
|
|
649
|
+
const sBoundary = "batch_" + PortableDocument._createGuid();
|
|
650
|
+
const oHeaders = new Headers(oDataSource.headers);
|
|
651
|
+
|
|
652
|
+
/* Header adjustments for inner request */
|
|
653
|
+
oHeaders.set("Accept", MIME_TYPE);
|
|
654
|
+
oHeaders.set("SAP-Document-Description-Id", sDocumentDescriptionId);
|
|
655
|
+
|
|
656
|
+
const sBody = PortableDocument.createRequestBody(sUrl, sBoundary, oHeaders);
|
|
657
|
+
|
|
658
|
+
/* Header adjustments for outer request */
|
|
659
|
+
oHeaders.set("Accept", "multipart/mixed");
|
|
660
|
+
oHeaders.set("Content-Type", "multipart/mixed;boundary=" + sBoundary);
|
|
661
|
+
oHeaders.delete("SAP-Document-Description-Id");
|
|
662
|
+
oHeaders.delete("SAP-Upload-To-File-Share");
|
|
663
|
+
|
|
664
|
+
return new Request(oDataSource.serviceUrl + "$batch", {
|
|
665
|
+
body: sBody,
|
|
666
|
+
cache: "no-store",
|
|
667
|
+
headers: oHeaders,
|
|
668
|
+
method: "POST",
|
|
669
|
+
signal: oAbortController.signal
|
|
670
|
+
});
|
|
671
|
+
};
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* Creates the request body for a $batch request.
|
|
675
|
+
*
|
|
676
|
+
* @param {string} sUrl The URL that is requested
|
|
677
|
+
* @param {string} sBoundary The boundary id for the inner request
|
|
678
|
+
* @param {Headers} oHeaders The headers that are sent with the request
|
|
679
|
+
*
|
|
680
|
+
* @returns {string} The request body
|
|
681
|
+
* @static
|
|
682
|
+
* @private
|
|
683
|
+
*/
|
|
684
|
+
PortableDocument.createRequestBody = function(sUrl, sBoundary, oHeaders) {
|
|
685
|
+
const aBody = [];
|
|
686
|
+
|
|
687
|
+
aBody.push("--" + sBoundary);
|
|
688
|
+
aBody.push("Content-Type: application/http");
|
|
689
|
+
aBody.push("Content-Transfer-Encoding: binary");
|
|
690
|
+
aBody.push("");
|
|
691
|
+
aBody.push(`GET ${sUrl} HTTP/1.1`);
|
|
692
|
+
|
|
693
|
+
/* Set header information */
|
|
694
|
+
for (const [sKey, sValue] of oHeaders.entries()) {
|
|
695
|
+
aBody.push(sKey + ":" + sValue);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
aBody.push("");
|
|
699
|
+
aBody.push("");
|
|
700
|
+
aBody.push("--" + sBoundary + "--");
|
|
701
|
+
aBody.push("");
|
|
702
|
+
|
|
703
|
+
return aBody.join("\r\n");
|
|
704
|
+
};
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Unwraps the $batch response and returns a <code>Response</code> object
|
|
708
|
+
* corresponding to the inner GET request.
|
|
709
|
+
*
|
|
710
|
+
* @param {Response} oResponse The <code>Response</code> of the $batch request
|
|
711
|
+
*
|
|
712
|
+
* @returns {Promise<Response>} A <code>Promise</code> that resolves with the <code>Response</code> of the inner GET request
|
|
713
|
+
* @async
|
|
714
|
+
* @static
|
|
715
|
+
* @private
|
|
716
|
+
*/
|
|
717
|
+
PortableDocument.getBatchResponse = async function(oResponse) {
|
|
718
|
+
if (!oResponse.ok) {
|
|
719
|
+
// $batch response cannot be unwrapped when the outer request failed
|
|
720
|
+
return oResponse;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
const oBuffer = await oResponse.arrayBuffer();
|
|
724
|
+
const oUint8 = new Uint8Array(oBuffer);
|
|
725
|
+
|
|
726
|
+
const {status, statusText, headers, pdfContent} = PortableDocument.parseResponseBody(oUint8);
|
|
727
|
+
|
|
728
|
+
return new Response(pdfContent, {
|
|
729
|
+
status: status,
|
|
730
|
+
statusText: statusText,
|
|
731
|
+
headers: headers
|
|
732
|
+
});
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Detects the start index of the PDF content in the binary response.
|
|
737
|
+
* The start boundary is "%PDF-". If the response contains multiple PDFs,
|
|
738
|
+
* the first one is used.
|
|
739
|
+
*
|
|
740
|
+
* @param {Uint8Array} oTypedArray The binary data of the response
|
|
741
|
+
*
|
|
742
|
+
* @returns {number} The start index of the PDF content. If no PDF content is found, -1 is returned.
|
|
743
|
+
* @static
|
|
744
|
+
* @private
|
|
745
|
+
*/
|
|
746
|
+
PortableDocument.getStartIndex = function(oTypedArray) {
|
|
747
|
+
return oTypedArray.findIndex((element, index) => {
|
|
748
|
+
const sStartBoundary = "%PDF-";
|
|
749
|
+
|
|
750
|
+
return element === sStartBoundary.charCodeAt(0)
|
|
751
|
+
&& oTypedArray[index + 1] === sStartBoundary.charCodeAt(1)
|
|
752
|
+
&& oTypedArray[index + 2] === sStartBoundary.charCodeAt(2)
|
|
753
|
+
&& oTypedArray[index + 3] === sStartBoundary.charCodeAt(3)
|
|
754
|
+
&& oTypedArray[index + 4] === sStartBoundary.charCodeAt(4);
|
|
755
|
+
});
|
|
756
|
+
};
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Detects the end index of the PDF content in the binary response.
|
|
760
|
+
* The end boundary is "%%EOF". If the response contains multiple PDFs,
|
|
761
|
+
* the last one is used.
|
|
762
|
+
*
|
|
763
|
+
* @param {Uint8Array} oTypedArray The binary data of the response
|
|
764
|
+
*
|
|
765
|
+
* @returns {number} The start index of the PDF content. If no PDF content is found, -1 is returned.
|
|
766
|
+
* @static
|
|
767
|
+
* @private
|
|
768
|
+
*/
|
|
769
|
+
PortableDocument.getEndIndex = function(oTypedArray) {
|
|
770
|
+
return oTypedArray.findLastIndex((element, index) => {
|
|
771
|
+
const sEndBoundary = "%%EOF";
|
|
772
|
+
|
|
773
|
+
return element === sEndBoundary.charCodeAt(4)
|
|
774
|
+
&& oTypedArray[index - 1] === sEndBoundary.charCodeAt(3)
|
|
775
|
+
&& oTypedArray[index - 2] === sEndBoundary.charCodeAt(2)
|
|
776
|
+
&& oTypedArray[index - 3] === sEndBoundary.charCodeAt(1)
|
|
777
|
+
&& oTypedArray[index - 4] === sEndBoundary.charCodeAt(0);
|
|
778
|
+
});
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
/**
|
|
782
|
+
* Parses the binary response of the inner request. It identifies the PDF content
|
|
783
|
+
* by its field boundaries %PDF- and %%EOF. The response status and its headers are
|
|
784
|
+
* evaluated as well.
|
|
785
|
+
*
|
|
786
|
+
* @param {Uint8Array} oTypedArray The binary response of the inner request
|
|
787
|
+
* @returns {object} An object containing the <code>status</code>, <code>statusText</code>, <code>headers</code>, and the PDF content
|
|
788
|
+
* @static
|
|
789
|
+
* @private
|
|
790
|
+
*/
|
|
791
|
+
PortableDocument.parseResponseBody = function(oTypedArray) {
|
|
792
|
+
let oPDFContent;
|
|
793
|
+
const iPDFStartIndex = PortableDocument.getStartIndex(oTypedArray);
|
|
794
|
+
const iPDFEndIndex = PortableDocument.getEndIndex(oTypedArray);
|
|
795
|
+
|
|
796
|
+
if (iPDFStartIndex !== -1 && iPDFEndIndex !== -1) {
|
|
797
|
+
// Increase end index by one, since subarray does not include the second index
|
|
798
|
+
oPDFContent = oTypedArray.subarray(iPDFStartIndex, iPDFEndIndex + 1);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/*
|
|
802
|
+
* If iPDFStartIndex is -1, the responseText is missing the last character
|
|
803
|
+
* of the response which can be ignored because it is either a line break
|
|
804
|
+
* or the trailing "-" of the batch boundary.
|
|
805
|
+
*/
|
|
806
|
+
const sResponseText = new TextDecoder().decode(oTypedArray.subarray(0, iPDFStartIndex));
|
|
807
|
+
const aLines = sResponseText.split("\r\n");
|
|
808
|
+
|
|
809
|
+
// Remove all lines prior to HTTP status
|
|
810
|
+
aLines.splice(0, aLines.findIndex((sLine) => /^HTTP\/1\.[0|1] ([1-9][0-9]{2})/.test(sLine)));
|
|
811
|
+
|
|
812
|
+
const [, iStatusCode, sStatusText] = aLines[0].match(/^HTTP\/1\.[0|1] ([1-9][0-9]{2}) ?([\w ]*)$/);
|
|
813
|
+
const reHeaders = /^([\w\-]+): ?(.+)$/;
|
|
814
|
+
const oHeaders = aLines
|
|
815
|
+
.filter((sLine) => reHeaders.test(sLine))
|
|
816
|
+
.reduce((oAccumulator, sLine) => {
|
|
817
|
+
const [, sKey, sValue] = sLine.match(reHeaders);
|
|
818
|
+
|
|
819
|
+
oAccumulator.set(sKey, sValue);
|
|
820
|
+
|
|
821
|
+
return oAccumulator;
|
|
822
|
+
}, new Headers());
|
|
823
|
+
|
|
824
|
+
return {
|
|
825
|
+
status: iStatusCode,
|
|
826
|
+
statusText: sStatusText,
|
|
827
|
+
headers: oHeaders,
|
|
828
|
+
pdfContent: oPDFContent
|
|
829
|
+
};
|
|
830
|
+
};
|
|
831
|
+
|
|
832
|
+
/**
|
|
833
|
+
* Creates a pseudo random GUID. This algorithm is not suitable for
|
|
834
|
+
* cryptographic purposes and should not be used for such.
|
|
835
|
+
*
|
|
836
|
+
* *** IMPORTANT ***
|
|
837
|
+
* This is a fallback solution due to missing crypto features in
|
|
838
|
+
* headless chrome that is used for the UI5 voter.
|
|
839
|
+
*
|
|
840
|
+
* @returns {string} Generated GUID
|
|
841
|
+
*
|
|
842
|
+
* @static
|
|
843
|
+
* @private
|
|
844
|
+
*/
|
|
845
|
+
PortableDocument._createGuid = function() {
|
|
846
|
+
if (globalThis.crypto?.randomUUID) {
|
|
847
|
+
return globalThis.crypto.randomUUID();
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
|
|
851
|
+
const r = Math.random() * 16 | 0, // Bitwise OR is equivalent to Math.floor() but faster
|
|
852
|
+
v = c === "x" ? r : ((r & 0x3) | 0x8); // In case of c != "x", the value is always between 0x8 and 0xB
|
|
853
|
+
|
|
854
|
+
return v.toString(16);
|
|
855
|
+
});
|
|
856
|
+
};
|
|
857
|
+
|
|
609
858
|
/**
|
|
610
859
|
* Returns the specific MIME type
|
|
611
860
|
*
|
|
@@ -615,7 +864,7 @@ sap.ui.define([
|
|
|
615
864
|
* @public
|
|
616
865
|
*/
|
|
617
866
|
PortableDocument.prototype.getMimeType = function() {
|
|
618
|
-
return
|
|
867
|
+
return MIME_TYPE;
|
|
619
868
|
};
|
|
620
869
|
|
|
621
870
|
/**
|
|
@@ -90,7 +90,7 @@ sap.ui.define([
|
|
|
90
90
|
* <li><code>workbook.context</code> - Context object that will be applied to the generated file. It may contain the following fields:</li>
|
|
91
91
|
* <ul>
|
|
92
92
|
* <li><code>application</code> (string) - The application that creates the XLSX document (default: "SAP UI5")</li>
|
|
93
|
-
* <li><code>version</code> (string) - Application version that creates the XLSX document (default: "1.
|
|
93
|
+
* <li><code>version</code> (string) - Application version that creates the XLSX document (default: "1.134.0")</li>
|
|
94
94
|
* <li><code>title</code> (string) - Title of the XLSX document (NOT the filename)</li>
|
|
95
95
|
* <li><code>modifiedBy</code> (string) - User context for the XLSX document</li>
|
|
96
96
|
* <li><code>sheetName</code> (string) - The label of the data sheet</li>
|
|
@@ -174,7 +174,7 @@ sap.ui.define([
|
|
|
174
174
|
* columns: aColumns,
|
|
175
175
|
* context: {
|
|
176
176
|
* application: 'Debug Test Application',
|
|
177
|
-
* version: '1.
|
|
177
|
+
* version: '1.134.0',
|
|
178
178
|
* title: 'Some random title',
|
|
179
179
|
* modifiedBy: 'John Doe',
|
|
180
180
|
* metaSheetName: 'Custom metadata',
|
|
@@ -286,7 +286,7 @@ sap.ui.define([
|
|
|
286
286
|
* @class The <code>sap.ui.export.Spreadsheet</code> class allows you to export table data from a UI5 application to a spreadsheet file.
|
|
287
287
|
*
|
|
288
288
|
* @author SAP SE
|
|
289
|
-
* @version 1.
|
|
289
|
+
* @version 1.134.0
|
|
290
290
|
*
|
|
291
291
|
* @since 1.50
|
|
292
292
|
* @alias sap.ui.export.Spreadsheet
|
|
@@ -21,7 +21,7 @@ sap.ui.define(['sap/base/Log', 'sap/ui/export/ExportUtils'], function(Log, Expor
|
|
|
21
21
|
* Utility class to perform spreadsheet export.
|
|
22
22
|
*
|
|
23
23
|
* @author SAP SE
|
|
24
|
-
* @version 1.
|
|
24
|
+
* @version 1.134.0
|
|
25
25
|
*
|
|
26
26
|
* @alias sap.ui.export.SpreadsheetExport
|
|
27
27
|
* @private
|
|
@@ -15,7 +15,7 @@ sap.ui.define(["sap/ui/core/Lib"], function(Library) {
|
|
|
15
15
|
* @namespace
|
|
16
16
|
* @alias sap.ui.export
|
|
17
17
|
* @author SAP SE
|
|
18
|
-
* @version 1.
|
|
18
|
+
* @version 1.134.0
|
|
19
19
|
* @public
|
|
20
20
|
*/
|
|
21
21
|
|
|
@@ -34,7 +34,7 @@ sap.ui.define(["sap/ui/core/Lib"], function(Library) {
|
|
|
34
34
|
interfaces: [],
|
|
35
35
|
controls: [],
|
|
36
36
|
elements: [],
|
|
37
|
-
version: "1.
|
|
37
|
+
version: "1.134.0"
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
/**
|
|
@@ -20,7 +20,7 @@ sap.ui.define(['sap/ui/base/Object'], function(BaseObject) {
|
|
|
20
20
|
* convenience functions like <code>sap.ui.export.util.Filter#setType</code> to improve the result.
|
|
21
21
|
*
|
|
22
22
|
* @author SAP SE
|
|
23
|
-
* @version 1.
|
|
23
|
+
* @version 1.134.0
|
|
24
24
|
*
|
|
25
25
|
* @since 1.110
|
|
26
26
|
* @alias sap.ui.export.util.Filter
|