|
@@ -1,5 +1,3 @@
|
1
|
|
-/* @flow */
|
2
|
|
-
|
3
|
1
|
/**
|
4
|
2
|
* The {@link RegExp} pattern of the authority of a URI.
|
5
|
3
|
*
|
|
@@ -127,6 +125,30 @@ export function getLocationContextRoot(location: Object) {
|
127
|
125
|
: pathname.substring(0, contextRootEndIndex + 1));
|
128
|
126
|
}
|
129
|
127
|
|
|
128
|
+/**
|
|
129
|
+ * Constructs a new {@code Array} with URL parameter {@code String}s out of a
|
|
130
|
+ * specific {@code Object}.
|
|
131
|
+ *
|
|
132
|
+ * @param {Object} obj - The {@code Object} to turn into URL parameter
|
|
133
|
+ * {@code String}s.
|
|
134
|
+ * @returns {Array<string>} The {@code Array} with URL parameter {@code String}s
|
|
135
|
+ * constructed out of the specified {@code obj}.
|
|
136
|
+ */
|
|
137
|
+function _objectToURLParamsArray(obj = {}) {
|
|
138
|
+ const params = [];
|
|
139
|
+
|
|
140
|
+ for (const key in obj) { // eslint-disable-line guard-for-in
|
|
141
|
+ try {
|
|
142
|
+ params.push(
|
|
143
|
+ `${key}=${encodeURIComponent(JSON.stringify(obj[key]))}`);
|
|
144
|
+ } catch (e) {
|
|
145
|
+ console.warn(`Error encoding ${key}: ${e}`);
|
|
146
|
+ }
|
|
147
|
+ }
|
|
148
|
+
|
|
149
|
+ return params;
|
|
150
|
+}
|
|
151
|
+
|
130
|
152
|
/**
|
131
|
153
|
* Parses a specific URI string into an object with the well-known properties of
|
132
|
154
|
* the {@link Location} and/or {@link URL} interfaces implemented by Web
|
|
@@ -147,7 +169,9 @@ export function getLocationContextRoot(location: Object) {
|
147
|
169
|
export function parseStandardURIString(str: string) {
|
148
|
170
|
/* eslint-disable no-param-reassign */
|
149
|
171
|
|
150
|
|
- const obj = {};
|
|
172
|
+ const obj = {
|
|
173
|
+ toString: _standardURIToString
|
|
174
|
+ };
|
151
|
175
|
|
152
|
176
|
let regex;
|
153
|
177
|
let match;
|
|
@@ -200,9 +224,7 @@ export function parseStandardURIString(str: string) {
|
200
|
224
|
str = str.substring(regex.lastIndex);
|
201
|
225
|
}
|
202
|
226
|
if (pathname) {
|
203
|
|
- if (!pathname.startsWith('/')) {
|
204
|
|
- pathname = `/${pathname}`;
|
205
|
|
- }
|
|
227
|
+ pathname.startsWith('/') || (pathname = `/${pathname}`);
|
206
|
228
|
} else {
|
207
|
229
|
pathname = '/';
|
208
|
230
|
}
|
|
@@ -263,6 +285,32 @@ export function parseURIString(uri: ?string) {
|
263
|
285
|
return obj;
|
264
|
286
|
}
|
265
|
287
|
|
|
288
|
+/**
|
|
289
|
+ * Implements {@code href} and {@code toString} for the {@code Object} returned
|
|
290
|
+ * by {@link #parseStandardURIString}.
|
|
291
|
+ *
|
|
292
|
+ * @param {Object} [thiz] - An {@code Object} returned by
|
|
293
|
+ * {@code #parseStandardURIString} if any; otherwise, it is presumed that the
|
|
294
|
+ * function is invoked on such an instance.
|
|
295
|
+ * @returns {string}
|
|
296
|
+ */
|
|
297
|
+function _standardURIToString(thiz: ?Object) {
|
|
298
|
+ // eslint-disable-next-line no-invalid-this
|
|
299
|
+ const { hash, host, pathname, protocol, search } = thiz || this;
|
|
300
|
+ let str = '';
|
|
301
|
+
|
|
302
|
+ protocol && (str += protocol);
|
|
303
|
+
|
|
304
|
+ // TODO userinfo
|
|
305
|
+
|
|
306
|
+ host && (str += `//${host}`);
|
|
307
|
+ str += pathname || '/';
|
|
308
|
+ search && (str += search);
|
|
309
|
+ hash && (str += hash);
|
|
310
|
+
|
|
311
|
+ return str;
|
|
312
|
+}
|
|
313
|
+
|
266
|
314
|
/**
|
267
|
315
|
* Attempts to return a {@code String} representation of a specific
|
268
|
316
|
* {@code Object} which is supposed to represent a URL. Obviously, if a
|
|
@@ -285,7 +333,7 @@ export function toURLString(obj: ?(string | Object)): ?string {
|
285
|
333
|
if (obj instanceof URL) {
|
286
|
334
|
str = obj.href;
|
287
|
335
|
} else {
|
288
|
|
- str = _urlObjectToString(obj);
|
|
336
|
+ str = urlObjectToString(obj);
|
289
|
337
|
}
|
290
|
338
|
}
|
291
|
339
|
break;
|
|
@@ -303,12 +351,103 @@ export function toURLString(obj: ?(string | Object)): ?string {
|
303
|
351
|
* {@code Object} similar to the one accepted by the constructor
|
304
|
352
|
* of Web's ExternalAPI.
|
305
|
353
|
*
|
306
|
|
- * @param {Object} obj - The URL to return a {@code String} representation of.
|
|
354
|
+ * @param {Object} o - The URL to return a {@code String} representation of.
|
307
|
355
|
* @returns {string} - A {@code String} representation of the specified
|
308
|
|
- * {@code obj}.
|
|
356
|
+ * {@code Object}.
|
309
|
357
|
*/
|
310
|
|
-function _urlObjectToString({ url }: Object): ?string {
|
311
|
|
- // TODO Support properties other than url. Support (pretty much) all
|
312
|
|
- // properties accepted by the constructor of Web's ExternalAPI.
|
313
|
|
- return url;
|
|
358
|
+export function urlObjectToString(o: Object): ?string {
|
|
359
|
+ const url = parseStandardURIString(o.url || '');
|
|
360
|
+
|
|
361
|
+ // protocol
|
|
362
|
+ if (!url.protocol) {
|
|
363
|
+ let protocol = o.protocol || o.scheme;
|
|
364
|
+
|
|
365
|
+ if (protocol) {
|
|
366
|
+ // Protocol is supposed to be the scheme and the final ':'. Anyway,
|
|
367
|
+ // do not make a fuss if the final ':' is not there.
|
|
368
|
+ protocol.endsWith(':') || (protocol += ':');
|
|
369
|
+ url.protocol = protocol;
|
|
370
|
+ }
|
|
371
|
+ }
|
|
372
|
+
|
|
373
|
+ // authority & pathname
|
|
374
|
+ let { pathname } = url;
|
|
375
|
+
|
|
376
|
+ if (!url.host) {
|
|
377
|
+ // Web's ExternalAPI domain
|
|
378
|
+ //
|
|
379
|
+ // It may be host/hostname and pathname with the latter denoting the
|
|
380
|
+ // tenant.
|
|
381
|
+ const { host, hostname, pathname: contextRoot, port }
|
|
382
|
+ = parseStandardURIString(o.domain || o.host || o.hostname);
|
|
383
|
+
|
|
384
|
+ // authority
|
|
385
|
+ if (host) {
|
|
386
|
+ url.host = host;
|
|
387
|
+ url.hostname = hostname;
|
|
388
|
+ url.port = port;
|
|
389
|
+ }
|
|
390
|
+
|
|
391
|
+ // pathname
|
|
392
|
+ pathname === '/' && contextRoot !== '/' && (pathname = contextRoot);
|
|
393
|
+ }
|
|
394
|
+
|
|
395
|
+ // pathname
|
|
396
|
+
|
|
397
|
+ // Web's ExternalAPI roomName
|
|
398
|
+ const room = o.roomName || o.room;
|
|
399
|
+
|
|
400
|
+ if (room
|
|
401
|
+ && (url.pathname.endsWith('/')
|
|
402
|
+ || !url.pathname.endsWith(`/${room}`))) {
|
|
403
|
+ pathname.endsWith('/') || (pathname += '/');
|
|
404
|
+ pathname += room;
|
|
405
|
+ }
|
|
406
|
+
|
|
407
|
+ url.pathname = pathname;
|
|
408
|
+
|
|
409
|
+ // query/search
|
|
410
|
+
|
|
411
|
+ // Web's ExternalAPI jwt
|
|
412
|
+ const { jwt } = o;
|
|
413
|
+
|
|
414
|
+ if (jwt) {
|
|
415
|
+ let { search } = url;
|
|
416
|
+
|
|
417
|
+ if (search.indexOf('?jwt=') === -1 && search.indexOf('&jwt=') === -1) {
|
|
418
|
+ search.startsWith('?') || (search = `?${search}`);
|
|
419
|
+ search.length === 1 || (search += '&');
|
|
420
|
+ search += `jwt=${jwt}`;
|
|
421
|
+
|
|
422
|
+ url.search = search;
|
|
423
|
+ }
|
|
424
|
+ }
|
|
425
|
+
|
|
426
|
+ // fragment/hash
|
|
427
|
+
|
|
428
|
+ let { hash } = url;
|
|
429
|
+
|
|
430
|
+ for (const configName of [ 'config', 'interfaceConfig' ]) {
|
|
431
|
+ const urlParamsArray
|
|
432
|
+ = _objectToURLParamsArray(
|
|
433
|
+ o[`${configName}Overwrite`]
|
|
434
|
+ || o[configName]
|
|
435
|
+ || o[`${configName}Override`]);
|
|
436
|
+
|
|
437
|
+ if (urlParamsArray.length) {
|
|
438
|
+ let urlParamsString
|
|
439
|
+ = `${configName}.${urlParamsArray.join(`&${configName}.`)}`;
|
|
440
|
+
|
|
441
|
+ if (hash.length) {
|
|
442
|
+ urlParamsString = `&${urlParamsString}`;
|
|
443
|
+ } else {
|
|
444
|
+ hash = '#';
|
|
445
|
+ }
|
|
446
|
+ hash += urlParamsString;
|
|
447
|
+ }
|
|
448
|
+ }
|
|
449
|
+
|
|
450
|
+ url.hash = hash;
|
|
451
|
+
|
|
452
|
+ return url.toString() || undefined;
|
314
|
453
|
}
|