@sapui5/sap.ushell_abap 1.150.0 → 1.151.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.
Files changed (49) hide show
  1. package/package.json +1 -1
  2. package/src/main/js/sap/ushell_abap/.library +1 -1
  3. package/src/main/js/sap/ushell_abap/adapters/abap/AppStateAdapter.js +5 -5
  4. package/src/main/js/sap/ushell_abap/adapters/abap/ClientSideTargetResolutionAdapter.js +7 -7
  5. package/src/main/js/sap/ushell_abap/adapters/abap/CommonDataModelAdapter.js +1 -1
  6. package/src/main/js/sap/ushell_abap/adapters/abap/ConfigurationDefaultsAdapter.js +1 -1
  7. package/src/main/js/sap/ushell_abap/adapters/abap/ContainerAdapter.js +1 -1
  8. package/src/main/js/sap/ushell_abap/adapters/abap/FlpLaunchPageAdapter.js +5 -5
  9. package/src/main/js/sap/ushell_abap/adapters/abap/LaunchPageAdapter.js +1 -1
  10. package/src/main/js/sap/ushell_abap/adapters/abap/NavTargetResolutionAdapter.js +1 -1
  11. package/src/main/js/sap/ushell_abap/adapters/abap/NavTargetResolutionInternalAdapter.js +1 -1
  12. package/src/main/js/sap/ushell_abap/adapters/abap/PageBuildingAdapter.js +1 -1
  13. package/src/main/js/sap/ushell_abap/adapters/abap/PagePersistenceAdapter.js +1 -1
  14. package/src/main/js/sap/ushell_abap/adapters/abap/PersonalizationAdapter.js +2 -2
  15. package/src/main/js/sap/ushell_abap/adapters/abap/PersonalizationV2Adapter.js +1 -1
  16. package/src/main/js/sap/ushell_abap/adapters/abap/SearchAdapter.js +1 -1
  17. package/src/main/js/sap/ushell_abap/adapters/abap/SupportTicketAdapter.js +4 -4
  18. package/src/main/js/sap/ushell_abap/adapters/abap/Ui5ComponentLoaderAdapter.js +1 -1
  19. package/src/main/js/sap/ushell_abap/adapters/hana/ContainerAdapter.js +1 -1
  20. package/src/main/js/sap/ushell_abap/appRuntime/ui5/libsPreload.js +4 -0
  21. package/src/main/js/sap/ushell_abap/base/Ui2Error.js +46 -0
  22. package/src/main/js/sap/ushell_abap/base/Ui2Utils.js +710 -0
  23. package/src/main/js/sap/ushell_abap/bootstrap/LoadLaunchpad.js +6 -0
  24. package/src/main/js/sap/ushell_abap/bootstrap/PageSetsRequestHandler.js +1 -1
  25. package/src/main/js/sap/ushell_abap/bootstrap/StartupRequestHandler.js +6 -6
  26. package/src/main/js/sap/ushell_abap/bootstrap/abapConstants.js +1 -0
  27. package/src/main/js/sap/ushell_abap/library.js +1 -1
  28. package/src/main/js/sap/ushell_abap/pbServices/ui2/AllCatalogs.js +1 -1
  29. package/src/main/js/sap/ushell_abap/pbServices/ui2/Bag.js +2 -2
  30. package/src/main/js/sap/ushell_abap/pbServices/ui2/Catalog.js +2 -2
  31. package/src/main/js/sap/ushell_abap/pbServices/ui2/Chip.js +2 -2
  32. package/src/main/js/sap/ushell_abap/pbServices/ui2/ChipDefinition.js +1 -1
  33. package/src/main/js/sap/ushell_abap/pbServices/ui2/ChipInstance.js +4 -4
  34. package/src/main/js/sap/ushell_abap/pbServices/ui2/Error.js +5 -37
  35. package/src/main/js/sap/ushell_abap/pbServices/ui2/Factory.js +3 -3
  36. package/src/main/js/sap/ushell_abap/pbServices/ui2/ODataService.js +2 -2
  37. package/src/main/js/sap/ushell_abap/pbServices/ui2/ODataWrapper.js +3 -3
  38. package/src/main/js/sap/ushell_abap/pbServices/ui2/Page.js +2 -2
  39. package/src/main/js/sap/ushell_abap/pbServices/ui2/PageBuildingService.js +2 -2
  40. package/src/main/js/sap/ushell_abap/pbServices/ui2/PageSet.js +2 -2
  41. package/src/main/js/sap/ushell_abap/pbServices/ui2/Utils.js +5 -703
  42. package/src/main/js/sap/ushell_abap/pbServices/ui2/contracts/actions.js +1 -1
  43. package/src/main/js/sap/ushell_abap/pbServices/ui2/contracts/bag.js +3 -3
  44. package/src/main/js/sap/ushell_abap/pbServices/ui2/contracts/configuration.js +3 -3
  45. package/src/main/js/sap/ushell_abap/pbServices/ui2/contracts/configurationUi.js +1 -1
  46. package/src/main/js/sap/ushell_abap/pbServices/ui2/contracts/search.js +3 -3
  47. package/src/main/js/sap/ushell_abap/pbServices/ui2/contracts/visible.js +1 -1
  48. package/src/main/js/sap/ushell_abap/services/NavigationDataProvider.js +126 -0
  49. package/ui5.yaml +32 -183
@@ -1,710 +1,12 @@
1
1
  // Copyright (c) 2009-2026 SAP SE, All Rights Reserved
2
2
 
3
- /* eslint-disable no-console */
4
-
5
3
  /**
6
- * @fileOverview This file contains miscellaneous utility functions.
4
+ * @fileOverview Deprecated re-export shim. Use "sap/ushell_abap/base/Ui2Utils" instead.
5
+ * @deprecated since 1.147.0 - use sap/ushell_abap/base/Ui2Utils
7
6
  */
8
-
9
7
  sap.ui.define([
10
- "sap/ui/thirdparty/URI",
11
- "sap/base/Log",
12
- "sap/ushell/Config",
13
- "sap/ushell_abap/pbServices/ui2/Error",
14
- "sap/ui/Device"
15
- ], (
16
- URI,
17
- Log,
18
- Config,
19
- SrvcError,
20
- Device
21
- ) => {
8
+ "sap/ushell_abap/base/Ui2Utils"
9
+ ], (Ui2Utils) => {
22
10
  "use strict";
23
-
24
- function Utils () { }
25
-
26
- // cache for GET requests
27
- let oCache;
28
-
29
- // "private static" methods **************************************************
30
-
31
- /**
32
- * Makes the given relative URL absolute. URLs containing host and/or protocol
33
- * and URLs with an absolute path remain unchanged. The URL is in no way
34
- * normalized; the function simply cuts off the file name from the base and
35
- * appends the relative URL.
36
- *
37
- * @param {string} sUrl
38
- * the (possibly server-relative) URL
39
- * @param {string} [sBase=location.href]
40
- * the base URL; it <b>must</b> at least be server-absolute
41
- * @returns {string}
42
- * the absolute URL
43
- * @since 1.2.0
44
- */
45
- Utils.absoluteUrl = function (sUrl, sBase) {
46
- /* jslint regexp: true */
47
-
48
- // default base is the page location
49
- sBase = sBase || window.location.href;
50
- // base must be absolute
51
- if (sBase.indexOf("://") < 0 && sBase.charAt(0) !== "/") {
52
- throw new SrvcError(`Illegal base URL: ${sBase}`);
53
- }
54
- // do not change empty or absolute URL
55
- if (!sUrl || sUrl.indexOf("://") >= 0 || sUrl.charAt(0) === "/") {
56
- return Utils.addCacheBusterTokenUsingUshellConfig(sUrl);
57
- }
58
- if (sBase.search(/^([^:]*:)?\/\/[^/]+$/) < 0) {
59
- // not a pure server URL -> cut off the file name
60
- sBase = sBase.replace(/\/[^/]*$/, "");
61
- }
62
- // append the relative path
63
- return Utils.addCacheBusterTokenUsingUshellConfig(`${sBase}/${sUrl}`);
64
- };
65
-
66
- /**
67
- * Calls the given success handler (a)synchronously. Errors thrown in the success handler are
68
- * caught and the error message is reported to the error handler; if an error stack is
69
- * available, it is logged.
70
- *
71
- * @param {function} fnSuccess
72
- * no-args success handler
73
- * @param {function(string)} [fnFailure]
74
- * error handler, taking an error message; MUST NOT throw any error itself!
75
- * @param {boolean} [bAsync=false]
76
- * whether the call shall be asynchronously
77
- * @since 1.2.0
78
- */
79
- Utils.callHandler = function (fnSuccess, fnFailure, bAsync) {
80
- // see also redundant declaration in sap.ushell.utils.call which has to be in sync
81
- if (bAsync) {
82
- setTimeout(() => {
83
- Utils.callHandler(fnSuccess, fnFailure, false);
84
- }, 0);
85
- return;
86
- }
87
-
88
- try {
89
- fnSuccess();
90
- } catch (oError) {
91
- const sMessage = oError.message || oError.toString();
92
- Log.error(`Call to success handler failed: ${sMessage}`, oError);
93
- if (fnFailure) {
94
- fnFailure(sMessage);
95
- }
96
- }
97
- };
98
-
99
- /**
100
- * GETs the given URL (as XML if indicated) and hands it to the given
101
- * success handler. As this is a root cause for asynchronous behaviour,
102
- * special precautions are taken: errors thrown in the success handler are
103
- * caught and reported to the error handler!
104
- *
105
- * @param {string} sUrl
106
- * URL for GET request
107
- * @param {boolean} bXml
108
- * whether the handler expects XML instead of plain text
109
- * @param {function(*)} fnSuccess
110
- * success handler, taking a DOM document or text string
111
- * @param {function(string, string)} fnFailure
112
- * error handler, taking an error message and (if http status is not OK) the GET response as
113
- * text; MUST NOT throw any error itself!
114
- * @param {object} [oXHR]
115
- * the XMLHttpRequest object which may be predefined (e.g. by setting request headers). If
116
- * <code>undefined</code>, a new XMLHttpRequest object is created.
117
- * @param {boolean} [bCache]
118
- * whether the response is cached for further calls (since 1.8.1). XML responses cannot be
119
- * cached. An Error is thrown if both <code>bXml</code> and
120
- * <code>bCache</code> are set to <code>true</code>.
121
- * @since 1.2.0
122
- */
123
- Utils.get = function (sUrl, bXml, fnSuccess, fnFailure, oXHR, bCache) {
124
- if (typeof fnSuccess !== "function") {
125
- throw new SrvcError("Missing success handler");
126
- }
127
- if (typeof fnFailure !== "function") {
128
- throw new SrvcError("Missing error handler");
129
- }
130
- if (bXml && bCache) {
131
- throw new SrvcError("Caching of XML responses not supported");
132
- }
133
- if (typeof Utils.addCacheBusterTokenUsingUshellConfig === "function") {
134
- sUrl = Utils.addCacheBusterTokenUsingUshellConfig(sUrl);
135
- }
136
- oXHR = oXHR || new XMLHttpRequest();
137
-
138
- /**
139
- * @private
140
- */
141
- oXHR.onreadystatechange = function () {
142
- let oResult;
143
- let oXml;
144
- // Note: "this" refers to oXHR according to W3C
145
- if (this.readyState !== /* DONE */4) {
146
- return; // not yet DONE
147
- }
148
- if (this.status !== /* OK */200) {
149
- // HTTP status not OK
150
- Log.error(`Error ${this.status} in response for URL ${sUrl}`,
151
- null);
152
- fnFailure(`${sUrl}: ${this.status} ${this.statusText}`, this.responseText);
153
- return;
154
- }
155
-
156
- Log.debug(`Received response for URL ${sUrl}`, null);
157
- if (bXml) {
158
- oXml = this.responseXML;
159
- if (oXml === null || !oXml.documentElement) {
160
- // in FF it is null, in IE it is a document with only an error message
161
- fnFailure(`${sUrl}: no valid XML`);
162
- return;
163
- }
164
- oResult = oXml;
165
- } else {
166
- oResult = this.responseText;
167
- if (bCache) {
168
- oCache.put(sUrl, oResult);
169
- }
170
- }
171
- Utils.callHandler(fnSuccess.bind(null, oResult), fnFailure);
172
- };
173
-
174
- if (!bXml && oCache.containsKey(sUrl)) {
175
- Log.debug(`Return cached response for URL ${sUrl}`, null);
176
- Utils.callHandler(fnSuccess.bind(null, oCache.get(sUrl)), fnFailure);
177
- } else {
178
- try {
179
- // Given that the XHR request could be provided as a parameter, we must
180
- // check that this was not already opened before calling open. One
181
- // reason this could happen is header settings. Only after opening the
182
- // request headers can be set. Calling open again will cause the
183
- // previous request to be aborted (i.e., headers loss).
184
- if (oXHR.readyState < XMLHttpRequest.OPENED) { // keep working on the opened request
185
- oXHR.open("GET", sUrl, /* asynchronously */true);
186
- } else {
187
- Log.debug(`XHR Request was already opened for ${sUrl}`, null);
188
- }
189
- oXHR.send();
190
- Log.debug(`Sent request to URL ${sUrl}`, null);
191
- } catch (oError) {
192
- Log.error(`Error '${oError.message || oError}' in request to URL ${sUrl}`,
193
- null);
194
- throw oError;
195
- }
196
- }
197
- };
198
-
199
- /**
200
- * Gets an URL and adds the given cache buster token to it if no other token is already
201
- * contained. In case the URL is no valid URL the token is not added.
202
- *
203
- * @param {string} sUrl
204
- * e.g. "/sap/bc/ui5_ui5/application/path"
205
- * URL to be changed
206
- * @param {RegExp} oPattern
207
- * e.g /^\/sap\/bc\/ui5_ui5\//
208
- * RegExp to determine if sUrl matches and needs to be extended by the cache buster token
209
- * sToken
210
- * @param {string} sReplacement
211
- * e.g. "/sap/bc/ui5_ui5/[CacheBusterToken]/"
212
- * The part of sUrl matched by oPattern will be exchanged by this. Before that is done sToken
213
- * is inserted in sReplacement at the position indicated by [CacheBusterToken]
214
- * The replacement may refer to capture groups of oPattern
215
- * @param {string} sToken
216
- * e.g. "~201412132350000~"
217
- * token to be inserted in sUrl. It will be inserted as indicated in the final constructed URL!
218
- * @returns {string}
219
- * - if sUrl did not matched oPattern: unchanged sUrl
220
- * - if sUrl matched oPattern: sUrl enhanced with sToken,
221
- * e.g. "/sap/bc/ui5_ui5/~201412132350000~/application/path"
222
- *
223
- * @private
224
- */
225
- Utils.addCacheBusterToken = function (sUrl, oPattern, sReplacement, sToken) {
226
- if (oPattern.test(sUrl)) { // url matches the pattern
227
- sUrl = sUrl.replace(oPattern, sReplacement);
228
- // replace the token placeholder globally in the final url (!)
229
- // (also allow the token to be added elsewhere)
230
- sUrl = sUrl.replace(/\[CacheBusterToken\]/g, sToken);
231
- }
232
- return sUrl;
233
- };
234
-
235
- /**
236
- * Removes a cache buster token (if available) of an Url and normalizes the url afterwards
237
- * @param {string} sUrl
238
- * the URL to be normalized
239
- * @returns {string}
240
- * normalized url (without a cache buster token)
241
- * @since 1.28.1
242
- *
243
- * @private
244
- */
245
- Utils.removeCBAndNormalizeUrl = function (sUrl) {
246
- let sUrlPrefix;
247
- let sCacheBusterSegment;
248
- let sUrlPostfix;
249
-
250
- function isUriWithRelativeOrEmptyPath (sUrl0) {
251
- const oUri = new URI(sUrl0);
252
- const sPath = oUri.path();
253
-
254
- if (oUri.is("absolute")) {
255
- return false;
256
- }
257
-
258
- if (sPath && sPath.charAt(0) === "/") {
259
- return false;
260
- }
261
-
262
- return true;
263
- }
264
-
265
- if (typeof sUrl !== "string" || sUrl === "" || isUriWithRelativeOrEmptyPath(sUrl)) {
266
- return sUrl;
267
- }
268
-
269
- // split up the URL into 3 parts: prefix, cache-buster segment, postfix
270
- // leading slashes are always part of the segment, the postfix might have a trailing slash
271
- const aMatches = sUrl.match(/(.*)(\/~[\w-]+~[A-Z0-9]?)(.*)/);
272
- if (aMatches) {
273
- sUrlPrefix = aMatches[1];
274
- sCacheBusterSegment = aMatches[2];
275
- sUrlPostfix = aMatches[3];
276
- }
277
-
278
- function normalizePath (sUrl0) {
279
- return new URI(sUrl0).normalizePathname().toString();
280
- }
281
-
282
- function isRelativePathWithDotSegmentsThatGoOutside (sPath) {
283
- const aSegments = new URI(sPath).segment();
284
- let i;
285
- let iPos = 0;
286
-
287
- for (i = 0; i < aSegments.length && iPos >= 0; i += 1) {
288
- if (aSegments[i] === "..") {
289
- iPos = iPos - 1;
290
- } else {
291
- iPos = iPos + 1;
292
- }
293
- }
294
-
295
- return iPos < 0;
296
- }
297
-
298
- // check if URL contains a cache-buster token
299
- if (sCacheBusterSegment) {
300
- // check if removal of cache-buster token is required
301
- if (sUrlPostfix && isRelativePathWithDotSegmentsThatGoOutside(sUrlPostfix)) {
302
- // remove the cache-buster token
303
- sUrl = sUrlPrefix + sUrlPostfix;
304
- }
305
- }
306
-
307
- // always normalize the URL path
308
- return normalizePath(sUrl);
309
- };
310
-
311
- /**
312
- * Gets an URL and adds the given cache buster token to it if no other token is already
313
- * contained. The rules to be applied are coming from the ushell configuration:
314
- * sap-ushell-config.cacheBusting.patterns
315
- * The rules are applied by there order property (lowest first) and the modified URL is returned
316
- * as soon as the first rule matched.
317
- * <p>
318
- * If the query parameter <code>sap-ushell-nocb</code> is set to <code>true</code> or <code>X</code>,
319
- * no cache buster tokens are added and existing cache buster tokens are removed from the specified URL.
320
- *
321
- * @param {string} sUrl
322
- * e.g. "/sap/bc/ui5_ui5/application/path"
323
- * URL to be changed
324
- * @returns {string}
325
- * - if sUrl already contained a cache buster token (e.g. ~00000~): unchanged sUrl
326
- * - if sUrl did not match any pattern: unchanged sUrl
327
- * - if sUrl matched pattern: sUrl enhanced with sToken,
328
- * e.g. "/sap/bc/ui5_ui5/~201412132350000~/application/path"
329
- * - if the modified sUrl (normalized and cache buster token was removed)
330
- * is found as an attribute of the config
331
- * (window["sap-ushell-config"].cacheBusting.urls),
332
- * the cache buster token which is defined as the value of this attribute
333
- * is going to be returned.
334
- *
335
- * @private
336
- */
337
- Utils.addCacheBusterTokenUsingUshellConfig = function (sUrl) {
338
- // TODO move to sap.ushell.utils
339
- const oCacheBusting = Config.getRawBootstrapConfig()?.cacheBusting;
340
- const oPatterns = oCacheBusting && oCacheBusting.patterns;
341
- let sCacheBusterUrl = sUrl;
342
- let aParameterMap = [];
343
- const aRules = [];
344
-
345
- aParameterMap = Utils.getParameterMap();
346
- const sSapUshellNoCb = aParameterMap["sap-ushell-nocb"] && aParameterMap["sap-ushell-nocb"][0];
347
-
348
- // When URL disables Cache Busting return URL without cache busting token
349
- // It can happen that we get a URL which already has a cache-buster token included (from the ABAP server), so we also remove
350
- // an existing token here (this implementation is simpler than passing the URL parameter to the resolveLink service and evaluate it there)
351
- if ((sSapUshellNoCb === "true" || sSapUshellNoCb === "X") && typeof sUrl === "string") {
352
- sUrl = sUrl.replace(/\/~[\w-]+~[A-Z0-9]?/, "");
353
- return sUrl;
354
- }
355
-
356
- // don't continue if the string is empty or a token is already present,
357
- // either as path segment (e.g.: /~0123_-Abc~/) or as query parameter
358
- // /e.g. ?cb=~xxxxxx~
359
- // also consider URLs with query parameters and fragments
360
- // this case happens during navigation, because this method is both called from
361
- // NavTargetResolutionInternal service as well as from the stubbed jQuery.sap.registerModulePath method
362
- //
363
- // syntax for application cache-buster contains now an additional scope qualifier that can be
364
- // either empty, "R" for resource, "5" for UI5 app, "W" for web app and "C" for custom
365
- // see ABAP class /UI5/CL_UI5_APP_HTTP_HANDLER for details
366
- if (!oCacheBusting
367
- || typeof sUrl !== "string"
368
- || sUrl === ""
369
- || /[/=]~[\w-]+~[A-Z0-9]?[/#?&]/.test(sUrl) // matches intermediate segment with cb-token; consider URLs with query string or fragment
370
- || /[/=]~[\w-]+~[A-Z0-9]?$/.test(sUrl)) { // matches last segment with cb-token (no trailing slash or further parameters)
371
- return sUrl;
372
- }
373
-
374
- if (oCacheBusting && oCacheBusting.urls) {
375
- // Removing the last slash of the input url
376
- if (sUrl.charAt(sUrl.length - 1) === "/") {
377
- sUrl = sUrl.substr(0, sUrl.length - 1);
378
- }
379
- // Config contains the modified url (without a slash at the end)
380
- if (oCacheBusting.urls.hasOwnProperty(sUrl)) {
381
- return `${sUrl}/${oCacheBusting.urls[sUrl].cacheBusterToken}`;
382
- }
383
- // Config contains the modified url (having a slash at the end)
384
- if (oCacheBusting.urls.hasOwnProperty(`${sUrl}/`)) {
385
- return `${sUrl}/${oCacheBusting.urls[`${sUrl}/`].cacheBusterToken}`;
386
- }
387
- }
388
-
389
- if (!oPatterns) {
390
- return sUrl;
391
- }
392
-
393
- // put rules in aRules and sort them by oRule.order
394
- Object.keys(oPatterns).forEach((sPattern) => {
395
- if (oPatterns.hasOwnProperty(sPattern)) {
396
- const oRule = oPatterns[sPattern];
397
- // the property name is the pattern to be used, copy it to the object itself for later
398
- oRule.pattern = new RegExp(sPattern);
399
- aRules.push(oRule);
400
- }
401
- });
402
- aRules.sort((oRule1, oRule2) => { return oRule1.order - oRule2.order; });
403
-
404
- // apply rules
405
- aRules.every((oRule) => { // use every to be able to break
406
- if (oRule.pattern.test(sUrl)) {
407
- if (!oRule.cacheBusterToken) {
408
- oRule.cacheBusterToken = oCacheBusting.cacheBusterToken;
409
- }
410
-
411
- // url matches the pattern, note that this is not redundant
412
- // one can define patterns without a replacement to match and end the matching process!
413
- sCacheBusterUrl = Utils.addCacheBusterToken(sUrl, oRule.pattern, oRule.replacement,
414
- oRule.cacheBusterToken);
415
- // break as soon as first rule matches (irrespective of alteration)
416
- return false;
417
- }
418
- return true;
419
- });
420
-
421
- return sCacheBusterUrl;
422
- };
423
-
424
- /**
425
- * Clear cache for GET requests.
426
- *
427
- * @since 1.8.1
428
- */
429
- Utils.clearCache = function () {
430
- oCache = new Utils.Map();
431
- };
432
-
433
- /**
434
- * Gets the device's form factor. Based on <code>sap.ui.Device.system</code> from SAPUI5.
435
- * @returns {string}
436
- * the device's form factor ("desktop", "tablet" or "phone")
437
- * @since 1.19.1
438
- */
439
- Utils.getFormFactor = function () {
440
- // see also redundant declaration in sap.ushell.utils.getFormFactor which has to be in sync
441
-
442
- if (Device.system.desktop) {
443
- return Device.system.SYSTEMTYPE.DESKTOP;
444
- }
445
- if (Device.system.tablet) {
446
- return Device.system.SYSTEMTYPE.TABLET;
447
- }
448
- if (Device.system.phone) {
449
- return Device.system.SYSTEMTYPE.PHONE;
450
- }
451
- };
452
-
453
- /**
454
- * Returns a map of all search parameters present in the given search string
455
- * or this window's current URL. To be precise, <code>location.search</code>
456
- * is used as a default and any given search string must use the same syntax
457
- * (start with a "?" and not include a "#").
458
- *
459
- * @param {string} [sSearchString=location.search]
460
- * search string starting with a "?" (unless empty) and not including a "#"
461
- * @returns {object}
462
- * a <code>map&lt;string, string[]></code> from key to array of values
463
- * @since 1.2.0
464
- *
465
- * @see <a href="http://java.sun.com/javaee/5/docs/api/javax/servlet/ServletRequest.html#getParameterMap()">
466
- * javax.servlet.ServletRequest#getParameterMap()</a>
467
- */
468
- Utils.getParameterMap = function (sSearchString) {
469
- let i;
470
- let n;
471
- const mResult = {};
472
- let sKey;
473
- let sValue;
474
- let iIndexOfEquals;
475
- // Note: location.search starts with "?" if not empty
476
- const sSearch = arguments.length > 0 ? sSearchString : window.location.search;
477
-
478
- if (sSearch && sSearch.charAt(0) !== "?") {
479
- throw new SrvcError(`Illegal search string ${sSearch}`);
480
- }
481
- if (!sSearch || sSearch === "?") {
482
- return {}; // Note: split("") would return [""]
483
- }
484
-
485
- // Note: W3C recommends that servers support ";" as well as "&"
486
- // (http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.2.2)
487
- // http://unixpapa.com/js/querystring.html advocates this on the client-side also!
488
- const aKeyValuePairs = sSearch.substring(1).replace(/\+/g, " ").split(/[&;]/);
489
- const aKeyValuePairsLength = aKeyValuePairs.length < 500 ? aKeyValuePairs.length : 500;
490
-
491
- for (i = 0, n = aKeyValuePairsLength; i < n; i += 1) {
492
- // decode key/value pair at first "=" character
493
- sKey = aKeyValuePairs[i];
494
- sValue = ""; // Note: empty value may be omitted altogether
495
- iIndexOfEquals = sKey.indexOf("=");
496
- if (iIndexOfEquals >= 0) {
497
- sValue = sKey.slice(iIndexOfEquals + 1);
498
- sValue = decodeURIComponent(sValue);
499
- sKey = sKey.slice(0, iIndexOfEquals);
500
- }
501
- sKey = decodeURIComponent(sKey);
502
-
503
- // map key to value(s)
504
- // Note: beware of inherited functions!
505
- if (!Object.prototype.hasOwnProperty.call(mResult, sKey)) {
506
- mResult[sKey] = [];
507
- }
508
- mResult[sKey].push(sValue);
509
- }
510
-
511
- return mResult;
512
- };
513
-
514
- /**
515
- * Returns the value of the given URL's GET parameter with the given name, properly decoded.
516
- * Returns "" if no such parameter can be found.
517
- *
518
- * @param {string} sUrl
519
- * any URL
520
- * @param {string} sName
521
- * the name of the GET parameter we are looking for
522
- * @returns {string}
523
- * the parameter value, properly decoded
524
- *
525
- * @private
526
- * @since 1.17.0
527
- */
528
- Utils.getParameterValue = function (sUrl, sName) {
529
- let oParameterMap;
530
-
531
- if (typeof sName !== "string") {
532
- // avoid surprises when sName would later be converted into a string
533
- throw new SrvcError("Missing parameter name");
534
- }
535
-
536
- sUrl = sUrl.split("#")[0];
537
- const iQueryIndex = sUrl.indexOf("?");
538
- if (iQueryIndex >= 0) {
539
- oParameterMap = Utils.getParameterMap(sUrl.slice(iQueryIndex));
540
- if (oParameterMap[sName]) {
541
- return oParameterMap[sName][0];
542
- }
543
- }
544
- return "";
545
- };
546
-
547
- /**
548
- * Tells whether the given value is an array.
549
- *
550
- * @param {object} o
551
- * any value
552
- * @returns {boolean}
553
- * <code>true</code> if and only if the given value is an array
554
- * @since 1.2.0
555
- */
556
- Utils.isArray = function (o) {
557
- // see Crockford page 61
558
- return Object.prototype.toString.apply(o) === "[object Array]";
559
- };
560
- /**
561
- * Tells whether the given value is a string.
562
- *
563
- * @param {object} o
564
- * any value
565
- * @returns {boolean}
566
- * <code>true</code> if and only if the given value is a string
567
- * @since 1.50.1
568
- */
569
- Utils.isString = function name (o) {
570
- return /String/.test(Object.prototype.toString.call(o));
571
- };
572
-
573
- /**
574
- * Parses the given XML string and returns it as a document.
575
- *
576
- * @param {string} sXml
577
- * the XML
578
- * @returns {DOMDocument}
579
- * a DOM document, or <code>null</code> in case of missing or empty XML string
580
- * @throws {Error}
581
- * in case of invalid XML string
582
- * @since 1.2.0
583
- */
584
- Utils.parseXml = function (sXml) {
585
- if (!sXml || typeof sXml !== "string") {
586
- return null;
587
- }
588
- const oXml = new DOMParser().parseFromString(sXml, "text/xml");
589
- if (oXml.getElementsByTagName("parsererror").length) { // Chrome, Firefox
590
- throw new SrvcError(`Invalid XML: ${sXml}`);
591
- }
592
- return oXml;
593
- };
594
-
595
- /**
596
- * Serves as a marker for functions that are to be exposed in QUnit tests. Calls to this function
597
- * are expected to be placed directly before the named function declaration (even <b>after</b>
598
- * the JSDoc). The function itself does nothing.
599
- *
600
- * @param {object} o
601
- * the object to which this function will be attached in tests; must not be <code>this</code>
602
- * (use <code>that</code> instead)
603
- * @since 1.3.0
604
- */
605
-
606
- // "public classes" **********************************************************
607
-
608
- /**
609
- * Creates an empty map. It is used for mapping from arbitrary string(!) keys (including "get" or
610
- * "hasOwnProperty") to values of any type.
611
- * @class
612
- * @since 1.5.0
613
- */
614
- Utils.Map = function () {
615
- this.entries = {};
616
- };
617
-
618
- /**
619
- * Associates the specified value with the specified key in this map. If the map previously
620
- * contained a mapping for the key, the old value is replaced by the specified value. Returns
621
- * the old value. Note: It might be a good idea to assert that the old value is
622
- * <code>undefined</code> in case you expect your keys to be unique.
623
- *
624
- * @param {string} sKey
625
- * key with which the specified value is to be associated
626
- * @param {any} vValue
627
- * value to be associated with the specified key
628
- * @returns {any}
629
- * the old value
630
- * @since 1.5.0
631
- */
632
- Utils.Map.prototype.put = function (sKey, vValue) {
633
- const vOldValue = this.get(sKey);
634
- this.entries[sKey] = vValue;
635
- return vOldValue;
636
- };
637
-
638
- /**
639
- * Returns <tt>true</tt> if this map contains a mapping for the specified key.
640
- *
641
- * @param {string} sKey
642
- * key whose presence in this map is to be tested
643
- * @returns {boolean}
644
- * <tt>true</tt> if this map contains a mapping for the specified key
645
- * @since 1.5.0
646
- */
647
- Utils.Map.prototype.containsKey = function (sKey) {
648
- if (typeof sKey !== "string") {
649
- throw new SrvcError(`Not a string key: ${sKey}`);
650
- }
651
- return Object.prototype.hasOwnProperty.call(this.entries, sKey);
652
- };
653
-
654
- /**
655
- * Returns the value to which the specified key is mapped, or <code>undefined</code> if this map
656
- * contains no mapping for the key.
657
- * @param {string} sKey
658
- * the key whose associated value is to be returned
659
- * @returns {any}
660
- * the value to which the specified key is mapped, or <code>undefined</code> if this map
661
- * contains no mapping for the key
662
- * @since 1.5.0
663
- */
664
- Utils.Map.prototype.get = function (sKey) {
665
- if (this.containsKey(sKey)) {
666
- return this.entries[sKey];
667
- }
668
- return undefined;
669
- };
670
-
671
- /**
672
- * Returns an array of this map's keys. This array is a snapshot of the map; concurrent
673
- * modifications of the map while iterating do not influence the sequence.
674
- * @returns {string[]}
675
- * this map's keys
676
- * @since 1.5.0
677
- */
678
- Utils.Map.prototype.keys = function () {
679
- return Object.keys(this.entries);
680
- };
681
-
682
- /**
683
- * Removes a key together with its value from the map.
684
- * @param {string} sKey
685
- * the map's key to be removed
686
- * @since 1.11.0
687
- */
688
- Utils.Map.prototype.remove = function (sKey) {
689
- delete this.entries[sKey];
690
- };
691
-
692
- /**
693
- * Returns this map's string representation.
694
- *
695
- * @returns {string}
696
- * this map's string representation
697
- * @since 1.5.0
698
- */
699
- Utils.Map.prototype.toString = function () {
700
- const aResult = ["Map("];
701
- aResult.push(JSON.stringify(this.entries));
702
- aResult.push(")");
703
- return aResult.join("");
704
- };
705
-
706
- // initialize the cache for GET
707
- Utils.clearCache();
708
-
709
- return Utils;
11
+ return Ui2Utils;
710
12
  });