@disy/cadenza.js 2.2.2 β 2.3.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/CHANGELOG.md +17 -2
- package/README.md +1 -322
- package/apidoc/assets/highlight.css +0 -7
- package/apidoc/assets/main.js +2 -2
- package/apidoc/assets/navigation.js +1 -1
- package/apidoc/assets/search.js +1 -1
- package/apidoc/assets/style.css +46 -15
- package/apidoc/classes/AbortError.html +3 -3
- package/apidoc/classes/CadenzaClient.html +68 -89
- package/apidoc/classes/CadenzaError.html +8 -6
- package/apidoc/functions/cadenza.html +6 -5
- package/apidoc/index.html +152 -9
- package/apidoc/interfaces/CadenzaEvent.html +6 -6
- package/apidoc/interfaces/ExternalLinkKey.html +6 -3
- package/apidoc/interfaces/Geometry.html +2 -2
- package/apidoc/interfaces/PageSource.html +2 -2
- package/apidoc/modules.html +14 -2
- package/apidoc/types/CadenzaChangeSelectionEvent.html +2 -0
- package/apidoc/types/CadenzaDrillThroughEvent.html +7 -0
- package/apidoc/types/CadenzaEditGeometryCancelEvent.html +2 -0
- package/apidoc/types/CadenzaEditGeometryOkEvent.html +2 -0
- package/apidoc/types/CadenzaEditGeometryUpdateEvent.html +2 -0
- package/apidoc/types/CadenzaErrorEvent.html +2 -2
- package/apidoc/types/CadenzaEventByType.html +1 -0
- package/apidoc/types/CadenzaEventType.html +2 -0
- package/apidoc/types/CadenzaObjectInfoEvent.html +2 -0
- package/apidoc/types/CadenzaSelectObjectsCancelEvent.html +2 -0
- package/apidoc/types/CadenzaSelectObjectsOkEvent.html +2 -0
- package/apidoc/types/DataType.html +3 -2
- package/apidoc/types/EmbeddingTargetId.html +9 -2
- package/apidoc/types/Extent.html +1 -1
- package/apidoc/types/FilterVariables.html +5 -2
- package/apidoc/types/GeometryType.html +1 -1
- package/apidoc/types/GlobalId.html +2 -2
- package/apidoc/types/OpaqueString.html +6 -0
- package/apidoc/types/OperationMode.html +1 -1
- package/apidoc/types/TablePart.html +1 -1
- package/apidoc/types/UiFeature.html +3 -3
- package/apidoc/types/WorkbookLayerPath.html +3 -0
- package/cadenza.d.ts +321 -56
- package/cadenza.js +349 -71
- package/package.json +6 -6
- package/sandbox.html +197 -31
package/cadenza.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* @param {ExternalLinkKey} [options.webApplication] - An external link that Cadenza uses to resolve the
|
|
10
10
|
* [target origin](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#targetorigin) when posting events.
|
|
11
11
|
* This is required if Cadenza and your application are not running on the same origin.
|
|
12
|
+
* Please ensure that the user has view privilege for that link!
|
|
12
13
|
* @param {boolean} [options.debug] - Whether to enable debug logging
|
|
13
14
|
* @throws For invalid arguments
|
|
14
15
|
*/
|
|
@@ -23,13 +24,42 @@ globalThis.cadenza = Object.assign((/** @type Parameters<cadenza> */ ...args) =>
|
|
|
23
24
|
return cadenza;
|
|
24
25
|
},
|
|
25
26
|
});
|
|
26
|
-
/**
|
|
27
|
-
|
|
27
|
+
/**
|
|
28
|
+
* @template {string} T
|
|
29
|
+
* @typedef {string & {__type: T}} OpaqueString - A specific `string` type that is not assignable from another string
|
|
30
|
+
*
|
|
31
|
+
* The idea is to have a specific type e.g. for the {@link EmbeddingTargetId} instead of a plain `string`.
|
|
32
|
+
* You don't need to _actually_ add that `__type` property. In TS code, just use a
|
|
33
|
+
* [type assertion](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions)
|
|
34
|
+
* (e.g. `cadenzaClient.show('{embeddingTargetId}' as EmbeddingTargetId)`).
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* @typedef {OpaqueString<'EmbeddingTargetId'>} EmbeddingTargetId - The ID of a Cadenza embedding target
|
|
38
|
+
*
|
|
39
|
+
* Embedding targets are called π©πͺ "Einbettbarer Inhalt" / πΊπΈ "Embeddable content" throughout the Cadenza UI and help.
|
|
40
|
+
* They're managed within the respective workbook:
|
|
41
|
+
*
|
|
42
|
+
* - π©πͺ "Mehr" > "Arbeitsmappe verwalten" > "Einbettung"
|
|
43
|
+
* - πΊπΈ "More" > "Manage workbook" > "Embedding"
|
|
44
|
+
*
|
|
45
|
+
* The name of an embedding target (as entered in the UI) is its ID.
|
|
46
|
+
*/
|
|
47
|
+
/** @typedef {OpaqueString<'GlobalId'>} GlobalId - The ID of a navigator item */
|
|
28
48
|
/**
|
|
29
49
|
* @typedef ExternalLinkKey - A tuple qualifying a Cadenza external link
|
|
50
|
+
*
|
|
51
|
+
* You get the `repositoryName` and `externalLinkId` from the URL of the external link's page in the Cadenza management center:
|
|
52
|
+
* ```
|
|
53
|
+
* {baseUrl}/admin/repositories/{repositoryName}/external-links/{externalLinkId}?...
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
30
56
|
* @property {string} repositoryName - The name of the link's repository
|
|
31
57
|
* @property {string} externalLinkId - The ID of the external link
|
|
32
58
|
*/
|
|
59
|
+
/**
|
|
60
|
+
* @typedef {string[]} WorkbookLayerPath - Identifies a layer within a workbook map view
|
|
61
|
+
* using the print names of the layer and - if the layer is grouped - its ancestors
|
|
62
|
+
*/
|
|
33
63
|
/**
|
|
34
64
|
* @typedef PageSource - A well-known Cadenza page
|
|
35
65
|
* @property {'welcome'} page - The name of the page (Only `"welcome"` is currently supported.)
|
|
@@ -39,8 +69,8 @@ globalThis.cadenza = Object.assign((/** @type Parameters<cadenza> */ ...args) =>
|
|
|
39
69
|
* @typedef {'workbook-design'|'workbook-view-management'} UiFeature - The name of a Cadenza UI feature
|
|
40
70
|
*
|
|
41
71
|
* _Note:_ Supported features are:
|
|
42
|
-
* *
|
|
43
|
-
* *
|
|
72
|
+
* * `"workbook-design"` - The workbook designer
|
|
73
|
+
* * `"workbook-view-management"` - Add/Edit/Remove workbook views (Is included in 'workbook-design'.)
|
|
44
74
|
* */
|
|
45
75
|
/**
|
|
46
76
|
* @typedef Geometry - A [GeoJSON](https://geojson.org/) geometry object
|
|
@@ -52,9 +82,20 @@ globalThis.cadenza = Object.assign((/** @type Parameters<cadenza> */ ...args) =>
|
|
|
52
82
|
* _Note:_ The GeoJSON geometry type "GeometryCollection" is currently not supported.
|
|
53
83
|
*/
|
|
54
84
|
/** @typedef {[number,number,number,number]} Extent - An array of numbers representing an extent: [minx, miny, maxx, maxy] */
|
|
55
|
-
/**
|
|
85
|
+
/**
|
|
86
|
+
* @typedef {'csv' | 'excel' | 'json' | 'pdf' | 'png'} DataType - A data type
|
|
87
|
+
*
|
|
88
|
+
* See [JSON Representation of Cadenza Object Data](../index.html#md:json-representation-of-cadenza-object-data) for JSON data.
|
|
89
|
+
*/
|
|
56
90
|
/** @typedef {'columns' | 'values' | 'totals'} TablePart - A part of a table to export */
|
|
57
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* @typedef {Record<string, string | string[] | number | Date | null>} FilterVariables - Filter variable names and values
|
|
93
|
+
*
|
|
94
|
+
* Variables of type String, Integer, Long, Double and Date can be set.
|
|
95
|
+
*
|
|
96
|
+
* _Note:_ Since numbers in JavaScript are Double values ([more info on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number#number_encoding)),
|
|
97
|
+
* for Long variables, the API is currently limited to the Double value range.
|
|
98
|
+
*/
|
|
58
99
|
/**
|
|
59
100
|
* _Notes:_
|
|
60
101
|
* * Most public methods can be aborted using an [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal).
|
|
@@ -77,7 +118,7 @@ export class CadenzaClient {
|
|
|
77
118
|
#iframeElement;
|
|
78
119
|
/** @readonly */
|
|
79
120
|
#debug;
|
|
80
|
-
/** @type {[ string, (event: CadenzaEvent<never>) => void ][]} */
|
|
121
|
+
/** @type {[ CadenzaEventType | string, (event: CadenzaEvent<never>) => void ][]} */
|
|
81
122
|
#subscriptions = [];
|
|
82
123
|
/**
|
|
83
124
|
* @hidden
|
|
@@ -119,9 +160,11 @@ export class CadenzaClient {
|
|
|
119
160
|
return this.#iframeElement;
|
|
120
161
|
}
|
|
121
162
|
get #requiredIframe() {
|
|
122
|
-
const iframe = this.iframe;
|
|
163
|
+
const iframe = /** @type {HTMLIFrameElement} */ (this.iframe);
|
|
123
164
|
assert(iframe instanceof HTMLIFrameElement, 'Required iframe is not present.');
|
|
124
|
-
|
|
165
|
+
const { width, height } = iframe.getBoundingClientRect();
|
|
166
|
+
assert(width > 0 && height > 0, 'Iframe must be visible.');
|
|
167
|
+
return iframe;
|
|
125
168
|
}
|
|
126
169
|
/**
|
|
127
170
|
* Show a page, workbook, worksheet or workbook view in an iframe.
|
|
@@ -139,15 +182,12 @@ export class CadenzaClient {
|
|
|
139
182
|
* @param {String} [options.labelSet] - The name of a label set defined in the `basicweb-config.xml` (only supported for the welcome page)
|
|
140
183
|
* @param {OperationMode} [options.operationMode] - The mode in which a workbook should be operated
|
|
141
184
|
* @param {AbortSignal} [options.signal] - A signal to abort the iframe loading
|
|
142
|
-
* @return {Promise<void>} A Promise for when the iframe is loaded
|
|
185
|
+
* @return {Promise<void>} A `Promise` for when the iframe is loaded
|
|
143
186
|
* @throws For invalid arguments
|
|
144
|
-
* @fires
|
|
145
|
-
* The event includes a row of values for each row in the workbook selection, each row consisting of the values of
|
|
146
|
-
* the attributes that were selected for the POST message content. If the drill-through was executed from a map
|
|
147
|
-
* view, each row includes the geometry of the select object as the last value.
|
|
187
|
+
* @fires {@link CadenzaDrillThroughEvent}
|
|
148
188
|
*/
|
|
149
189
|
show(source, { dataType, disabledUiFeatures, expandNavigator, filter, hideMainHeaderAndFooter, hideWorkbookToolBar, highlightGlobalId, labelSet, operationMode, signal, } = {}) {
|
|
150
|
-
this.#log('CadenzaClient#show',
|
|
190
|
+
this.#log('CadenzaClient#show', ...arguments);
|
|
151
191
|
if (dataType) {
|
|
152
192
|
assertSupportedDataType(dataType, ['pdf']);
|
|
153
193
|
}
|
|
@@ -166,7 +206,6 @@ export class CadenzaClient {
|
|
|
166
206
|
labelSet,
|
|
167
207
|
dataType,
|
|
168
208
|
operationMode,
|
|
169
|
-
webApplication: this.#webApplication,
|
|
170
209
|
});
|
|
171
210
|
return this.#show(resolvePath(source), params, signal);
|
|
172
211
|
}
|
|
@@ -187,14 +226,12 @@ export class CadenzaClient {
|
|
|
187
226
|
* @param {OperationMode} [options.operationMode] - The mode in which a workbook should be operated
|
|
188
227
|
* @param {boolean} [options.useMapSrs] - Whether the geometry and the extent are in the map's SRS (otherwise EPSG:4326 is assumed)
|
|
189
228
|
* @param {AbortSignal} [options.signal] - A signal to abort the iframe loading
|
|
190
|
-
* @return {Promise<void>} A Promise for when the iframe is loaded
|
|
229
|
+
* @return {Promise<void>} A `Promise` for when the iframe is loaded
|
|
191
230
|
* @throws For invalid arguments
|
|
192
|
-
* @fires
|
|
193
|
-
* The event includes a row of values for each row in the workbook selection, each row consisting of the values of
|
|
194
|
-
* the attributes that were selected for the POST message content plus the geometry of the select object as the last value.
|
|
231
|
+
* @fires {@link CadenzaDrillThroughEvent}
|
|
195
232
|
*/
|
|
196
233
|
async showMap(mapView, { disabledUiFeatures, expandNavigator, filter, geometry, hideMainHeaderAndFooter, hideWorkbookToolBar, highlightGlobalId, locationFinder, mapExtent, operationMode, useMapSrs, signal, } = {}) {
|
|
197
|
-
this.#log('CadenzaClient#showMap',
|
|
234
|
+
this.#log('CadenzaClient#showMap', ...arguments);
|
|
198
235
|
if (geometry) {
|
|
199
236
|
assertValidGeometryType(geometry.type);
|
|
200
237
|
}
|
|
@@ -208,11 +245,13 @@ export class CadenzaClient {
|
|
|
208
245
|
locationFinder,
|
|
209
246
|
mapExtent,
|
|
210
247
|
operationMode,
|
|
248
|
+
targetType: 'MAP',
|
|
211
249
|
useMapSrs,
|
|
212
|
-
webApplication: this.#webApplication,
|
|
213
250
|
});
|
|
214
251
|
await this.#show(resolvePath(mapView), params, signal);
|
|
215
|
-
|
|
252
|
+
if (geometry) {
|
|
253
|
+
this.#postEvent('setGeometry', { geometry });
|
|
254
|
+
}
|
|
216
255
|
}
|
|
217
256
|
/**
|
|
218
257
|
* Expand/collapse the navigator.
|
|
@@ -220,9 +259,93 @@ export class CadenzaClient {
|
|
|
220
259
|
* @param {boolean} expanded - The expansion state of the navigator
|
|
221
260
|
*/
|
|
222
261
|
expandNavigator(expanded = true) {
|
|
223
|
-
this.#log('CadenzaClient#expandNavigator',
|
|
262
|
+
this.#log('CadenzaClient#expandNavigator', ...arguments);
|
|
224
263
|
this.#postEvent('expandNavigator', { expandNavigator: Boolean(expanded) });
|
|
225
264
|
}
|
|
265
|
+
/**
|
|
266
|
+
* Get data from the currently shown workbook view.
|
|
267
|
+
*
|
|
268
|
+
* Currently, only map views are supported.
|
|
269
|
+
*
|
|
270
|
+
* @hidden
|
|
271
|
+
* @template {DataType} T
|
|
272
|
+
* @param {T} dataType - The requested data type. Currently, only `"png"` is supported.
|
|
273
|
+
* @return {Promise<T extends 'png' ? Blob : never>}
|
|
274
|
+
*/
|
|
275
|
+
async getData(dataType) {
|
|
276
|
+
this.#log('CadenzaClient#getData', ...arguments);
|
|
277
|
+
assertSupportedDataType(dataType, ['png']);
|
|
278
|
+
return this.#postRequest('getData', { dataType });
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Set filter variables in the currently shown workbook.
|
|
282
|
+
*
|
|
283
|
+
* @hidden
|
|
284
|
+
* @param {FilterVariables} filter - The variable values
|
|
285
|
+
* @return {Promise<void>} A `Promise` for when the filter variables were set.
|
|
286
|
+
*/
|
|
287
|
+
setFilter(filter) {
|
|
288
|
+
this.#log('CadenzaClient#setFilter', ...arguments);
|
|
289
|
+
return this.#postRequest('setFilter', { filter });
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Set the visibility of a layer in the currently shown workbook map view.
|
|
293
|
+
*
|
|
294
|
+
* When making a layer visible, its ancestors will be made visible, too.
|
|
295
|
+
* When hiding a layer, the ancestors are not affected.
|
|
296
|
+
*
|
|
297
|
+
* @hidden
|
|
298
|
+
* @param {WorkbookLayerPath | string} layer - The layer to show or hide
|
|
299
|
+
* (identified using a layer path or a print name)
|
|
300
|
+
* @param {boolean} visible - The visibility state of the layer
|
|
301
|
+
* @return {Promise<void>} A `Promise` for when the layer visibility was set.
|
|
302
|
+
*/
|
|
303
|
+
setLayerVisibility(layer, visible) {
|
|
304
|
+
this.#log('CadenzaClient#setLayerVisibility', ...arguments);
|
|
305
|
+
return this.#postRequest('setLayerVisibility', {
|
|
306
|
+
layer: array(layer),
|
|
307
|
+
visible,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Set the selection in the currently shown workbook map view.
|
|
312
|
+
*
|
|
313
|
+
* @hidden
|
|
314
|
+
* @param {WorkbookLayerPath | string} layer - The data view layer to set the selection in
|
|
315
|
+
* @param {unknown[]} values - The IDs of the objects to select
|
|
316
|
+
* @return {Promise<void>} A `Promise` for when the selection was set.
|
|
317
|
+
*/
|
|
318
|
+
setSelection(layer, values) {
|
|
319
|
+
this.#log('CadenzaClient#setSelection', ...arguments);
|
|
320
|
+
return this.#postRequest('setSelection', { layer: array(layer), values });
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Add to the selection in the currently shown workbook map view.
|
|
324
|
+
*
|
|
325
|
+
* @hidden
|
|
326
|
+
* @param {WorkbookLayerPath | string} layer - The data view layer to change the selection in
|
|
327
|
+
* @param {unknown[]} values - The IDs of the objects to select
|
|
328
|
+
* @return {Promise<void>} A `Promise` for when the selection was changed.
|
|
329
|
+
*/
|
|
330
|
+
addSelection(layer, values) {
|
|
331
|
+
this.#log('CadenzaClient#addSelection', ...arguments);
|
|
332
|
+
return this.#postRequest('addSelection', { layer: array(layer), values });
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Remove from the selection in the currently shown workbook map view.
|
|
336
|
+
*
|
|
337
|
+
* @hidden
|
|
338
|
+
* @param {WorkbookLayerPath | string} layer - The data view layer to change the selection in
|
|
339
|
+
* @param {unknown[]} values - The IDs of the objects to unselect
|
|
340
|
+
* @return {Promise<void>} A `Promise` for when the selection was changed.
|
|
341
|
+
*/
|
|
342
|
+
removeSelection(layer, values) {
|
|
343
|
+
this.#log('CadenzaClient#removeSelection', ...arguments);
|
|
344
|
+
return this.#postRequest('removeSelection', {
|
|
345
|
+
layer: array(layer),
|
|
346
|
+
values,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
226
349
|
/**
|
|
227
350
|
* Create a geometry.
|
|
228
351
|
*
|
|
@@ -237,14 +360,15 @@ export class CadenzaClient {
|
|
|
237
360
|
* @param {number} [options.minScale] - The minimum scale where the user should work on. A warning is shown when the map is zoomed out above the threshold.
|
|
238
361
|
* @param {boolean} [options.useMapSrs] - Whether the created geometry should use the map's SRS (otherwise EPSG:4326 will be used)
|
|
239
362
|
* @param {AbortSignal} [options.signal] - A signal to abort the iframe loading
|
|
240
|
-
* @return {Promise<void>} A Promise for when the iframe is loaded
|
|
363
|
+
* @return {Promise<void>} A `Promise` for when the iframe is loaded
|
|
241
364
|
* @throws For invalid arguments
|
|
242
|
-
* @fires
|
|
243
|
-
*
|
|
244
|
-
*
|
|
365
|
+
* @fires
|
|
366
|
+
* - {@link CadenzaEditGeometryUpdateEvent}
|
|
367
|
+
* - {@link CadenzaEditGeometryOkEvent}
|
|
368
|
+
* - {@link CadenzaEditGeometryCancelEvent}
|
|
245
369
|
*/
|
|
246
370
|
createGeometry(backgroundMapView, geometryType, { locationFinder, mapExtent, minScale, useMapSrs, signal } = {}) {
|
|
247
|
-
this.#log('CadenzaClient#createGeometry',
|
|
371
|
+
this.#log('CadenzaClient#createGeometry', ...arguments);
|
|
248
372
|
const params = createParams({
|
|
249
373
|
action: 'editGeometry',
|
|
250
374
|
geometryType,
|
|
@@ -252,7 +376,6 @@ export class CadenzaClient {
|
|
|
252
376
|
mapExtent,
|
|
253
377
|
minScale,
|
|
254
378
|
useMapSrs,
|
|
255
|
-
webApplication: this.#webApplication,
|
|
256
379
|
});
|
|
257
380
|
return this.#show(resolvePath(backgroundMapView), params, signal);
|
|
258
381
|
}
|
|
@@ -267,14 +390,15 @@ export class CadenzaClient {
|
|
|
267
390
|
* @param {number} [options.minScale] - The minimum scale where the user should work on. A warning is shown when the map is zoomed out above the threshold.
|
|
268
391
|
* @param {boolean} [options.useMapSrs] - Whether the geometry is in the map's SRS (otherwise EPSG:4326 is assumed)
|
|
269
392
|
* @param {AbortSignal} [options.signal] - A signal to abort the iframe loading
|
|
270
|
-
* @return {Promise<void>} A Promise for when the iframe is loaded
|
|
393
|
+
* @return {Promise<void>} A `Promise` for when the iframe is loaded
|
|
271
394
|
* @throws For invalid arguments
|
|
272
|
-
* @fires
|
|
273
|
-
*
|
|
274
|
-
*
|
|
395
|
+
* @fires
|
|
396
|
+
* - {@link CadenzaEditGeometryUpdateEvent}
|
|
397
|
+
* - {@link CadenzaEditGeometryOkEvent}
|
|
398
|
+
* - {@link CadenzaEditGeometryCancelEvent}
|
|
275
399
|
*/
|
|
276
400
|
async editGeometry(backgroundMapView, geometry, { locationFinder, mapExtent, minScale, useMapSrs, signal } = {}) {
|
|
277
|
-
this.#log('CadenzaClient#editGeometry',
|
|
401
|
+
this.#log('CadenzaClient#editGeometry', ...arguments);
|
|
278
402
|
assertValidGeometryType(geometry.type);
|
|
279
403
|
const params = createParams({
|
|
280
404
|
action: 'editGeometry',
|
|
@@ -282,15 +406,51 @@ export class CadenzaClient {
|
|
|
282
406
|
mapExtent,
|
|
283
407
|
minScale,
|
|
284
408
|
useMapSrs,
|
|
285
|
-
webApplication: this.#webApplication,
|
|
286
409
|
});
|
|
287
410
|
await this.#show(resolvePath(backgroundMapView), params, signal);
|
|
288
|
-
|
|
411
|
+
if (geometry) {
|
|
412
|
+
this.#postEvent('setGeometry', { geometry });
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
/**
|
|
416
|
+
* Select objects in a workbook map.
|
|
417
|
+
*
|
|
418
|
+
* @param {EmbeddingTargetId} backgroundMapView - The workbook map view
|
|
419
|
+
* @param {object} [options] - Options
|
|
420
|
+
* @param {(WorkbookLayerPath | string)[]} [options.layers] - Layers to restrict the selection to
|
|
421
|
+
* (identified using layer paths or print names)
|
|
422
|
+
* @param {string} [options.locationFinder] - A search query for the location finder
|
|
423
|
+
* @param {Extent} [options.mapExtent] - A map extent to set
|
|
424
|
+
* @param {boolean} [options.useMapSrs] - Whether the geometry is in the map's SRS (otherwise EPSG:4326 is assumed)
|
|
425
|
+
* @param {AbortSignal} [options.signal] - A signal to abort the iframe loading
|
|
426
|
+
* @return {Promise<void>} A `Promise` for when the iframe is loaded
|
|
427
|
+
* @throws For invalid arguments
|
|
428
|
+
* @fires
|
|
429
|
+
* - {@link CadenzaChangeSelectionEvent}
|
|
430
|
+
* - {@link CadenzaObjectInfoEvent}
|
|
431
|
+
* - {@link CadenzaSelectObjectsOkEvent}
|
|
432
|
+
* - {@link CadenzaSelectObjectsCancelEvent}
|
|
433
|
+
*/
|
|
434
|
+
selectObjects(backgroundMapView, { layers, locationFinder, mapExtent, useMapSrs, signal } = {}) {
|
|
435
|
+
this.#log('CadenzaClient#selectObjects', ...arguments);
|
|
436
|
+
const params = createParams({
|
|
437
|
+
action: 'selectObjects',
|
|
438
|
+
layers: layers?.map(array),
|
|
439
|
+
locationFinder,
|
|
440
|
+
mapExtent,
|
|
441
|
+
useMapSrs,
|
|
442
|
+
});
|
|
443
|
+
return this.#show(resolvePath(backgroundMapView), params, signal);
|
|
289
444
|
}
|
|
290
445
|
#show(
|
|
291
446
|
/** @type string */ path,
|
|
292
447
|
/** @type URLSearchParams */ params,
|
|
293
448
|
/** @type AbortSignal | undefined */ signal) {
|
|
449
|
+
const webApplication = this.#webApplication;
|
|
450
|
+
if (webApplication) {
|
|
451
|
+
params.set('webApplicationLink', webApplication.externalLinkId);
|
|
452
|
+
params.set('webApplicationLinkRepository', webApplication.repositoryName);
|
|
453
|
+
}
|
|
294
454
|
const url = this.#createUrl(path, params);
|
|
295
455
|
this.#log('Load iframe', url.toString());
|
|
296
456
|
this.#requiredIframe.src = url.toString();
|
|
@@ -298,14 +458,14 @@ export class CadenzaClient {
|
|
|
298
458
|
}
|
|
299
459
|
#getIframePromise(/** @type AbortSignal | undefined */ signal) {
|
|
300
460
|
const iframe = this.#requiredIframe;
|
|
301
|
-
/** @type {
|
|
461
|
+
/** @type {EventListener} */
|
|
302
462
|
let onerror;
|
|
303
|
-
/** @type {
|
|
463
|
+
/** @type {EventListener} */
|
|
304
464
|
let onabort;
|
|
305
465
|
/** @type {(() => void)[]} */
|
|
306
466
|
let unsubscribes;
|
|
307
467
|
/** @type {Promise<void>} */
|
|
308
|
-
|
|
468
|
+
const promise = new Promise((resolve, reject) => {
|
|
309
469
|
onerror = () => reject(new CadenzaError('loading-error', 'Loading failed'));
|
|
310
470
|
iframe.addEventListener('error', onerror);
|
|
311
471
|
if (signal) {
|
|
@@ -316,8 +476,8 @@ export class CadenzaClient {
|
|
|
316
476
|
signal.addEventListener('abort', onabort);
|
|
317
477
|
}
|
|
318
478
|
unsubscribes = [
|
|
319
|
-
this
|
|
320
|
-
this
|
|
479
|
+
this.#on('ready', () => resolve()),
|
|
480
|
+
this.#on('error', (/** @type {CadenzaErrorEvent} */ event) => {
|
|
321
481
|
const { type, message } = event.detail;
|
|
322
482
|
reject(new CadenzaError(type, message ?? 'Loading failed'));
|
|
323
483
|
}),
|
|
@@ -335,17 +495,30 @@ export class CadenzaClient {
|
|
|
335
495
|
/**
|
|
336
496
|
* Subscribe to a `postMessage()` event.
|
|
337
497
|
*
|
|
338
|
-
* @template
|
|
339
|
-
* @param {
|
|
340
|
-
* @param {(event: CadenzaEvent<
|
|
498
|
+
* @template {CadenzaEventType} TYPE
|
|
499
|
+
* @param {TYPE} type - The event type
|
|
500
|
+
* @param {(event: CadenzaEvent<TYPE, CadenzaEventByType<TYPE>['detail']>) => void} subscriber - The subscriber function
|
|
341
501
|
* @return {() => void} An unsubscribe function
|
|
342
502
|
*/
|
|
343
503
|
on(type, subscriber) {
|
|
504
|
+
return this.#on(type, subscriber);
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* @template {CadenzaEventType | string} TYPE
|
|
508
|
+
* @template [DETAIL=unknown]
|
|
509
|
+
* @param {TYPE} type
|
|
510
|
+
* @param {(event: CadenzaEvent<TYPE, DETAIL>) => void} subscriber
|
|
511
|
+
* @return {() => void} An unsubscribe function
|
|
512
|
+
*/
|
|
513
|
+
#on(type, subscriber) {
|
|
344
514
|
const subscriptions = this.#subscriptions;
|
|
345
515
|
if (subscriptions.length === 0) {
|
|
346
516
|
window.addEventListener('message', this.#onMessage);
|
|
347
517
|
}
|
|
348
|
-
subscriptions.push([
|
|
518
|
+
subscriptions.push([
|
|
519
|
+
type,
|
|
520
|
+
/** @type {(event: CadenzaEvent<never>) => void} */ (subscriber),
|
|
521
|
+
]);
|
|
349
522
|
return () => {
|
|
350
523
|
subscriptions.forEach(([subscriptionType, subscriptionSubscriber], i) => {
|
|
351
524
|
if (subscriptionType === type &&
|
|
@@ -359,7 +532,8 @@ export class CadenzaClient {
|
|
|
359
532
|
};
|
|
360
533
|
}
|
|
361
534
|
// Use arrow function so that it's bound to this.
|
|
362
|
-
#onMessage = (
|
|
535
|
+
#onMessage = (
|
|
536
|
+
/** @type MessageEvent<CadenzaEvent<never, never>> */ event) => {
|
|
363
537
|
if (event.origin !== this.#origin ||
|
|
364
538
|
event.source !== this.#requiredIframe.contentWindow) {
|
|
365
539
|
return;
|
|
@@ -372,26 +546,63 @@ export class CadenzaClient {
|
|
|
372
546
|
}
|
|
373
547
|
});
|
|
374
548
|
};
|
|
375
|
-
|
|
549
|
+
/**
|
|
550
|
+
* Posts an event to Cadenza and returns a `Promise` for the response.
|
|
551
|
+
*
|
|
552
|
+
* It is guaranteed that a response refers to a specific request,
|
|
553
|
+
* even if multiple request are executed in parallel.
|
|
554
|
+
* @template [T=void]
|
|
555
|
+
* @param {string} type
|
|
556
|
+
* @param {unknown} [detail]
|
|
557
|
+
* @returns {Promise<T>}
|
|
558
|
+
*/
|
|
559
|
+
#postRequest(type, detail) {
|
|
560
|
+
const { port1, port2 } = new MessageChannel();
|
|
561
|
+
const promise = new Promise((resolve, reject) => {
|
|
562
|
+
port1.onmessage = (
|
|
563
|
+
/** @type MessageEvent<CadenzaEvent<never, never>> */ event) => {
|
|
564
|
+
const cadenzaEvent = event.data;
|
|
565
|
+
if (cadenzaEvent.type === `${type}:success`) {
|
|
566
|
+
resolve(cadenzaEvent.detail);
|
|
567
|
+
}
|
|
568
|
+
else if (cadenzaEvent.type === `${type}:error`) {
|
|
569
|
+
reject();
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
});
|
|
573
|
+
this.#postEvent(type, detail, [port2]);
|
|
574
|
+
return promise;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* @param {string} type
|
|
578
|
+
* @param {unknown} [detail]
|
|
579
|
+
* @param {Transferable[]} [transfer]
|
|
580
|
+
*/
|
|
581
|
+
#postEvent(type, detail, transfer) {
|
|
376
582
|
const cadenzaEvent = { type, detail };
|
|
377
583
|
this.#log('postMessage', cadenzaEvent);
|
|
378
584
|
const contentWindow = /** @type {WindowProxy} */ (this.#requiredIframe.contentWindow);
|
|
379
|
-
contentWindow.postMessage(cadenzaEvent, {
|
|
585
|
+
contentWindow.postMessage(cadenzaEvent, {
|
|
586
|
+
targetOrigin: this.#origin,
|
|
587
|
+
transfer,
|
|
588
|
+
});
|
|
380
589
|
}
|
|
381
590
|
/**
|
|
382
591
|
* Fetch data from a workbook view.
|
|
383
592
|
*
|
|
384
|
-
* @param {EmbeddingTargetId} source - The workbook view to fetch data from
|
|
385
|
-
*
|
|
593
|
+
* @param {EmbeddingTargetId} source - The workbook view to fetch data from.
|
|
594
|
+
* Currently only table and indicator views are supported.
|
|
595
|
+
* @param {DataType} dataType - The data type you want to get back from the server.
|
|
596
|
+
* Currently, `"csv"`, `"excel"` and `"json"` are supported.
|
|
386
597
|
* @param {object} options - Options
|
|
387
598
|
* @param {TablePart[]} [options.parts] - Table parts to export; If not specified, all parts are exported.
|
|
388
599
|
* @param {AbortSignal} [options.signal] - A signal to abort the data fetching
|
|
389
|
-
* @return {Promise<Response>} A Promise for the fetch response
|
|
600
|
+
* @return {Promise<Response>} A `Promise` for the fetch response
|
|
390
601
|
* @throws For invalid arguments
|
|
391
602
|
*/
|
|
392
603
|
fetchData(source, dataType, { parts, signal } = {}) {
|
|
393
|
-
this.#log('CadenzaClient#fetchData',
|
|
394
|
-
assertSupportedDataType(dataType);
|
|
604
|
+
this.#log('CadenzaClient#fetchData', ...arguments);
|
|
605
|
+
assertSupportedDataType(dataType, ['csv', 'excel', 'json']);
|
|
395
606
|
const params = createParams({ dataType, parts });
|
|
396
607
|
return this.#fetch(resolvePath(source), params, signal);
|
|
397
608
|
}
|
|
@@ -417,16 +628,18 @@ export class CadenzaClient {
|
|
|
417
628
|
*
|
|
418
629
|
* _Note:_ The file name, if not provided, is generated from the name of the workbook view and the current date.
|
|
419
630
|
*
|
|
420
|
-
* @param {EmbeddingTargetId} source - The workbook view to download data from
|
|
421
|
-
*
|
|
631
|
+
* @param {EmbeddingTargetId} source - The workbook view to download data from.
|
|
632
|
+
* Currently only table and indicator views are supported.
|
|
633
|
+
* @param {DataType} dataType - The data type you want to get back from the server.
|
|
634
|
+
* Currently, `"csv"`, `"excel"` and `"json"` are supported.
|
|
422
635
|
* @param {object} options - Options
|
|
423
636
|
* @param {string} [options.fileName] - The file name to use; The file extension is appended by Cadenza.
|
|
424
637
|
* @param {TablePart[]} [options.parts] - Table parts to export; If not specified, all parts are exported.
|
|
425
638
|
* @throws For invalid arguments
|
|
426
639
|
*/
|
|
427
640
|
downloadData(source, dataType, { fileName, parts }) {
|
|
428
|
-
this.#log('CadenzaClient#downloadData',
|
|
429
|
-
assertSupportedDataType(dataType);
|
|
641
|
+
this.#log('CadenzaClient#downloadData', ...arguments);
|
|
642
|
+
assertSupportedDataType(dataType, ['csv', 'excel', 'json']);
|
|
430
643
|
const params = createParams({ dataType, fileName, parts });
|
|
431
644
|
this.#download(resolvePath(source), params);
|
|
432
645
|
}
|
|
@@ -452,7 +665,20 @@ export class CadenzaClient {
|
|
|
452
665
|
}
|
|
453
666
|
#log(/** @type unknown[] */ ...args) {
|
|
454
667
|
if (this.#debug) {
|
|
455
|
-
|
|
668
|
+
/** @type {unknown[]} */
|
|
669
|
+
const redundantValues = [undefined, '', false];
|
|
670
|
+
/** @type {(value: unknown) => value is object} */
|
|
671
|
+
const isObject = (/** @type {unknown} */ value) => value != null && typeof value === 'object';
|
|
672
|
+
const sanitizedArgs = args
|
|
673
|
+
.map((arg) => {
|
|
674
|
+
if (isObject(arg)) {
|
|
675
|
+
return Object.fromEntries(Object.entries(arg).filter(([, value]) => !redundantValues.includes(value)));
|
|
676
|
+
}
|
|
677
|
+
return arg;
|
|
678
|
+
})
|
|
679
|
+
.filter((arg) => !redundantValues.includes(arg) &&
|
|
680
|
+
!(isObject(arg) && Object.keys(arg).length === 0));
|
|
681
|
+
console.log(...sanitizedArgs);
|
|
456
682
|
}
|
|
457
683
|
}
|
|
458
684
|
}
|
|
@@ -529,11 +755,11 @@ function validUiFeature(/** @type string */ value) {
|
|
|
529
755
|
}
|
|
530
756
|
function assertSupportedDataType(
|
|
531
757
|
/** @type DataType */ type,
|
|
532
|
-
/** @type DataType[] */ supportedTypes
|
|
758
|
+
/** @type DataType[] */ supportedTypes) {
|
|
533
759
|
assert(supportedTypes.includes(type), `Invalid data type: ${type}`);
|
|
534
760
|
}
|
|
535
761
|
/**
|
|
536
|
-
* @param {object} params
|
|
762
|
+
* @param {object} params
|
|
537
763
|
* @param {string} [params.action]
|
|
538
764
|
* @param {DataType} [params.dataType]
|
|
539
765
|
* @param {UiFeature[]} [params.disabledUiFeatures]
|
|
@@ -545,16 +771,17 @@ function assertSupportedDataType(
|
|
|
545
771
|
* @param {boolean} [params.hideWorkbookToolBar]
|
|
546
772
|
* @param {GlobalId} [params.highlightGlobalId]
|
|
547
773
|
* @param {string} [params.labelSet]
|
|
774
|
+
* @param {WorkbookLayerPath[]} [params.layers]
|
|
548
775
|
* @param {string} [params.locationFinder]
|
|
549
776
|
* @param {Extent} [params.mapExtent]
|
|
550
777
|
* @param {number} [params.minScale]
|
|
551
778
|
* @param {OperationMode} [params.operationMode]
|
|
552
779
|
* @param {TablePart[]} [params.parts]
|
|
780
|
+
* @param {'MAP'} [params.targetType]
|
|
553
781
|
* @param {boolean} [params.useMapSrs]
|
|
554
|
-
* @param {ExternalLinkKey} [params.webApplication]
|
|
555
782
|
* @return {URLSearchParams}
|
|
556
783
|
*/
|
|
557
|
-
function createParams({ action, dataType, disabledUiFeatures, expandNavigator, fileName, filter, geometryType, hideMainHeaderAndFooter, hideWorkbookToolBar, highlightGlobalId, labelSet, locationFinder, mapExtent, minScale,
|
|
784
|
+
function createParams({ action, dataType, disabledUiFeatures, expandNavigator, fileName, filter, geometryType, hideMainHeaderAndFooter, hideWorkbookToolBar, highlightGlobalId, labelSet, layers, locationFinder, mapExtent, minScale, operationMode, parts, targetType, useMapSrs, }) {
|
|
558
785
|
if (disabledUiFeatures) {
|
|
559
786
|
disabledUiFeatures.forEach((feature) => assert(validUiFeature(feature), `Invalid UI feature: ${feature}`));
|
|
560
787
|
}
|
|
@@ -588,25 +815,76 @@ function createParams({ action, dataType, disabledUiFeatures, expandNavigator, f
|
|
|
588
815
|
...(hideWorkbookToolBar && { hideWorkbookToolBar: 'true' }),
|
|
589
816
|
...(highlightGlobalId && { highlightGlobalId }),
|
|
590
817
|
...(labelSet && { labelSet }),
|
|
818
|
+
...(layers &&
|
|
819
|
+
layers.length && {
|
|
820
|
+
layers: JSON.stringify(layers),
|
|
821
|
+
}),
|
|
591
822
|
...(locationFinder && { locationFinder }),
|
|
592
823
|
...(mapExtent && { mapExtent: mapExtent.join() }),
|
|
593
824
|
...(minScale && { minScale: String(minScale) }),
|
|
594
825
|
...(operationMode && operationMode !== 'normal' && { operationMode }),
|
|
595
826
|
...(parts && { parts: parts.join() }),
|
|
827
|
+
...(targetType && { targetType }),
|
|
596
828
|
...(useMapSrs && { useMapSrs: 'true' }),
|
|
597
|
-
...(webApplication && {
|
|
598
|
-
webApplicationLink: webApplication.externalLinkId,
|
|
599
|
-
webApplicationLinkRepository: webApplication.repositoryName,
|
|
600
|
-
}),
|
|
601
829
|
});
|
|
602
830
|
}
|
|
831
|
+
function array(/** @type unknown */ value) {
|
|
832
|
+
return Array.isArray(value) ? value : [value];
|
|
833
|
+
}
|
|
834
|
+
// Please do not add internal event types like 'ready' here.
|
|
835
|
+
/**
|
|
836
|
+
* @typedef {'change:selection'
|
|
837
|
+
* | 'drillThrough'
|
|
838
|
+
* | 'editGeometry:ok'
|
|
839
|
+
* | 'editGeometry:update'
|
|
840
|
+
* | 'editGeometry:cancel'
|
|
841
|
+
* | 'objectInfo'
|
|
842
|
+
* | 'selectObjects:ok'
|
|
843
|
+
* | 'selectObjects:cancel'
|
|
844
|
+
* } CadenzaEventType - An event type to subscribe to using {@link CadenzaClient#on}
|
|
845
|
+
*/
|
|
846
|
+
/**
|
|
847
|
+
* @template {CadenzaEventType} T
|
|
848
|
+
* @typedef {T extends 'change:selection' ? CadenzaChangeSelectionEvent
|
|
849
|
+
* : T extends 'drillThrough' ? CadenzaDrillThroughEvent
|
|
850
|
+
* : T extends 'editGeometry:update' ? CadenzaEditGeometryUpdateEvent
|
|
851
|
+
* : T extends 'editGeometry:ok' ? CadenzaEditGeometryOkEvent
|
|
852
|
+
* : T extends 'editGeometry:cancel' ? CadenzaEditGeometryCancelEvent
|
|
853
|
+
* : T extends 'objectInfo' ? CadenzaObjectInfoEvent
|
|
854
|
+
* : T extends 'selectObjects:ok' ? CadenzaSelectObjectsOkEvent
|
|
855
|
+
* : T extends 'selectObjects:cancel' ? CadenzaSelectObjectsCancelEvent
|
|
856
|
+
* : never
|
|
857
|
+
* } CadenzaEventByType
|
|
858
|
+
*/
|
|
603
859
|
/**
|
|
604
|
-
* @template
|
|
860
|
+
* @template {CadenzaEventType | string} TYPE
|
|
861
|
+
* @template [DETAIL=unknown]
|
|
605
862
|
* @typedef CadenzaEvent - A Cadenza `postMessage()` event
|
|
606
|
-
* @property {
|
|
607
|
-
* @property {
|
|
863
|
+
* @property {TYPE} type - The event type
|
|
864
|
+
* @property {DETAIL} detail - Optional event details (depending on the event type)
|
|
865
|
+
*/
|
|
866
|
+
/*
|
|
867
|
+
* @hidden
|
|
868
|
+
* @typedef {CadenzaEvent<'change:extent', {extent: Extent}>} CadenzaChangeExtentEvent - When the user moved the map.
|
|
869
|
+
* The extent is transformed according to the `useMapSrs` option.
|
|
870
|
+
*/
|
|
871
|
+
/** @typedef {CadenzaEvent<'change:selection', undefined | {layer: WorkbookLayerPath, values: unknown[][]}>} CadenzaChangeSelectionEvent - When the user changed the selection. */
|
|
872
|
+
/**
|
|
873
|
+
* @typedef {CadenzaEvent<'drillThrough', {values: unknown[][]}>} CadenzaDrillThroughEvent - When the user executed a POST message drill-through.
|
|
874
|
+
* <p>
|
|
875
|
+
* The event includes a data row for every item in the workbook selection, each row consisting of the values of
|
|
876
|
+
* the attributes that were selected for the POST message content. If the drill-through was executed from a map
|
|
877
|
+
* view, each row includes the geometry of the selected object as the last value.
|
|
878
|
+
* <p>
|
|
879
|
+
* See also: <a href="../index.html#md:json-representation-of-cadenza-object-data">JSON Representation of Cadenza Object Data</a>
|
|
608
880
|
*/
|
|
609
|
-
/** @typedef {CadenzaEvent<
|
|
881
|
+
/** @typedef {CadenzaEvent<'editGeometry:update', {geometry: Geometry}>} CadenzaEditGeometryUpdateEvent - When the user changed the geometry. */
|
|
882
|
+
/** @typedef {CadenzaEvent<'editGeometry:ok', {geometry: Geometry}>} CadenzaEditGeometryOkEvent - When the user submitted the geometry. */
|
|
883
|
+
/** @typedef {CadenzaEvent<'editGeometry:cancel'>} CadenzaEditGeometryCancelEvent - When the user cancelled the geometry editing. */
|
|
884
|
+
/** @typedef {CadenzaEvent<'error', {type: string, message?: string}>} CadenzaErrorEvent - An error event that is mapped to a {@link CadenzaError} */
|
|
885
|
+
/** @typedef {CadenzaEvent<'objectInfo', {layer: WorkbookLayerPath, objectInfos: {selectionIndex: number, formattedValues: Record<string, string>}[]}>} CadenzaObjectInfoEvent - When the user opened the object info flyout. */
|
|
886
|
+
/** @typedef {CadenzaEvent<'selectObjects:ok', {layer: WorkbookLayerPath, values: unknown[][]}>} CadenzaSelectObjectsOkEvent - When the user submitted the selection. */
|
|
887
|
+
/** @typedef {CadenzaEvent<'selectObjects:cancel'>} CadenzaSelectObjectsCancelEvent - When the user cancelled the selection. */
|
|
610
888
|
export class AbortError extends DOMException {
|
|
611
889
|
constructor() {
|
|
612
890
|
super('Aborted', 'AbortError');
|