@reveldigital/player-client 1.0.15 → 2.0.2

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 (58) hide show
  1. package/README.md +236 -236
  2. package/esm2022/lib/app-init.service.mjs +113 -0
  3. package/esm2022/lib/interfaces/client.interface.mjs +2 -0
  4. package/esm2022/lib/interfaces/command.interface.mjs +2 -0
  5. package/esm2022/lib/interfaces/config.interface.mjs +50 -0
  6. package/esm2022/lib/interfaces/device.interface.mjs +2 -0
  7. package/esm2022/lib/interfaces/event-properties.interface.mjs +2 -0
  8. package/esm2022/lib/interfaces/location.interface.mjs +2 -0
  9. package/esm2022/lib/player-client.module.mjs +71 -0
  10. package/esm2022/lib/player-client.service.mjs +928 -0
  11. package/esm2022/lib/safe-style.pipe.mjs +41 -0
  12. package/{esm2020 → esm2022}/lib/version.mjs +3 -3
  13. package/{esm2020 → esm2022}/public-api.mjs +6 -6
  14. package/{esm2020 → esm2022}/reveldigital-player-client.mjs +4 -4
  15. package/{fesm2020 → fesm2022}/reveldigital-player-client.mjs +1132 -1134
  16. package/fesm2022/reveldigital-player-client.mjs.map +1 -0
  17. package/{reveldigital-player-client.d.ts → index.d.ts} +5 -5
  18. package/lib/app-init.service.d.ts +18 -18
  19. package/lib/app-init.service.d.ts.map +1 -1
  20. package/lib/interfaces/client.interface.d.ts +406 -406
  21. package/lib/interfaces/command.interface.d.ts +78 -78
  22. package/lib/interfaces/config.interface.d.ts +151 -151
  23. package/lib/interfaces/device.interface.d.ts +139 -139
  24. package/lib/interfaces/event-properties.interface.d.ts +134 -134
  25. package/lib/interfaces/location.interface.d.ts +187 -187
  26. package/lib/player-client.module.d.ts +9 -9
  27. package/lib/player-client.service.d.ts +640 -640
  28. package/lib/safe-style.pipe.d.ts +23 -23
  29. package/lib/safe-style.pipe.d.ts.map +1 -1
  30. package/lib/version.d.ts +1 -1
  31. package/lib/version.d.ts.map +1 -1
  32. package/package.json +12 -18
  33. package/public-api.d.ts +3 -3
  34. package/schematics/collection.json +15 -15
  35. package/schematics/ng-add/assets/gadget.yaml +54 -54
  36. package/schematics/ng-add/index.d.ts +18 -4
  37. package/schematics/ng-add/index.js +391 -287
  38. package/schematics/ng-add/index.js.map +1 -1
  39. package/schematics/ng-add/schema.d.ts +4 -4
  40. package/schematics/ng-add/schema.js +2 -2
  41. package/schematics/ng-add/schema.json +23 -23
  42. package/schematics/ng-add/templates/index.html +30 -30
  43. package/schematics/ng-add/templates/polyfills.ts +72 -72
  44. package/schematics/ng-add/utils/changeBasePath.js +19 -19
  45. package/schematics/ng-add/utils/yml2xml.js +132 -132
  46. package/esm2020/lib/app-init.service.mjs +0 -110
  47. package/esm2020/lib/interfaces/client.interface.mjs +0 -2
  48. package/esm2020/lib/interfaces/command.interface.mjs +0 -2
  49. package/esm2020/lib/interfaces/config.interface.mjs +0 -50
  50. package/esm2020/lib/interfaces/device.interface.mjs +0 -2
  51. package/esm2020/lib/interfaces/event-properties.interface.mjs +0 -2
  52. package/esm2020/lib/interfaces/location.interface.mjs +0 -2
  53. package/esm2020/lib/player-client.module.mjs +0 -73
  54. package/esm2020/lib/player-client.service.mjs +0 -928
  55. package/esm2020/lib/safe-style.pipe.mjs +0 -40
  56. package/fesm2015/reveldigital-player-client.mjs +0 -1219
  57. package/fesm2015/reveldigital-player-client.mjs.map +0 -1
  58. package/fesm2020/reveldigital-player-client.mjs.map +0 -1
@@ -11,1148 +11,1146 @@ import { RouterModule } from '@angular/router';
11
11
  import { APP_BASE_HREF } from '@angular/common';
12
12
  import * as i1$1 from '@angular/platform-browser';
13
13
 
14
- // Generated by genversion.
15
- const version = '1.0.15';
14
+ // Generated by genversion.
15
+ const version = '2.0.2';
16
16
 
17
- /**
18
- * Service for interacting with the Revel Digital player client.
19
- *
20
- * This service provides a comprehensive interface for gadgets and web applications
21
- * to communicate with the Revel Digital player environment. It handles device
22
- * information, commands, events, analytics tracking, and configuration management.
23
- *
24
- * The service supports both direct API calls and event-based communication patterns,
25
- * allowing gadgets to respond to player lifecycle events (start, stop, commands) and
26
- * send data back to the player or remote devices.
27
- *
28
- * ```typescript
29
- * constructor(private client: PlayerClientService) {
30
- * // Subscribe to player events
31
- * this.client.onStart$.subscribe(() => {
32
- * console.log('Gadget started');
33
- * });
34
- *
35
- * this.client.onCommand$.subscribe(command => {
36
- * console.log('Received command:', command);
37
- * });
38
- * }
39
- *
40
- * async ngOnInit() {
41
- * // Get device information
42
- * const device = await this.client.getDevice();
43
- * const deviceTime = await this.client.getDeviceTime();
44
- *
45
- * // Track analytics
46
- * this.client.track('gadget_loaded', { version: '1.0' });
47
- * }
48
- * ```
49
- *
50
- * @since 1.0.0
51
- */
52
- class PlayerClientService {
53
- /** @ignore */
54
- constructor(zone) {
55
- /**
56
- * Observable stream of commands sent to this player from the Revel Digital platform.
57
- * Subscribe to this to handle custom commands sent from templates, playlists, or remote devices.
58
- *
59
- * ```typescript
60
- * this.client.onCommand$.subscribe(command => {
61
- * if (command.name === 'customAction') {
62
- * this.handleCustomAction(command.arg);
63
- * }
64
- * });
65
- * ```
66
- */
67
- this.onCommand$ = new Subject();
68
- /**
69
- * Observable that signals when the gadget has been loaded and is ready to start.
70
- * Emits `true` when ready, `false` when destroyed.
71
- *
72
- * ```typescript
73
- * this.client.onReady$.subscribe(isReady => {
74
- * if (isReady) {
75
- * console.log('Client is ready');
76
- * this.initializeGadget();
77
- * }
78
- * });
79
- * ```
80
- */
81
- this.onReady$ = new BehaviorSubject(false);
82
- /**
83
- * Observable that signals when the gadget has been started by the player.
84
- * This event occurs when the player begins execution of the gadget content.
85
- *
86
- * ```typescript
87
- * this.client.onStart$.subscribe(() => {
88
- * console.log('Gadget started');
89
- * this.startAnimation();
90
- * });
91
- * ```
92
- */
93
- this.onStart$ = new Subject();
94
- /**
95
- * Observable that signals when the gadget has been stopped by the player.
96
- * This event occurs when the player stops execution, typically when moving
97
- * to the next item in a playlist or when the content duration expires.
98
- *
99
- * ```typescript
100
- * this.client.onStop$.subscribe(() => {
101
- * console.log('Gadget stopped');
102
- * this.cleanup();
103
- * });
104
- * ```
105
- */
106
- this.onStop$ = new Subject();
107
- /**
108
- * Observable that signals when the gadget should open the configuration window.
109
- * This allows gadgets to respond to configuration requests from the player.
110
- *
111
- * ```typescript
112
- * this.client.onConfig$.subscribe(() => {
113
- * this.openConfigurationDialog();
114
- * });
115
- * ```
116
- */
117
- this.onConfig$ = new Subject();
118
- /**
119
- * Observable that signals when the gadget has received a postMessage event from the player.
120
- * This handles communication between the gadget and player via the postMessage API.
121
- *
122
- * ```typescript
123
- * this.client.onPostMessage$.subscribe(message => {
124
- * console.log('Received message:', message);
125
- * this.handlePlayerMessage(message);
126
- * });
127
- * ```
128
- */
129
- this.onPostMessage$ = new Subject();
130
- /** @ignore */
131
- this.onStartEvt$ = fromEvent(window, 'RevelDigital.Start').pipe(share(), tap(this.onStart$));
132
- /** @ignore */
133
- this.onStopEvt$ = fromEvent(window, 'RevelDigital.Stop').pipe(share(), tap(this.onStop$));
134
- /** @ignore */
135
- this.onCommandEvt$ = fromEvent(window, 'RevelDigital.Command').pipe(map((e) => { return { name: e.detail.name, arg: e.detail.arg }; }), share(), tap(this.onCommand$));
136
- this.onPostMessageEvt$ = fromEvent(window, 'message').pipe(filter((messageEvent) =>
137
- //messageEvent.source !== window.parent &&
138
- typeof messageEvent.data === 'string'), map((e) => JSON.parse(e.data)), share(), tap((e) => {
139
- if (e.type === 'applyConfig' && e.isOpener) {
140
- e.isOpener = false;
141
- // propagate config to iframe parent from the popup window
142
- window.parent.postMessage(JSON.stringify(e), '*');
143
- }
144
- else if (e.type === 'openConfig') {
145
- this.onConfig$.next(null);
146
- }
147
- }), tap(e => this.onPostMessage$.next(e)));
148
- let self = this;
149
- window.RevelDigital = {
150
- Controller: {
151
- onCommand: function (name, arg) {
152
- zone.run(() => {
153
- self.onCommand$.next({ name: name, arg: arg });
154
- });
155
- },
156
- onStart: function () {
157
- zone.run(() => {
158
- self.onStart$.next(null);
159
- });
160
- },
161
- onStop: function () {
162
- zone.run(() => {
163
- self.onStop$.next(null);
164
- });
165
- }
166
- }
167
- };
168
- this.onStartSub = this.onStartEvt$.subscribe(() => { });
169
- this.onStopSub = this.onStopEvt$.subscribe(() => { });
170
- this.onCommandSub = this.onCommandEvt$.subscribe(() => { });
171
- //this.onConfigSub = this.onConfigEvt$.subscribe(() => { });
172
- this.onPostMessageSub = this.onPostMessageEvt$.subscribe(() => { });
173
- this.clientPromise = null;
174
- this.onReady$.next(true);
175
- }
176
- /** @ignore */
177
- ngOnDestroy() {
178
- this.onStartSub?.unsubscribe();
179
- this.onStopSub?.unsubscribe();
180
- this.onCommandSub?.unsubscribe();
181
- //this.onConfigSub?.unsubscribe();
182
- this.onPostMessageSub?.unsubscribe();
183
- this.onReady$.next(false);
184
- }
185
- /** @ignore */
186
- static init(data) {
187
- console.log('%c⚙️ Initializing Revel Digital client library', 'background-color:blue; color:yellow;');
188
- }
189
- /**
190
- * Sends a callback to player scripting with variable arguments.
191
- *
192
- * This method allows the gadget to communicate with player scripting.
193
- * If the appropriate scripting is in place in the currently running template,
194
- * calling this method will initiate a callback which can be acted upon in player script.
195
- *
196
- * @param args - Variable number of arguments to pass to the callback (max 5 arguments)
197
- *
198
- * ```typescript
199
- * // Send a simple callback
200
- * this.client.callback('test', 'data');
201
- *
202
- * // Send multiple parameters
203
- * this.client.callback('action', 'value1', 'value2', { data: 'object' });
204
- * ```
205
- */
206
- callback(...args) {
207
- this.getClient().then((client) => {
208
- switch (args.length) {
209
- case 0:
210
- client.callback();
211
- break;
212
- case 1:
213
- client.callback(args[0]);
214
- break;
215
- case 2:
216
- client.callback(args[1]);
217
- break;
218
- case 3:
219
- client.callback(args[2]);
220
- break;
221
- case 4:
222
- client.callback(args[3]);
223
- break;
224
- case 5:
225
- client.callback(args[4]);
226
- break;
227
- }
228
- });
229
- }
230
- /**
231
- * Gets the user preferences interface exposed by the Google Gadgets API.
232
- *
233
- * This method provides access to gadget preferences which can be configured
234
- * in the Revel Digital CMS. Use this to retrieve user-configurable settings
235
- * for your gadget.
236
- *
237
- * @returns The Gadgets API Prefs object for accessing preference values
238
- *
239
- * ```typescript
240
- * constructor(public client: PlayerClientService) {
241
- * const prefs = client.getPrefs();
242
- * const myString = prefs.getString('myStringPref');
243
- * const myNumber = prefs.getInt('myNumberPref');
244
- * const myBool = prefs.getBool('myBoolPref');
245
- * }
246
- * ```
247
- *
248
- * @see {@link https://developers.google.com/gadgets/docs/basic} Google Gadgets API documentation
249
- */
250
- getPrefs() {
251
- return new window['gadgets']['Prefs']();
252
- }
253
- /**
254
- * Gets the current device time in ISO8601 format.
255
- *
256
- * Current device time is determined by the device timezone assigned to the device in the CMS.
257
- * This is useful for displaying time-sensitive content or scheduling operations based on
258
- * the device's local time rather than browser time.
259
- *
260
- * @param date - Optional. If supplied, will translate the supplied date/time to device time based on respective timezones
261
- * @returns Promise resolving to date/time in ISO8601 format
262
- *
263
- * ```typescript
264
- * // Get current device time
265
- * const currentTime = await this.client.getDeviceTime();
266
- * console.log('Device time:', currentTime);
267
- *
268
- * // Convert a specific date to device time
269
- * const specificDate = new Date('2023-01-01T12:00:00Z');
270
- * const deviceTime = await this.client.getDeviceTime(specificDate);
271
- * ```
272
- */
273
- async getDeviceTime(date) {
274
- const client = await this.getClient();
275
- if (date !== undefined) {
276
- return client.getDeviceTime(date);
277
- }
278
- return client.getDeviceTime();
279
- }
280
- /**
281
- * Gets the timezone name currently assigned to the device.
282
- *
283
- * @returns Promise resolving to the timezone name (e.g., "America/New_York")
284
- *
285
- * ```typescript
286
- * const timezoneName = await this.client.getDeviceTimeZoneName();
287
- * console.log('Device timezone:', timezoneName);
288
- * ```
289
- */
290
- async getDeviceTimeZoneName() {
291
- const client = await this.getClient();
292
- return client.getDeviceTimeZoneName();
293
- }
294
- /**
295
- * Gets the timezone ID currently assigned to the device.
296
- *
297
- * @returns Promise resolving to the timezone ID
298
- *
299
- * ```typescript
300
- * const timezoneId = await this.client.getDeviceTimeZoneID();
301
- * console.log('Device timezone ID:', timezoneId);
302
- * ```
303
- */
304
- async getDeviceTimeZoneID() {
305
- const client = await this.getClient();
306
- return client.getDeviceTimeZoneID();
307
- }
308
- /**
309
- * Gets the numerical offset from GMT of the timezone currently assigned to the device.
310
- *
311
- * @returns Promise resolving to the timezone offset in hours (e.g., -5 for EST)
312
- *
313
- * ```typescript
314
- * const offset = await this.client.getDeviceTimeZoneOffset();
315
- * console.log('Device timezone offset:', offset, 'hours from GMT');
316
- * ```
317
- */
318
- async getDeviceTimeZoneOffset() {
319
- const client = await this.getClient();
320
- return client.getDeviceTimeZoneOffset();
321
- }
322
- /**
323
- * Gets the language code of the language currently assigned to the device.
324
- *
325
- * @returns Promise resolving to the language code (e.g., "en-US", "fr-FR")
326
- *
327
- * ```typescript
328
- * const languageCode = await this.client.getLanguageCode();
329
- * console.log('Device language:', languageCode);
330
- * // Use for localization
331
- * this.loadLanguageResources(languageCode);
332
- * ```
333
- */
334
- async getLanguageCode() {
335
- const client = await this.getClient();
336
- return client.getLanguageCode();
337
- }
338
- /**
339
- * Gets the unique Revel Digital device key associated with the device.
340
- *
341
- * The device key is a unique identifier for this specific player device
342
- * and can be used for device-specific operations or remote commands.
343
- *
344
- * @returns Promise resolving to the device key string
345
- *
346
- * ```typescript
347
- * const deviceKey = await this.client.getDeviceKey();
348
- * console.log('Device key:', deviceKey);
349
- * ```
350
- */
351
- async getDeviceKey() {
352
- const client = await this.getClient();
353
- return client.getDeviceKey();
354
- }
355
- /**
356
- * Sends a command to the local player device.
357
- *
358
- * Commands can be used to control various aspects of the player or trigger
359
- * specific behaviors. The command is processed by the local player only.
360
- *
361
- * @param name - The command name/identifier
362
- * @param arg - The command argument/payload
363
- *
364
- * ```typescript
365
- * // Send a simple command
366
- * this.client.sendCommand('refresh', '');
367
- *
368
- * // Send a command with data
369
- * this.client.sendCommand('setVolume', '50');
370
- *
371
- * // Send a command with JSON data
372
- * this.client.sendCommand('configure', JSON.stringify({ setting: 'value' }));
373
- * ```
374
- */
375
- sendCommand(name, arg) {
376
- this.getClient().then((client) => {
377
- client.sendCommand(name, arg);
378
- });
379
- }
380
- /**
381
- * Sends a command to remote player devices with the specified device keys.
382
- *
383
- * Remote commands allow cross-device communication within the same Revel Digital account.
384
- * This is useful for synchronized displays, device coordination, or remote control scenarios.
385
- *
386
- * Note: Remote commands can only be delivered to devices within the same account as the sender device.
387
- *
388
- * @param deviceKeys - Array of target device keys to send the command to
389
- * @param name - The command name/identifier
390
- * @param arg - The command argument/payload
391
- *
392
- * ```typescript
393
- * // Send command to specific devices
394
- * const targetDevices = ['device-key-1', 'device-key-2'];
395
- * this.client.sendRemoteCommand(targetDevices, 'syncAction', 'start');
396
- *
397
- * // Broadcast to multiple devices
398
- * this.client.sendRemoteCommand(
399
- * ['lobby-display', 'kiosk-1', 'kiosk-2'],
400
- * 'updateContent',
401
- * JSON.stringify({ contentId: '12345' })
402
- * );
403
- * ```
404
- */
405
- sendRemoteCommand(deviceKeys, name, arg) {
406
- this.getClient().then((client) => {
407
- client.sendRemoteCommand(deviceKeys, name, arg);
408
- });
409
- }
410
- /**
411
- * Logs an analytics event for use with AdHawk analytics and reporting.
412
- *
413
- * Events are used for tracking various metrics including usage statistics,
414
- * player condition, state changes, user interactions, and custom business metrics.
415
- * These events can be viewed in the Revel Digital analytics dashboard.
416
- *
417
- * @param eventName - Unique name for this event (should be descriptive and consistent)
418
- * @param properties - Optional map of user-defined properties to associate with this event
419
- *
420
- * ```typescript
421
- * // Simple event tracking
422
- * this.client.track('gadget_loaded');
423
- *
424
- * // Event with properties
425
- * this.client.track('user_interaction', {
426
- * action: 'button_click',
427
- * button_id: 'start_button',
428
- * timestamp: new Date().toISOString()
429
- * });
430
- *
431
- * // Performance tracking
432
- * this.client.track('content_displayed', {
433
- * content_type: 'video',
434
- * duration: 30,
435
- * quality: 'HD'
436
- * });
437
- * ```
438
- */
439
- track(eventName, properties) {
440
- this.getClient().then((client) => {
441
- client.track(eventName, JSON.stringify(properties));
442
- });
443
- }
444
- /**
445
- * Initiates a timed event for duration tracking.
446
- *
447
- * Timed events are useful for tracking the duration of operations or user interactions.
448
- * This method must be followed by a call to track() with the same event name to complete
449
- * the timing measurement. The duration will be automatically calculated and included
450
- * in the event properties.
451
- *
452
- * @param eventName - Unique name for this timed event (must match the subsequent track() call)
453
- *
454
- * ```typescript
455
- * // Start timing an event
456
- * this.client.timeEvent('video_playback');
457
- *
458
- * // ... video plays for some duration ...
459
- *
460
- * // End timing and log the event with duration
461
- * this.client.track('video_playback', {
462
- * video_id: 'abc123',
463
- * quality: 'HD'
464
- * }); // Duration will be automatically added
465
- *
466
- * // Example for user interaction timing
467
- * this.client.timeEvent('form_completion');
468
- * // ... user fills out form ...
469
- * this.client.track('form_completion', { form_type: 'contact' });
470
- * ```
471
- */
472
- timeEvent(eventName) {
473
- this.getClient().then((client) => {
474
- client.timeEvent(eventName);
475
- });
476
- }
477
- /**
478
- * Creates a new analytics event session for grouping related events.
479
- *
480
- * A session is a way of grouping events together for analysis. Each event tracked
481
- * after calling this method will have the same session ID until a new session is created.
482
- * Session IDs are randomly generated unless explicitly provided.
483
- *
484
- * This is useful for tracking user journeys, workflow completion, or grouping
485
- * related interactions within a specific time period.
486
- *
487
- * @param id - Optional user-supplied session ID. If not provided, a random session ID will be generated
488
- *
489
- * ```typescript
490
- * // Start a new session with auto-generated ID
491
- * this.client.newEventSession();
492
- * this.client.track('session_start');
493
- * this.client.track('user_action_1');
494
- * this.client.track('user_action_2');
495
- *
496
- * // Start a session with custom ID
497
- * this.client.newEventSession('user-workflow-12345');
498
- * this.client.track('workflow_start');
499
- * this.client.track('step_completed', { step: 1 });
500
- *
501
- * // Start a new session for different workflow
502
- * this.client.newEventSession();
503
- * this.client.track('different_workflow_start');
504
- * ```
505
- */
506
- newEventSession(id) {
507
- this.getClient().then((client) => {
508
- if (id !== undefined) {
509
- client.newEventSession();
510
- }
511
- else {
512
- client.newEventSession(id);
513
- }
514
- });
515
- }
516
- /**
517
- * Gets the root folder path utilized by this player device.
518
- *
519
- * This returns the base directory path where the Revel Digital player
520
- * stores its files and resources on the local device.
521
- *
522
- * @returns Promise resolving to the path of the root folder
523
- *
524
- * ```typescript
525
- * const rootPath = await this.client.getRevelRoot();
526
- * console.log('Player root directory:', rootPath);
527
- * // Use for constructing file paths or understanding storage structure
528
- * ```
529
- */
530
- async getRevelRoot() {
531
- const client = await this.getClient();
532
- return client.getRevelRoot();
533
- }
534
- /**
535
- * Gets a map of commands currently active for this device.
536
- *
537
- * This returns the current command configuration that defines how the device
538
- * responds to various command triggers and remote commands.
539
- *
540
- * @returns Promise resolving to a map of currently active commands
541
- *
542
- * ```typescript
543
- * const commandMap = await this.client.getCommandMap();
544
- * console.log('Active commands:', commandMap);
545
- *
546
- * // Check if specific command is available
547
- * if (commandMap['customCommand']) {
548
- * console.log('Custom command is available');
549
- * }
550
- * ```
551
- */
552
- async getCommandMap() {
553
- const client = await this.getClient();
554
- return JSON.parse(await client.getCommandMap());
555
- }
556
- /**
557
- * Signals to the player that this gadget has completed its visualization.
558
- *
559
- * This method notifies the player that the current gadget has finished its
560
- * content display or interaction cycle. The player can then proceed with
561
- * the next item in a playlist if applicable, or handle the completion
562
- * according to its configuration.
563
- *
564
- * Call this method when your gadget has completed its intended function,
565
- * such as finishing an animation, completing a form, or reaching a natural
566
- * stopping point.
567
- *
568
- * ```typescript
569
- * // After completing an animation
570
- * private onAnimationComplete(): void {
571
- * this.client.finish();
572
- * }
573
- *
574
- * // After user interaction is complete
575
- * private onFormSubmitted(): void {
576
- * this.saveFormData();
577
- * this.client.finish();
578
- * }
579
- *
580
- * // After a timed display period
581
- * setTimeout(() => {
582
- * this.client.finish();
583
- * }, 30000); // 30 seconds
584
- * ```
585
- */
586
- finish() {
587
- this.getClient().then((client) => {
588
- client.finish();
589
- });
590
- }
591
- /**
592
- * Checks if the gadget is running in preview mode.
593
- *
594
- * Preview mode is enabled when the gadget is being edited in the Revel Digital CMS,
595
- * tested in the gadget editor, or otherwise not running in a normal player environment.
596
- * This is useful for providing different behavior during development/testing versus
597
- * production deployment.
598
- *
599
- * @returns Promise resolving to true if running in preview mode, false if running on actual player
600
- *
601
- * ```typescript
602
- * const isPreview = await this.client.isPreviewMode();
603
- *
604
- * if (isPreview) {
605
- * console.log('Running in preview mode - using mock data');
606
- * this.loadMockData();
607
- * } else {
608
- * console.log('Running on player device - using live data');
609
- * this.loadLiveData();
610
- * }
611
- *
612
- * // Show different UI in preview
613
- * this.showPreviewIndicator = isPreview;
614
- * ```
615
- */
616
- async isPreviewMode() {
617
- const client = await this.getClient();
618
- return client instanceof NoopClient;
619
- }
620
- /**
621
- * Gets detailed information about the device running the player.
622
- *
623
- * Returns comprehensive device details including name, registration key, type,
624
- * service date, language, timezone, tags, and location information. This data
625
- * is configured in the Revel Digital CMS for each device.
626
- *
627
- * @returns Promise resolving to device details object, or null if not available
628
- *
629
- * ```typescript
630
- * const device = await this.client.getDevice();
631
- *
632
- * if (device) {
633
- * console.log('Device name:', device.name);
634
- * console.log('Device type:', device.deviceType);
635
- * console.log('Location:', device.location.city, device.location.state);
636
- * console.log('Tags:', device.tags);
637
- *
638
- * // Use device info for customization
639
- * if (device.location.country === 'US') {
640
- * this.loadUSContent();
641
- * }
642
- *
643
- * // Check device capabilities based on type
644
- * if (device.deviceType === 'android') {
645
- * this.enableTouchFeatures();
646
- * }
647
- * }
648
- * ```
649
- */
650
- async getDevice() {
651
- const client = await this.getClient();
652
- let obj = JSON.parse(await client.getDevice());
653
- const device = [obj].map((device) => {
654
- return {
655
- name: device.name,
656
- registrationKey: device.key,
657
- deviceType: device.devicetype,
658
- enteredService: new Date(device.enteredservice),
659
- langCode: device.langcode,
660
- timeZone: device.timezone,
661
- tags: device.description?.split('\n'),
662
- location: {
663
- city: device.location?.city,
664
- state: device.location?.state,
665
- country: device.location?.country,
666
- postalCode: device.location?.postalcode,
667
- address: device.location?.address,
668
- latitude: device.location?.latitude,
669
- longitude: device.location?.longitude
670
- }
671
- };
672
- });
673
- return device[0];
674
- }
675
- /**
676
- * Gets the width of the visualization area in pixels.
677
- *
678
- * This returns the available width for content display, which may be
679
- * different from the full screen width depending on player configuration
680
- * and template layout.
681
- *
682
- * @returns Promise resolving to width in pixels, or null if not available
683
- *
684
- * ```typescript
685
- * const width = await this.client.getWidth();
686
- *
687
- * if (width) {
688
- * console.log('Available width:', width, 'pixels');
689
- *
690
- * // Adapt content layout based on width
691
- * if (width < 800) {
692
- * this.enableMobileLayout();
693
- * } else {
694
- * this.enableDesktopLayout();
695
- * }
696
- * }
697
- * ```
698
- */
699
- async getWidth() {
700
- const client = await this.getClient();
701
- return client.getWidth();
702
- }
703
- /**
704
- * Gets the height of the visualization area in pixels.
705
- *
706
- * This returns the available height for content display, which may be
707
- * different from the full screen height depending on player configuration
708
- * and template layout.
709
- *
710
- * @returns Promise resolving to height in pixels, or null if not available
711
- *
712
- * ```typescript
713
- * const height = await this.client.getHeight();
714
- *
715
- * if (height) {
716
- * console.log('Available height:', height, 'pixels');
717
- *
718
- * // Calculate aspect ratio for responsive design
719
- * const width = await this.client.getWidth();
720
- * const aspectRatio = width / height;
721
- * this.adjustContentForAspectRatio(aspectRatio);
722
- * }
723
- * ```
724
- */
725
- async getHeight() {
726
- const client = await this.getClient();
727
- return client.getHeight();
728
- }
729
- /**
730
- * Gets the duration of the currently playing content item.
731
- *
732
- * This method is only applicable when the gadget is associated with a playlist
733
- * and returns the duration assigned to the current playlist item. The duration
734
- * determines how long the content should be displayed before moving to the next item.
735
- *
736
- * @returns Promise resolving to duration in milliseconds, or null if not applicable/available
737
- *
738
- * ```typescript
739
- * const duration = await this.client.getDuration();
740
- *
741
- * if (duration) {
742
- * console.log('Content duration:', duration, 'milliseconds');
743
- *
744
- * // Set up auto-finish timer
745
- * setTimeout(() => {
746
- * this.client.finish();
747
- * }, duration);
748
- *
749
- * // Show progress indicator
750
- * this.startProgressIndicator(duration);
751
- * }
752
- * ```
753
- */
754
- async getDuration() {
755
- const client = await this.getClient();
756
- return client.getDuration();
757
- }
758
- /**
759
- * Gets the current version of the Revel Digital SDK.
760
- *
761
- * @returns Promise resolving to the SDK version string
762
- *
763
- * ```typescript
764
- * const version = await this.client.getSdkVersion();
765
- * console.log('SDK Version:', version);
766
- *
767
- * // Use for compatibility checks or logging
768
- * this.client.track('gadget_loaded', { sdkVersion: version });
769
- * ```
770
- */
771
- async getSdkVersion() {
772
- return Promise.resolve(version);
773
- }
774
- /**
775
- * Applies configuration preferences to the gadget (preview mode only).
776
- *
777
- * This method is only available when running in preview mode (typically during
778
- * gadget development or testing in the CMS). It allows applying configuration
779
- * changes that would normally come from the gadget's preference settings.
780
- *
781
- * @param prefs - Dictionary of preference key-value pairs to apply
782
- *
783
- * ```typescript
784
- * if (await this.client.isPreviewMode()) {
785
- * // Apply test configuration in preview
786
- * await this.client.applyConfig({
787
- * 'title': 'Test Title',
788
- * 'backgroundColor': '#ff0000',
789
- * 'showBorder': true,
790
- * 'refreshInterval': 30
791
- * });
792
- * }
793
- * ```
794
- */
795
- async applyConfig(prefs) {
796
- if (await this.isPreviewMode()) {
797
- const client = await this.getClient();
798
- client.applyConfig(prefs);
799
- }
800
- else {
801
- console.log('%capplyConfig() is only available in preview mode.', 'background-color:blue; color:yellow;');
802
- }
803
- }
804
- // ---
805
- // PRIVATE METHODS.
806
- // ---
807
- /** @ignore */
808
- getClient() {
809
- if (this.clientPromise) {
810
- return (this.clientPromise);
811
- }
812
- if (window.Client) {
813
- return (this.clientPromise = Promise.resolve(window.Client));
814
- }
815
- // A "complete" status indicates that the "load" event has been fired on the
816
- // window; and, that all sub-resources such as Scripts, Images, and Frames have
817
- // been loaded.
818
- if (window.document.readyState === "complete") {
819
- // If this event has fired AND the 3rd-party script isn't available (see IF-
820
- // condition BEFORE this one), it means that the 3rd-party script either
821
- // failed on the network or was BLOCKED by an ad-blocker. As such, we have to
822
- // fall-back to using a mock API.
823
- return (this.clientPromise = Promise.resolve(new NoopClient()));
824
- }
825
- // ASSERT: If we made it this far, the document has not completed loading (but it
826
- // may be in an "interactive" state which is when I believe that the Angular app
827
- // gets bootstrapped). As such, we need bind to the LOAD event to wait for our
828
- // third-party scripts to load (or fail to load, or be blocked).
829
- this.clientPromise = new Promise((resolve) => {
830
- window.addEventListener("load", function handleWindowLoad() {
831
- // At this point, the 3rd-party library is either available or
832
- // it's not - there's no further loading to do. If it's not
833
- // present on the global scope, we're going to fall-back to using
834
- // a mock API.
835
- resolve(window.Client || new NoopClient());
836
- });
837
- });
838
- return (this.clientPromise);
839
- }
840
- }
841
- PlayerClientServicefac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: PlayerClientService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
842
- PlayerClientService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: PlayerClientService, providedIn: 'root' });
843
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: PlayerClientService, decorators: [{
844
- type: Injectable,
845
- args: [{
846
- providedIn: 'root'
847
- }]
848
- }], ctorParameters: function () { return [{ type: i0.NgZone }]; } });
849
- // ----------------------------------------------------------------------------------- //
850
- // ----------------------------------------------------------------------------------- //
851
- /**
852
- * Mock implementation of the IClient interface.
853
- *
854
- * This class provides a no-operation (NOOP) implementation of the client API
855
- * that allows consuming code to function normally even when the actual player
856
- * API is not available. This typically occurs during development, testing,
857
- * or when the player script is blocked by ad-blockers.
858
- *
859
- * All methods in this class either return null/empty values or perform no
860
- * operations, allowing gadgets to function without errors while providing
861
- * appropriate fallback behavior.
862
- *
863
- * @private
864
- */
865
- class NoopClient {
866
- constructor() {
867
- console.log('%cClient API not available, falling back to mock API', 'background-color:blue; color:yellow;');
868
- }
869
- callback(...args) {
870
- // NOOP implement, nothing to do....
871
- }
872
- getDeviceTime(date) {
873
- return Promise.resolve(new Date().toISOString());
874
- }
875
- async getDeviceTimeZoneName() {
876
- return Promise.resolve(null);
877
- }
878
- async getDeviceTimeZoneID() {
879
- return Promise.resolve(null);
880
- }
881
- async getDeviceTimeZoneOffset() {
882
- return Promise.resolve(null);
883
- }
884
- async getLanguageCode() {
885
- return Promise.resolve(null);
886
- }
887
- async getDeviceKey() {
888
- return Promise.resolve(null);
889
- }
890
- sendCommand(name, arg) {
891
- // NOOP implement, nothing to do....
892
- }
893
- sendRemoteCommand(deviceKeys, name, arg) {
894
- // NOOP implement, nothing to do....
895
- }
896
- track(eventName, properties) {
897
- // NOOP implement, nothing to do....
898
- }
899
- timeEvent(eventName) {
900
- // NOOP implement, nothing to do....
901
- }
902
- newEventSession(id) {
903
- // NOOP implement, nothing to do....
904
- }
905
- async getRevelRoot() {
906
- return Promise.resolve(null);
907
- }
908
- async getCommandMap() {
909
- return Promise.resolve('{}');
910
- }
911
- finish() {
912
- // NOOP implement, nothing to do....
913
- }
914
- async getDevice() {
915
- return Promise.resolve(null);
916
- }
917
- async getWidth() {
918
- return Promise.resolve(null);
919
- }
920
- async getHeight() {
921
- return Promise.resolve(null);
922
- }
923
- async getDuration() {
924
- return Promise.resolve(null);
925
- }
926
- async getSdkVersion() {
927
- return Promise.resolve(version);
928
- }
929
- applyConfig(prefs) {
930
- let evt = { type: 'applyConfig', prefs: prefs, isOpener: window.opener !== null };
931
- if (window.opener) {
932
- window.opener.postMessage(JSON.stringify(evt), '*');
933
- }
934
- else {
935
- window.parent.postMessage(JSON.stringify(evt), '*');
936
- }
937
- }
17
+ /**
18
+ * Service for interacting with the Revel Digital player client.
19
+ *
20
+ * This service provides a comprehensive interface for gadgets and web applications
21
+ * to communicate with the Revel Digital player environment. It handles device
22
+ * information, commands, events, analytics tracking, and configuration management.
23
+ *
24
+ * The service supports both direct API calls and event-based communication patterns,
25
+ * allowing gadgets to respond to player lifecycle events (start, stop, commands) and
26
+ * send data back to the player or remote devices.
27
+ *
28
+ * ```typescript
29
+ * constructor(private client: PlayerClientService) {
30
+ * // Subscribe to player events
31
+ * this.client.onStart$.subscribe(() => {
32
+ * console.log('Gadget started');
33
+ * });
34
+ *
35
+ * this.client.onCommand$.subscribe(command => {
36
+ * console.log('Received command:', command);
37
+ * });
38
+ * }
39
+ *
40
+ * async ngOnInit() {
41
+ * // Get device information
42
+ * const device = await this.client.getDevice();
43
+ * const deviceTime = await this.client.getDeviceTime();
44
+ *
45
+ * // Track analytics
46
+ * this.client.track('gadget_loaded', { version: '1.0' });
47
+ * }
48
+ * ```
49
+ *
50
+ * @since 1.0.0
51
+ */
52
+ class PlayerClientService {
53
+ /** @ignore */
54
+ constructor(zone) {
55
+ /**
56
+ * Observable stream of commands sent to this player from the Revel Digital platform.
57
+ * Subscribe to this to handle custom commands sent from templates, playlists, or remote devices.
58
+ *
59
+ * ```typescript
60
+ * this.client.onCommand$.subscribe(command => {
61
+ * if (command.name === 'customAction') {
62
+ * this.handleCustomAction(command.arg);
63
+ * }
64
+ * });
65
+ * ```
66
+ */
67
+ this.onCommand$ = new Subject();
68
+ /**
69
+ * Observable that signals when the gadget has been loaded and is ready to start.
70
+ * Emits `true` when ready, `false` when destroyed.
71
+ *
72
+ * ```typescript
73
+ * this.client.onReady$.subscribe(isReady => {
74
+ * if (isReady) {
75
+ * console.log('Client is ready');
76
+ * this.initializeGadget();
77
+ * }
78
+ * });
79
+ * ```
80
+ */
81
+ this.onReady$ = new BehaviorSubject(false);
82
+ /**
83
+ * Observable that signals when the gadget has been started by the player.
84
+ * This event occurs when the player begins execution of the gadget content.
85
+ *
86
+ * ```typescript
87
+ * this.client.onStart$.subscribe(() => {
88
+ * console.log('Gadget started');
89
+ * this.startAnimation();
90
+ * });
91
+ * ```
92
+ */
93
+ this.onStart$ = new Subject();
94
+ /**
95
+ * Observable that signals when the gadget has been stopped by the player.
96
+ * This event occurs when the player stops execution, typically when moving
97
+ * to the next item in a playlist or when the content duration expires.
98
+ *
99
+ * ```typescript
100
+ * this.client.onStop$.subscribe(() => {
101
+ * console.log('Gadget stopped');
102
+ * this.cleanup();
103
+ * });
104
+ * ```
105
+ */
106
+ this.onStop$ = new Subject();
107
+ /**
108
+ * Observable that signals when the gadget should open the configuration window.
109
+ * This allows gadgets to respond to configuration requests from the player.
110
+ *
111
+ * ```typescript
112
+ * this.client.onConfig$.subscribe(() => {
113
+ * this.openConfigurationDialog();
114
+ * });
115
+ * ```
116
+ */
117
+ this.onConfig$ = new Subject();
118
+ /**
119
+ * Observable that signals when the gadget has received a postMessage event from the player.
120
+ * This handles communication between the gadget and player via the postMessage API.
121
+ *
122
+ * ```typescript
123
+ * this.client.onPostMessage$.subscribe(message => {
124
+ * console.log('Received message:', message);
125
+ * this.handlePlayerMessage(message);
126
+ * });
127
+ * ```
128
+ */
129
+ this.onPostMessage$ = new Subject();
130
+ /** @ignore */
131
+ this.onStartEvt$ = fromEvent(window, 'RevelDigital.Start').pipe(share(), tap(this.onStart$));
132
+ /** @ignore */
133
+ this.onStopEvt$ = fromEvent(window, 'RevelDigital.Stop').pipe(share(), tap(this.onStop$));
134
+ /** @ignore */
135
+ this.onCommandEvt$ = fromEvent(window, 'RevelDigital.Command').pipe(map((e) => { return { name: e.detail.name, arg: e.detail.arg }; }), share(), tap(this.onCommand$));
136
+ this.onPostMessageEvt$ = fromEvent(window, 'message').pipe(filter((messageEvent) =>
137
+ //messageEvent.source !== window.parent &&
138
+ typeof messageEvent.data === 'string'), map((e) => JSON.parse(e.data)), share(), tap((e) => {
139
+ if (e.type === 'applyConfig' && e.isOpener) {
140
+ e.isOpener = false;
141
+ // propagate config to iframe parent from the popup window
142
+ window.parent.postMessage(JSON.stringify(e), '*');
143
+ }
144
+ else if (e.type === 'openConfig') {
145
+ this.onConfig$.next(null);
146
+ }
147
+ }), tap(e => this.onPostMessage$.next(e)));
148
+ let self = this;
149
+ window.RevelDigital = {
150
+ Controller: {
151
+ onCommand: function (name, arg) {
152
+ zone.run(() => {
153
+ self.onCommand$.next({ name: name, arg: arg });
154
+ });
155
+ },
156
+ onStart: function () {
157
+ zone.run(() => {
158
+ self.onStart$.next(null);
159
+ });
160
+ },
161
+ onStop: function () {
162
+ zone.run(() => {
163
+ self.onStop$.next(null);
164
+ });
165
+ }
166
+ }
167
+ };
168
+ this.onStartSub = this.onStartEvt$.subscribe(() => { });
169
+ this.onStopSub = this.onStopEvt$.subscribe(() => { });
170
+ this.onCommandSub = this.onCommandEvt$.subscribe(() => { });
171
+ //this.onConfigSub = this.onConfigEvt$.subscribe(() => { });
172
+ this.onPostMessageSub = this.onPostMessageEvt$.subscribe(() => { });
173
+ this.clientPromise = null;
174
+ this.onReady$.next(true);
175
+ }
176
+ /** @ignore */
177
+ ngOnDestroy() {
178
+ this.onStartSub?.unsubscribe();
179
+ this.onStopSub?.unsubscribe();
180
+ this.onCommandSub?.unsubscribe();
181
+ //this.onConfigSub?.unsubscribe();
182
+ this.onPostMessageSub?.unsubscribe();
183
+ this.onReady$.next(false);
184
+ }
185
+ /** @ignore */
186
+ static init(data) {
187
+ console.log('%c⚙️ Initializing Revel Digital client library', 'background-color:blue; color:yellow;');
188
+ }
189
+ /**
190
+ * Sends a callback to player scripting with variable arguments.
191
+ *
192
+ * This method allows the gadget to communicate with player scripting.
193
+ * If the appropriate scripting is in place in the currently running template,
194
+ * calling this method will initiate a callback which can be acted upon in player script.
195
+ *
196
+ * @param args - Variable number of arguments to pass to the callback (max 5 arguments)
197
+ *
198
+ * ```typescript
199
+ * // Send a simple callback
200
+ * this.client.callback('test', 'data');
201
+ *
202
+ * // Send multiple parameters
203
+ * this.client.callback('action', 'value1', 'value2', { data: 'object' });
204
+ * ```
205
+ */
206
+ callback(...args) {
207
+ this.getClient().then((client) => {
208
+ switch (args.length) {
209
+ case 0:
210
+ client.callback();
211
+ break;
212
+ case 1:
213
+ client.callback(args[0]);
214
+ break;
215
+ case 2:
216
+ client.callback(args[1]);
217
+ break;
218
+ case 3:
219
+ client.callback(args[2]);
220
+ break;
221
+ case 4:
222
+ client.callback(args[3]);
223
+ break;
224
+ case 5:
225
+ client.callback(args[4]);
226
+ break;
227
+ }
228
+ });
229
+ }
230
+ /**
231
+ * Gets the user preferences interface exposed by the Google Gadgets API.
232
+ *
233
+ * This method provides access to gadget preferences which can be configured
234
+ * in the Revel Digital CMS. Use this to retrieve user-configurable settings
235
+ * for your gadget.
236
+ *
237
+ * @returns The Gadgets API Prefs object for accessing preference values
238
+ *
239
+ * ```typescript
240
+ * constructor(public client: PlayerClientService) {
241
+ * const prefs = client.getPrefs();
242
+ * const myString = prefs.getString('myStringPref');
243
+ * const myNumber = prefs.getInt('myNumberPref');
244
+ * const myBool = prefs.getBool('myBoolPref');
245
+ * }
246
+ * ```
247
+ *
248
+ * @see {@link https://developers.google.com/gadgets/docs/basic} Google Gadgets API documentation
249
+ */
250
+ getPrefs() {
251
+ return new window['gadgets']['Prefs']();
252
+ }
253
+ /**
254
+ * Gets the current device time in ISO8601 format.
255
+ *
256
+ * Current device time is determined by the device timezone assigned to the device in the CMS.
257
+ * This is useful for displaying time-sensitive content or scheduling operations based on
258
+ * the device's local time rather than browser time.
259
+ *
260
+ * @param date - Optional. If supplied, will translate the supplied date/time to device time based on respective timezones
261
+ * @returns Promise resolving to date/time in ISO8601 format
262
+ *
263
+ * ```typescript
264
+ * // Get current device time
265
+ * const currentTime = await this.client.getDeviceTime();
266
+ * console.log('Device time:', currentTime);
267
+ *
268
+ * // Convert a specific date to device time
269
+ * const specificDate = new Date('2023-01-01T12:00:00Z');
270
+ * const deviceTime = await this.client.getDeviceTime(specificDate);
271
+ * ```
272
+ */
273
+ async getDeviceTime(date) {
274
+ const client = await this.getClient();
275
+ if (date !== undefined) {
276
+ return client.getDeviceTime(date);
277
+ }
278
+ return client.getDeviceTime();
279
+ }
280
+ /**
281
+ * Gets the timezone name currently assigned to the device.
282
+ *
283
+ * @returns Promise resolving to the timezone name (e.g., "America/New_York")
284
+ *
285
+ * ```typescript
286
+ * const timezoneName = await this.client.getDeviceTimeZoneName();
287
+ * console.log('Device timezone:', timezoneName);
288
+ * ```
289
+ */
290
+ async getDeviceTimeZoneName() {
291
+ const client = await this.getClient();
292
+ return client.getDeviceTimeZoneName();
293
+ }
294
+ /**
295
+ * Gets the timezone ID currently assigned to the device.
296
+ *
297
+ * @returns Promise resolving to the timezone ID
298
+ *
299
+ * ```typescript
300
+ * const timezoneId = await this.client.getDeviceTimeZoneID();
301
+ * console.log('Device timezone ID:', timezoneId);
302
+ * ```
303
+ */
304
+ async getDeviceTimeZoneID() {
305
+ const client = await this.getClient();
306
+ return client.getDeviceTimeZoneID();
307
+ }
308
+ /**
309
+ * Gets the numerical offset from GMT of the timezone currently assigned to the device.
310
+ *
311
+ * @returns Promise resolving to the timezone offset in hours (e.g., -5 for EST)
312
+ *
313
+ * ```typescript
314
+ * const offset = await this.client.getDeviceTimeZoneOffset();
315
+ * console.log('Device timezone offset:', offset, 'hours from GMT');
316
+ * ```
317
+ */
318
+ async getDeviceTimeZoneOffset() {
319
+ const client = await this.getClient();
320
+ return client.getDeviceTimeZoneOffset();
321
+ }
322
+ /**
323
+ * Gets the language code of the language currently assigned to the device.
324
+ *
325
+ * @returns Promise resolving to the language code (e.g., "en-US", "fr-FR")
326
+ *
327
+ * ```typescript
328
+ * const languageCode = await this.client.getLanguageCode();
329
+ * console.log('Device language:', languageCode);
330
+ * // Use for localization
331
+ * this.loadLanguageResources(languageCode);
332
+ * ```
333
+ */
334
+ async getLanguageCode() {
335
+ const client = await this.getClient();
336
+ return client.getLanguageCode();
337
+ }
338
+ /**
339
+ * Gets the unique Revel Digital device key associated with the device.
340
+ *
341
+ * The device key is a unique identifier for this specific player device
342
+ * and can be used for device-specific operations or remote commands.
343
+ *
344
+ * @returns Promise resolving to the device key string
345
+ *
346
+ * ```typescript
347
+ * const deviceKey = await this.client.getDeviceKey();
348
+ * console.log('Device key:', deviceKey);
349
+ * ```
350
+ */
351
+ async getDeviceKey() {
352
+ const client = await this.getClient();
353
+ return client.getDeviceKey();
354
+ }
355
+ /**
356
+ * Sends a command to the local player device.
357
+ *
358
+ * Commands can be used to control various aspects of the player or trigger
359
+ * specific behaviors. The command is processed by the local player only.
360
+ *
361
+ * @param name - The command name/identifier
362
+ * @param arg - The command argument/payload
363
+ *
364
+ * ```typescript
365
+ * // Send a simple command
366
+ * this.client.sendCommand('refresh', '');
367
+ *
368
+ * // Send a command with data
369
+ * this.client.sendCommand('setVolume', '50');
370
+ *
371
+ * // Send a command with JSON data
372
+ * this.client.sendCommand('configure', JSON.stringify({ setting: 'value' }));
373
+ * ```
374
+ */
375
+ sendCommand(name, arg) {
376
+ this.getClient().then((client) => {
377
+ client.sendCommand(name, arg);
378
+ });
379
+ }
380
+ /**
381
+ * Sends a command to remote player devices with the specified device keys.
382
+ *
383
+ * Remote commands allow cross-device communication within the same Revel Digital account.
384
+ * This is useful for synchronized displays, device coordination, or remote control scenarios.
385
+ *
386
+ * Note: Remote commands can only be delivered to devices within the same account as the sender device.
387
+ *
388
+ * @param deviceKeys - Array of target device keys to send the command to
389
+ * @param name - The command name/identifier
390
+ * @param arg - The command argument/payload
391
+ *
392
+ * ```typescript
393
+ * // Send command to specific devices
394
+ * const targetDevices = ['device-key-1', 'device-key-2'];
395
+ * this.client.sendRemoteCommand(targetDevices, 'syncAction', 'start');
396
+ *
397
+ * // Broadcast to multiple devices
398
+ * this.client.sendRemoteCommand(
399
+ * ['lobby-display', 'kiosk-1', 'kiosk-2'],
400
+ * 'updateContent',
401
+ * JSON.stringify({ contentId: '12345' })
402
+ * );
403
+ * ```
404
+ */
405
+ sendRemoteCommand(deviceKeys, name, arg) {
406
+ this.getClient().then((client) => {
407
+ client.sendRemoteCommand(deviceKeys, name, arg);
408
+ });
409
+ }
410
+ /**
411
+ * Logs an analytics event for use with AdHawk analytics and reporting.
412
+ *
413
+ * Events are used for tracking various metrics including usage statistics,
414
+ * player condition, state changes, user interactions, and custom business metrics.
415
+ * These events can be viewed in the Revel Digital analytics dashboard.
416
+ *
417
+ * @param eventName - Unique name for this event (should be descriptive and consistent)
418
+ * @param properties - Optional map of user-defined properties to associate with this event
419
+ *
420
+ * ```typescript
421
+ * // Simple event tracking
422
+ * this.client.track('gadget_loaded');
423
+ *
424
+ * // Event with properties
425
+ * this.client.track('user_interaction', {
426
+ * action: 'button_click',
427
+ * button_id: 'start_button',
428
+ * timestamp: new Date().toISOString()
429
+ * });
430
+ *
431
+ * // Performance tracking
432
+ * this.client.track('content_displayed', {
433
+ * content_type: 'video',
434
+ * duration: 30,
435
+ * quality: 'HD'
436
+ * });
437
+ * ```
438
+ */
439
+ track(eventName, properties) {
440
+ this.getClient().then((client) => {
441
+ client.track(eventName, JSON.stringify(properties));
442
+ });
443
+ }
444
+ /**
445
+ * Initiates a timed event for duration tracking.
446
+ *
447
+ * Timed events are useful for tracking the duration of operations or user interactions.
448
+ * This method must be followed by a call to track() with the same event name to complete
449
+ * the timing measurement. The duration will be automatically calculated and included
450
+ * in the event properties.
451
+ *
452
+ * @param eventName - Unique name for this timed event (must match the subsequent track() call)
453
+ *
454
+ * ```typescript
455
+ * // Start timing an event
456
+ * this.client.timeEvent('video_playback');
457
+ *
458
+ * // ... video plays for some duration ...
459
+ *
460
+ * // End timing and log the event with duration
461
+ * this.client.track('video_playback', {
462
+ * video_id: 'abc123',
463
+ * quality: 'HD'
464
+ * }); // Duration will be automatically added
465
+ *
466
+ * // Example for user interaction timing
467
+ * this.client.timeEvent('form_completion');
468
+ * // ... user fills out form ...
469
+ * this.client.track('form_completion', { form_type: 'contact' });
470
+ * ```
471
+ */
472
+ timeEvent(eventName) {
473
+ this.getClient().then((client) => {
474
+ client.timeEvent(eventName);
475
+ });
476
+ }
477
+ /**
478
+ * Creates a new analytics event session for grouping related events.
479
+ *
480
+ * A session is a way of grouping events together for analysis. Each event tracked
481
+ * after calling this method will have the same session ID until a new session is created.
482
+ * Session IDs are randomly generated unless explicitly provided.
483
+ *
484
+ * This is useful for tracking user journeys, workflow completion, or grouping
485
+ * related interactions within a specific time period.
486
+ *
487
+ * @param id - Optional user-supplied session ID. If not provided, a random session ID will be generated
488
+ *
489
+ * ```typescript
490
+ * // Start a new session with auto-generated ID
491
+ * this.client.newEventSession();
492
+ * this.client.track('session_start');
493
+ * this.client.track('user_action_1');
494
+ * this.client.track('user_action_2');
495
+ *
496
+ * // Start a session with custom ID
497
+ * this.client.newEventSession('user-workflow-12345');
498
+ * this.client.track('workflow_start');
499
+ * this.client.track('step_completed', { step: 1 });
500
+ *
501
+ * // Start a new session for different workflow
502
+ * this.client.newEventSession();
503
+ * this.client.track('different_workflow_start');
504
+ * ```
505
+ */
506
+ newEventSession(id) {
507
+ this.getClient().then((client) => {
508
+ if (id !== undefined) {
509
+ client.newEventSession();
510
+ }
511
+ else {
512
+ client.newEventSession(id);
513
+ }
514
+ });
515
+ }
516
+ /**
517
+ * Gets the root folder path utilized by this player device.
518
+ *
519
+ * This returns the base directory path where the Revel Digital player
520
+ * stores its files and resources on the local device.
521
+ *
522
+ * @returns Promise resolving to the path of the root folder
523
+ *
524
+ * ```typescript
525
+ * const rootPath = await this.client.getRevelRoot();
526
+ * console.log('Player root directory:', rootPath);
527
+ * // Use for constructing file paths or understanding storage structure
528
+ * ```
529
+ */
530
+ async getRevelRoot() {
531
+ const client = await this.getClient();
532
+ return client.getRevelRoot();
533
+ }
534
+ /**
535
+ * Gets a map of commands currently active for this device.
536
+ *
537
+ * This returns the current command configuration that defines how the device
538
+ * responds to various command triggers and remote commands.
539
+ *
540
+ * @returns Promise resolving to a map of currently active commands
541
+ *
542
+ * ```typescript
543
+ * const commandMap = await this.client.getCommandMap();
544
+ * console.log('Active commands:', commandMap);
545
+ *
546
+ * // Check if specific command is available
547
+ * if (commandMap['customCommand']) {
548
+ * console.log('Custom command is available');
549
+ * }
550
+ * ```
551
+ */
552
+ async getCommandMap() {
553
+ const client = await this.getClient();
554
+ return JSON.parse(await client.getCommandMap());
555
+ }
556
+ /**
557
+ * Signals to the player that this gadget has completed its visualization.
558
+ *
559
+ * This method notifies the player that the current gadget has finished its
560
+ * content display or interaction cycle. The player can then proceed with
561
+ * the next item in a playlist if applicable, or handle the completion
562
+ * according to its configuration.
563
+ *
564
+ * Call this method when your gadget has completed its intended function,
565
+ * such as finishing an animation, completing a form, or reaching a natural
566
+ * stopping point.
567
+ *
568
+ * ```typescript
569
+ * // After completing an animation
570
+ * private onAnimationComplete(): void {
571
+ * this.client.finish();
572
+ * }
573
+ *
574
+ * // After user interaction is complete
575
+ * private onFormSubmitted(): void {
576
+ * this.saveFormData();
577
+ * this.client.finish();
578
+ * }
579
+ *
580
+ * // After a timed display period
581
+ * setTimeout(() => {
582
+ * this.client.finish();
583
+ * }, 30000); // 30 seconds
584
+ * ```
585
+ */
586
+ finish() {
587
+ this.getClient().then((client) => {
588
+ client.finish();
589
+ });
590
+ }
591
+ /**
592
+ * Checks if the gadget is running in preview mode.
593
+ *
594
+ * Preview mode is enabled when the gadget is being edited in the Revel Digital CMS,
595
+ * tested in the gadget editor, or otherwise not running in a normal player environment.
596
+ * This is useful for providing different behavior during development/testing versus
597
+ * production deployment.
598
+ *
599
+ * @returns Promise resolving to true if running in preview mode, false if running on actual player
600
+ *
601
+ * ```typescript
602
+ * const isPreview = await this.client.isPreviewMode();
603
+ *
604
+ * if (isPreview) {
605
+ * console.log('Running in preview mode - using mock data');
606
+ * this.loadMockData();
607
+ * } else {
608
+ * console.log('Running on player device - using live data');
609
+ * this.loadLiveData();
610
+ * }
611
+ *
612
+ * // Show different UI in preview
613
+ * this.showPreviewIndicator = isPreview;
614
+ * ```
615
+ */
616
+ async isPreviewMode() {
617
+ const client = await this.getClient();
618
+ return client instanceof NoopClient;
619
+ }
620
+ /**
621
+ * Gets detailed information about the device running the player.
622
+ *
623
+ * Returns comprehensive device details including name, registration key, type,
624
+ * service date, language, timezone, tags, and location information. This data
625
+ * is configured in the Revel Digital CMS for each device.
626
+ *
627
+ * @returns Promise resolving to device details object, or null if not available
628
+ *
629
+ * ```typescript
630
+ * const device = await this.client.getDevice();
631
+ *
632
+ * if (device) {
633
+ * console.log('Device name:', device.name);
634
+ * console.log('Device type:', device.deviceType);
635
+ * console.log('Location:', device.location.city, device.location.state);
636
+ * console.log('Tags:', device.tags);
637
+ *
638
+ * // Use device info for customization
639
+ * if (device.location.country === 'US') {
640
+ * this.loadUSContent();
641
+ * }
642
+ *
643
+ * // Check device capabilities based on type
644
+ * if (device.deviceType === 'android') {
645
+ * this.enableTouchFeatures();
646
+ * }
647
+ * }
648
+ * ```
649
+ */
650
+ async getDevice() {
651
+ const client = await this.getClient();
652
+ let obj = JSON.parse(await client.getDevice());
653
+ const device = [obj].map((device) => {
654
+ return {
655
+ name: device.name,
656
+ registrationKey: device.key,
657
+ deviceType: device.devicetype,
658
+ enteredService: new Date(device.enteredservice),
659
+ langCode: device.langcode,
660
+ timeZone: device.timezone,
661
+ tags: device.description?.split('\n'),
662
+ location: {
663
+ city: device.location?.city,
664
+ state: device.location?.state,
665
+ country: device.location?.country,
666
+ postalCode: device.location?.postalcode,
667
+ address: device.location?.address,
668
+ latitude: device.location?.latitude,
669
+ longitude: device.location?.longitude
670
+ }
671
+ };
672
+ });
673
+ return device[0];
674
+ }
675
+ /**
676
+ * Gets the width of the visualization area in pixels.
677
+ *
678
+ * This returns the available width for content display, which may be
679
+ * different from the full screen width depending on player configuration
680
+ * and template layout.
681
+ *
682
+ * @returns Promise resolving to width in pixels, or null if not available
683
+ *
684
+ * ```typescript
685
+ * const width = await this.client.getWidth();
686
+ *
687
+ * if (width) {
688
+ * console.log('Available width:', width, 'pixels');
689
+ *
690
+ * // Adapt content layout based on width
691
+ * if (width < 800) {
692
+ * this.enableMobileLayout();
693
+ * } else {
694
+ * this.enableDesktopLayout();
695
+ * }
696
+ * }
697
+ * ```
698
+ */
699
+ async getWidth() {
700
+ const client = await this.getClient();
701
+ return client.getWidth();
702
+ }
703
+ /**
704
+ * Gets the height of the visualization area in pixels.
705
+ *
706
+ * This returns the available height for content display, which may be
707
+ * different from the full screen height depending on player configuration
708
+ * and template layout.
709
+ *
710
+ * @returns Promise resolving to height in pixels, or null if not available
711
+ *
712
+ * ```typescript
713
+ * const height = await this.client.getHeight();
714
+ *
715
+ * if (height) {
716
+ * console.log('Available height:', height, 'pixels');
717
+ *
718
+ * // Calculate aspect ratio for responsive design
719
+ * const width = await this.client.getWidth();
720
+ * const aspectRatio = width / height;
721
+ * this.adjustContentForAspectRatio(aspectRatio);
722
+ * }
723
+ * ```
724
+ */
725
+ async getHeight() {
726
+ const client = await this.getClient();
727
+ return client.getHeight();
728
+ }
729
+ /**
730
+ * Gets the duration of the currently playing content item.
731
+ *
732
+ * This method is only applicable when the gadget is associated with a playlist
733
+ * and returns the duration assigned to the current playlist item. The duration
734
+ * determines how long the content should be displayed before moving to the next item.
735
+ *
736
+ * @returns Promise resolving to duration in milliseconds, or null if not applicable/available
737
+ *
738
+ * ```typescript
739
+ * const duration = await this.client.getDuration();
740
+ *
741
+ * if (duration) {
742
+ * console.log('Content duration:', duration, 'milliseconds');
743
+ *
744
+ * // Set up auto-finish timer
745
+ * setTimeout(() => {
746
+ * this.client.finish();
747
+ * }, duration);
748
+ *
749
+ * // Show progress indicator
750
+ * this.startProgressIndicator(duration);
751
+ * }
752
+ * ```
753
+ */
754
+ async getDuration() {
755
+ const client = await this.getClient();
756
+ return client.getDuration();
757
+ }
758
+ /**
759
+ * Gets the current version of the Revel Digital SDK.
760
+ *
761
+ * @returns Promise resolving to the SDK version string
762
+ *
763
+ * ```typescript
764
+ * const version = await this.client.getSdkVersion();
765
+ * console.log('SDK Version:', version);
766
+ *
767
+ * // Use for compatibility checks or logging
768
+ * this.client.track('gadget_loaded', { sdkVersion: version });
769
+ * ```
770
+ */
771
+ async getSdkVersion() {
772
+ return Promise.resolve(version);
773
+ }
774
+ /**
775
+ * Applies configuration preferences to the gadget (preview mode only).
776
+ *
777
+ * This method is only available when running in preview mode (typically during
778
+ * gadget development or testing in the CMS). It allows applying configuration
779
+ * changes that would normally come from the gadget's preference settings.
780
+ *
781
+ * @param prefs - Dictionary of preference key-value pairs to apply
782
+ *
783
+ * ```typescript
784
+ * if (await this.client.isPreviewMode()) {
785
+ * // Apply test configuration in preview
786
+ * await this.client.applyConfig({
787
+ * 'title': 'Test Title',
788
+ * 'backgroundColor': '#ff0000',
789
+ * 'showBorder': true,
790
+ * 'refreshInterval': 30
791
+ * });
792
+ * }
793
+ * ```
794
+ */
795
+ async applyConfig(prefs) {
796
+ if (await this.isPreviewMode()) {
797
+ const client = await this.getClient();
798
+ client.applyConfig(prefs);
799
+ }
800
+ else {
801
+ console.log('%capplyConfig() is only available in preview mode.', 'background-color:blue; color:yellow;');
802
+ }
803
+ }
804
+ // ---
805
+ // PRIVATE METHODS.
806
+ // ---
807
+ /** @ignore */
808
+ getClient() {
809
+ if (this.clientPromise) {
810
+ return (this.clientPromise);
811
+ }
812
+ if (window.Client) {
813
+ return (this.clientPromise = Promise.resolve(window.Client));
814
+ }
815
+ // A "complete" status indicates that the "load" event has been fired on the
816
+ // window; and, that all sub-resources such as Scripts, Images, and Frames have
817
+ // been loaded.
818
+ if (window.document.readyState === "complete") {
819
+ // If this event has fired AND the 3rd-party script isn't available (see IF-
820
+ // condition BEFORE this one), it means that the 3rd-party script either
821
+ // failed on the network or was BLOCKED by an ad-blocker. As such, we have to
822
+ // fall-back to using a mock API.
823
+ return (this.clientPromise = Promise.resolve(new NoopClient()));
824
+ }
825
+ // ASSERT: If we made it this far, the document has not completed loading (but it
826
+ // may be in an "interactive" state which is when I believe that the Angular app
827
+ // gets bootstrapped). As such, we need bind to the LOAD event to wait for our
828
+ // third-party scripts to load (or fail to load, or be blocked).
829
+ this.clientPromise = new Promise((resolve) => {
830
+ window.addEventListener("load", function handleWindowLoad() {
831
+ // At this point, the 3rd-party library is either available or
832
+ // it's not - there's no further loading to do. If it's not
833
+ // present on the global scope, we're going to fall-back to using
834
+ // a mock API.
835
+ resolve(window.Client || new NoopClient());
836
+ });
837
+ });
838
+ return (this.clientPromise);
839
+ }
840
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PlayerClientService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); }
841
+ static { thisprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PlayerClientService, providedIn: 'root' }); }
842
+ }
843
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PlayerClientService, decorators: [{
844
+ type: Injectable,
845
+ args: [{
846
+ providedIn: 'root'
847
+ }]
848
+ }], ctorParameters: () => [{ type: i0.NgZone }] });
849
+ // ----------------------------------------------------------------------------------- //
850
+ // ----------------------------------------------------------------------------------- //
851
+ /**
852
+ * Mock implementation of the IClient interface.
853
+ *
854
+ * This class provides a no-operation (NOOP) implementation of the client API
855
+ * that allows consuming code to function normally even when the actual player
856
+ * API is not available. This typically occurs during development, testing,
857
+ * or when the player script is blocked by ad-blockers.
858
+ *
859
+ * All methods in this class either return null/empty values or perform no
860
+ * operations, allowing gadgets to function without errors while providing
861
+ * appropriate fallback behavior.
862
+ *
863
+ * @private
864
+ */
865
+ class NoopClient {
866
+ constructor() {
867
+ console.log('%cClient API not available, falling back to mock API', 'background-color:blue; color:yellow;');
868
+ }
869
+ callback(...args) {
870
+ // NOOP implement, nothing to do....
871
+ }
872
+ getDeviceTime(date) {
873
+ return Promise.resolve(new Date().toISOString());
874
+ }
875
+ async getDeviceTimeZoneName() {
876
+ return Promise.resolve(null);
877
+ }
878
+ async getDeviceTimeZoneID() {
879
+ return Promise.resolve(null);
880
+ }
881
+ async getDeviceTimeZoneOffset() {
882
+ return Promise.resolve(null);
883
+ }
884
+ async getLanguageCode() {
885
+ return Promise.resolve(null);
886
+ }
887
+ async getDeviceKey() {
888
+ return Promise.resolve(null);
889
+ }
890
+ sendCommand(name, arg) {
891
+ // NOOP implement, nothing to do....
892
+ }
893
+ sendRemoteCommand(deviceKeys, name, arg) {
894
+ // NOOP implement, nothing to do....
895
+ }
896
+ track(eventName, properties) {
897
+ // NOOP implement, nothing to do....
898
+ }
899
+ timeEvent(eventName) {
900
+ // NOOP implement, nothing to do....
901
+ }
902
+ newEventSession(id) {
903
+ // NOOP implement, nothing to do....
904
+ }
905
+ async getRevelRoot() {
906
+ return Promise.resolve(null);
907
+ }
908
+ async getCommandMap() {
909
+ return Promise.resolve('{}');
910
+ }
911
+ finish() {
912
+ // NOOP implement, nothing to do....
913
+ }
914
+ async getDevice() {
915
+ return Promise.resolve(null);
916
+ }
917
+ async getWidth() {
918
+ return Promise.resolve(null);
919
+ }
920
+ async getHeight() {
921
+ return Promise.resolve(null);
922
+ }
923
+ async getDuration() {
924
+ return Promise.resolve(null);
925
+ }
926
+ async getSdkVersion() {
927
+ return Promise.resolve(version);
928
+ }
929
+ applyConfig(prefs) {
930
+ let evt = { type: 'applyConfig', prefs: prefs, isOpener: window.opener !== null };
931
+ if (window.opener) {
932
+ window.opener.postMessage(JSON.stringify(evt), '*');
933
+ }
934
+ else {
935
+ window.parent.postMessage(JSON.stringify(evt), '*');
936
+ }
937
+ }
938
938
  }
939
939
 
940
- const isLocal = /localhost/.test(document.location.host);
941
- !isLocal && enableProdMode();
942
- /** @ignore */
943
- class AppInitService {
944
- constructor(http, _route, _router) {
945
- this.http = http;
946
- this._route = _route;
947
- this._router = _router;
948
- }
949
- init() {
950
- return new Promise(async (resolve) => {
951
- this.loadFonts();
952
- if (isDevMode()) {
953
- console.log('%cRunning in development mode', 'background-color:blue; color:yellow;');
954
- /**
955
- * Shim the shindig prefs functionality for dev mode
956
- */
957
- window.gadgets = {
958
- Prefs: class {
959
- getString(key) { return this.getParameterByName(key); }
960
- getArray(key) { return this.getParameterByName(key).split(','); }
961
- getBool(key) { return this.getParameterByName(key) === 'true'; }
962
- getCountry() { }
963
- getFloat(key) { return parseFloat(this.getParameterByName(key)); }
964
- getInt(key) { return parseInt(this.getParameterByName(key)); }
965
- getLang() { return this.getParameterByName('lang') === '' ? 'en' : this.getParameterByName('lang'); }
966
- getParameterByName(name, search = window.location.href) {
967
- name = name.replace(/[\[\]]/g, '\\$&');
968
- let regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'), results = regex.exec(search);
969
- if (!results)
970
- return '';
971
- if (!results[2])
972
- return '';
973
- return decodeURIComponent(results[2].replace(/\+/g, ' '));
974
- }
975
- }
976
- };
977
- this.http.get('assets/gadget.yaml', {
978
- responseType: 'text'
979
- }).subscribe(data => {
980
- const doc = yaml.load(data);
981
- let params = {};
982
- for (const val of doc.prefs) {
983
- params[val.name] = val.default_value;
984
- }
985
- this._router.navigate([], {
986
- relativeTo: this._route,
987
- queryParams: params,
988
- });
989
- console.log(`%cUser prefs loaded successfully`, 'background-color:blue; color:yellow;');
990
- }, (err) => {
991
- console.log(`%cUnable to load user preferences YAML definition file: ${err}`, 'background-color:blue; color:yellow;');
992
- console.log(`%cPlease see our developer documentation for help with your app configuration: https://developer.reveldigital.com`, 'background-color:red; color:yellow;');
993
- });
994
- }
995
- resolve();
996
- });
997
- }
998
- getFamilyName(css) {
999
- let FONT_FAMILY_REGEX = /font-family:\s*(?:[&#39;&#34;])*['"]*(.+?)['"]*(?:[&#39;&#34;])*\s*;/i;
1000
- if (FONT_FAMILY_REGEX.test(css)) {
1001
- var matches = css.match(FONT_FAMILY_REGEX);
1002
- return matches[1].split(',')[0];
1003
- }
1004
- else {
1005
- return '';
1006
- }
1007
- }
1008
- /**
1009
- * Loads the given font from Google Web Fonts.
1010
- */
1011
- loadFonts() {
1012
- const parameters = new URLSearchParams(window.location.search);
1013
- parameters.forEach((val, key) => {
1014
- try {
1015
- let fontFamily = this.getFamilyName(val);
1016
- if (fontFamily !== '') {
1017
- WebFont.load({
1018
- google: {
1019
- families: [fontFamily]
1020
- },
1021
- fontactive: (familyName) => {
1022
- console.log(`%cActivating font: ${familyName}`, 'background-color:blue; color:yellow;');
1023
- },
1024
- fontinactive: (familyName) => {
1025
- console.log(`%cFont inactive: ${familyName}`, 'background-color:red; color:yellow;');
1026
- }
1027
- });
1028
- }
1029
- }
1030
- catch (e) {
1031
- }
1032
- });
1033
- }
1034
- }
1035
- AppInitService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: AppInitService, deps: [{ token: i1.HttpClient }, { token: i2.ActivatedRoute }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable });
1036
- AppInitService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: AppInitService, providedIn: 'root' });
1037
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: AppInitService, decorators: [{
1038
- type: Injectable,
1039
- args: [{
1040
- providedIn: 'root'
1041
- }]
1042
- }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: i2.ActivatedRoute }, { type: i2.Router }]; } });
1043
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwLWluaXQuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3JldmVsZGlnaXRhbC9wbGF5ZXItY2xpZW50L3NyYy9saWIvYXBwLWluaXQuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLGNBQWMsRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFHdEUsT0FBTyxLQUFLLElBQUksTUFBTSxTQUFTLENBQUM7QUFDaEMsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7Ozs7QUFFekMsTUFBTSxPQUFPLEdBQVksV0FBVyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ2xFLENBQUMsT0FBTyxJQUFJLGNBQWMsRUFBRSxDQUFDO0FBRzdCLGNBQWM7QUFJZCxNQUFNLE9BQU8sY0FBYztJQUV6QixZQUNTLElBQWdCLEVBQ2YsTUFBc0IsRUFDdEIsT0FBZTtRQUZoQixTQUFJLEdBQUosSUFBSSxDQUFZO1FBQ2YsV0FBTSxHQUFOLE1BQU0sQ0FBZ0I7UUFDdEIsWUFBTyxHQUFQLE9BQU8sQ0FBUTtJQUN6QixDQUFDO0lBRUQsSUFBSTtRQUVGLE9BQU8sSUFBSSxPQUFPLENBQU8sS0FBSyxFQUFFLE9BQU8sRUFBRSxFQUFFO1lBRXpDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUVqQixJQUFJLFNBQVMsRUFBRSxFQUFFO2dCQUNmLE9BQU8sQ0FBQyxHQUFHLENBQ1QsK0JBQStCLEVBQy9CLHNDQUFzQyxDQUN2QyxDQUFDO2dCQUVGOzttQkFFRztnQkFDRyxNQUFPLENBQUMsT0FBTyxHQUFHO29CQUV0QixLQUFLLEVBQUU7d0JBQ0wsU0FBUyxDQUFDLEdBQVcsSUFBSSxPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsQ0FBQSxDQUFDLENBQUM7d0JBRTlELFFBQVEsQ0FBQyxHQUFXLElBQUksT0FBTyxJQUFJLENBQUMsa0JBQWtCLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFBLENBQUMsQ0FBQzt3QkFFeEUsT0FBTyxDQUFDLEdBQVcsSUFBSSxPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsS0FBSyxNQUFNLENBQUEsQ0FBQyxDQUFDO3dCQUV2RSxVQUFVLEtBQUssQ0FBQzt3QkFFaEIsUUFBUSxDQUFDLEdBQVcsSUFBSSxPQUFPLFVBQVUsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQSxDQUFDLENBQUM7d0JBRXpFLE1BQU0sQ0FBQyxHQUFXLElBQUksT0FBTyxRQUFRLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUEsQ0FBQyxDQUFDO3dCQUVyRSxPQUFPLEtBQUssT0FBTyxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7d0JBRXJHLGtCQUFrQixDQUFDLElBQVksRUFBRSxNQUFNLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJOzRCQUU1RCxJQUFJLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUM7NEJBQ3ZDLElBQUksS0FBSyxHQUFHLElBQUksTUFBTSxDQUFDLE1BQU0sR0FBRyxJQUFJLEdBQUcsbUJBQW1CLENBQUMsRUFDekQsT0FBTyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7NEJBQy9CLElBQUksQ0FBQyxPQUFPO2dDQUFFLE9BQU8sRUFBRSxDQUFDOzRCQUN4QixJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztnQ0FBRSxPQUFPLEVBQUUsQ0FBQzs0QkFDM0IsT0FBTyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO3dCQUM1RCxDQUFDO3FCQUNGO2lCQUNGLENBQUM7Z0JBRUYsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsb0JBQW9CLEVBQUU7b0JBQ2xDLFlBQVksRUFBRSxNQUFNO2lCQUNyQixDQUFDLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFO29CQUNsQixNQUFNLEdBQUcsR0FBUSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO29CQUNqQyxJQUFJLE1BQU0sR0FBUSxFQUFFLENBQUE7b0JBQ3BCLEtBQUssTUFBTSxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssRUFBRTt3QkFDM0IsTUFBTSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsYUFBYSxDQUFBO3FCQUNyQztvQkFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUU7d0JBQ3hCLFVBQVUsRUFBRSxJQUFJLENBQUMsTUFBTTt3QkFDdkIsV0FBVyxFQUFFLE1BQU07cUJBQ3BCLENBQUMsQ0FBQztvQkFFSCxPQUFPLENBQUMsR0FBRyxDQUNULGtDQUFrQyxFQUNsQyxzQ0FBc0MsQ0FDdkMsQ0FBQztnQkFDSixDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRTtvQkFDVCxPQUFPLENBQUMsR0FBRyxDQUNULDJEQUEyRCxHQUFHLEVBQUUsRUFDaEUsc0NBQXNDLENBQ3ZDLENBQUM7b0JBQ0YsT0FBTyxDQUFDLEdBQUcsQ0FDVCxtSEFBbUgsRUFDbkgscUNBQXFDLENBQ3RDLENBQUE7Z0JBQ0gsQ0FBQyxDQUFDLENBQUE7YUFDSDtZQUNELE9BQU8sRUFBRSxDQUFDO1FBQ1osQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBR08sYUFBYSxDQUFDLEdBQUc7UUFFdkIsSUFBSSxpQkFBaUIsR0FBRyx1RUFBdUUsQ0FBQztRQUNoRyxJQUFJLGlCQUFpQixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRTtZQUMvQixJQUFJLE9BQU8sR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLGlCQUFpQixDQUFDLENBQUM7WUFDM0MsT0FBTyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ2pDO2FBQU07WUFDTCxPQUFPLEVBQUUsQ0FBQztTQUNYO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0ssU0FBUztRQUVmLE1BQU0sVUFBVSxHQUFHLElBQUksZUFBZSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDL0QsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsRUFBRTtZQUM5QixJQUFJO2dCQUNGLElBQUksVUFBVSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQ3pDLElBQUksVUFBVSxLQUFLLEVBQUUsRUFBRTtvQkFDckIsT0FBTyxDQUFDLElBQUksQ0FBQzt3QkFDWCxNQUFNLEVBQUU7NEJBQ04sUUFBUSxFQUFFLENBQUMsVUFBVSxDQUFDO3lCQUN2Qjt3QkFDRCxVQUFVLEVBQUUsQ0FBQyxVQUFVLEVBQUUsRUFBRTs0QkFDekIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxzQkFBc0IsVUFBVSxFQUFFLEVBQzVDLHNDQUFzQyxDQUFDLENBQUM7d0JBQzVDLENBQUM7d0JBQ0QsWUFBWSxFQUFFLENBQUMsVUFBVSxFQUFFLEVBQUU7NEJBQzNCLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0JBQW9CLFVBQVUsRUFBRSxFQUMxQyxxQ0FBcUMsQ0FBQyxDQUFDO3dCQUMzQyxDQUFDO3FCQUNGLENBQUMsQ0FBQztpQkFDSjthQUNGO1lBQUMsT0FBTyxDQUFDLEVBQUU7YUFDWDtRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQzs7NEdBNUhVLGNBQWM7Z0hBQWQsY0FBYyxjQUZiLE1BQU07NEZBRVAsY0FBYztrQkFIMUIsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBlbmFibGVQcm9kTW9kZSwgaXNEZXZNb2RlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IEh0dHBDbGllbnQgfSBmcm9tIFwiQGFuZ3VsYXIvY29tbW9uL2h0dHBcIjtcclxuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUsIFJvdXRlciB9IGZyb20gXCJAYW5ndWxhci9yb3V0ZXJcIjtcclxuaW1wb3J0ICogYXMgeWFtbCBmcm9tIFwianMteWFtbFwiO1xyXG5pbXBvcnQgKiBhcyBXZWJGb250IGZyb20gJ3dlYmZvbnRsb2FkZXInO1xyXG5cclxuY29uc3QgaXNMb2NhbDogYm9vbGVhbiA9IC9sb2NhbGhvc3QvLnRlc3QoZG9jdW1lbnQubG9jYXRpb24uaG9zdCk7XHJcbiFpc0xvY2FsICYmIGVuYWJsZVByb2RNb2RlKCk7XHJcblxyXG5cclxuLyoqIEBpZ25vcmUgKi9cclxuQEluamVjdGFibGUoe1xyXG4gIHByb3ZpZGVkSW46ICdyb290J1xyXG59KVxyXG5leHBvcnQgY2xhc3MgQXBwSW5pdFNlcnZpY2Uge1xyXG5cclxuICBjb25zdHJ1Y3RvcihcclxuICAgIHB1YmxpYyBodHRwOiBIdHRwQ2xpZW50LFxyXG4gICAgcHJpdmF0ZSBfcm91dGU6IEFjdGl2YXRlZFJvdXRlLFxyXG4gICAgcHJpdmF0ZSBfcm91dGVyOiBSb3V0ZXIpIHtcclxuICB9XHJcblxyXG4gIGluaXQoKTogUHJvbWlzZTxhbnk+IHtcclxuXHJcbiAgICByZXR1cm4gbmV3IFByb21pc2U8dm9pZD4oYXN5bmMgKHJlc29sdmUpID0+IHtcclxuXHJcbiAgICAgIHRoaXMubG9hZEZvbnRzKCk7XHJcblxyXG4gICAgICBpZiAoaXNEZXZNb2RlKCkpIHtcclxuICAgICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAgICclY1J1bm5pbmcgaW4gZGV2ZWxvcG1lbnQgbW9kZScsXHJcbiAgICAgICAgICAnYmFja2dyb3VuZC1jb2xvcjpibHVlOyBjb2xvcjp5ZWxsb3c7J1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8qKlxyXG4gICAgICAgICAqIFNoaW0gdGhlIHNoaW5kaWcgcHJlZnMgZnVuY3Rpb25hbGl0eSBmb3IgZGV2IG1vZGVcclxuICAgICAgICAgKi9cclxuICAgICAgICAoPGFueT53aW5kb3cpLmdhZGdldHMgPSB7XHJcblxyXG4gICAgICAgICAgUHJlZnM6IGNsYXNzIHtcclxuICAgICAgICAgICAgZ2V0U3RyaW5nKGtleTogc3RyaW5nKSB7IHJldHVybiB0aGlzLmdldFBhcmFtZXRlckJ5TmFtZShrZXkpIH1cclxuXHJcbiAgICAgICAgICAgIGdldEFycmF5KGtleTogc3RyaW5nKSB7IHJldHVybiB0aGlzLmdldFBhcmFtZXRlckJ5TmFtZShrZXkpLnNwbGl0KCcsJykgfVxyXG5cclxuICAgICAgICAgICAgZ2V0Qm9vbChrZXk6IHN0cmluZykgeyByZXR1cm4gdGhpcy5nZXRQYXJhbWV0ZXJCeU5hbWUoa2V5KSA9PT0gJ3RydWUnIH1cclxuXHJcbiAgICAgICAgICAgIGdldENvdW50cnkoKSB7IH1cclxuXHJcbiAgICAgICAgICAgIGdldEZsb2F0KGtleTogc3RyaW5nKSB7IHJldHVybiBwYXJzZUZsb2F0KHRoaXMuZ2V0UGFyYW1ldGVyQnlOYW1lKGtleSkpIH1cclxuXHJcbiAgICAgICAgICAgIGdldEludChrZXk6IHN0cmluZykgeyByZXR1cm4gcGFyc2VJbnQodGhpcy5nZXRQYXJhbWV0ZXJCeU5hbWUoa2V5KSkgfVxyXG5cclxuICAgICAgICAgICAgZ2V0TGFuZygpIHsgcmV0dXJuIHRoaXMuZ2V0UGFyYW1ldGVyQnlOYW1lKCdsYW5nJykgPT09ICcnID8gJ2VuJyA6IHRoaXMuZ2V0UGFyYW1ldGVyQnlOYW1lKCdsYW5nJyk7IH1cclxuXHJcbiAgICAgICAgICAgIGdldFBhcmFtZXRlckJ5TmFtZShuYW1lOiBzdHJpbmcsIHNlYXJjaCA9IHdpbmRvdy5sb2NhdGlvbi5ocmVmKTogc3RyaW5nIHtcclxuXHJcbiAgICAgICAgICAgICAgbmFtZSA9IG5hbWUucmVwbGFjZSgvW1xcW1xcXV0vZywgJ1xcXFwkJicpO1xyXG4gICAgICAgICAgICAgIGxldCByZWdleCA9IG5ldyBSZWdFeHAoJ1s/Jl0nICsgbmFtZSArICcoPShbXiYjXSopfCZ8I3wkKScpLFxyXG4gICAgICAgICAgICAgICAgcmVzdWx0cyA9IHJlZ2V4LmV4ZWMoc2VhcmNoKTtcclxuICAgICAgICAgICAgICBpZiAoIXJlc3VsdHMpIHJldHVybiAnJztcclxuICAgICAgICAgICAgICBpZiAoIXJlc3VsdHNbMl0pIHJldHVybiAnJztcclxuICAgICAgICAgICAgICByZXR1cm4gZGVjb2RlVVJJQ29tcG9uZW50KHJlc3VsdHNbMl0ucmVwbGFjZSgvXFwrL2csICcgJykpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy5odHRwLmdldCgnYXNzZXRzL2dhZGdldC55YW1sJywge1xyXG4gICAgICAgICAgcmVzcG9uc2VUeXBlOiAndGV4dCdcclxuICAgICAgICB9KS5zdWJzY3JpYmUoZGF0YSA9PiB7XHJcbiAgICAgICAgICBjb25zdCBkb2M6IGFueSA9IHlhbWwubG9hZChkYXRhKTtcclxuICAgICAgICAgIGxldCBwYXJhbXM6IGFueSA9IHt9XHJcbiAgICAgICAgICBmb3IgKGNvbnN0IHZhbCBvZiBkb2MucHJlZnMpIHtcclxuICAgICAgICAgICAgcGFyYW1zW3ZhbC5uYW1lXSA9IHZhbC5kZWZhdWx0X3ZhbHVlXHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgdGhpcy5fcm91dGVyLm5hdmlnYXRlKFtdLCB7XHJcbiAgICAgICAgICAgIHJlbGF0aXZlVG86IHRoaXMuX3JvdXRlLFxyXG4gICAgICAgICAgICBxdWVyeVBhcmFtczogcGFyYW1zLFxyXG4gICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgICAgIGAlY1VzZXIgcHJlZnMgbG9hZGVkIHN1Y2Nlc3NmdWxseWAsXHJcbiAgICAgICAgICAgICdiYWNrZ3JvdW5kLWNvbG9yOmJsdWU7IGNvbG9yOnllbGxvdzsnXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0sIChlcnIpID0+IHtcclxuICAgICAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICAgICBgJWNVbmFibGUgdG8gbG9hZCB1c2VyIHByZWZlcmVuY2VzIFlBTUwgZGVmaW5pdGlvbiBmaWxlOiAke2Vycn1gLFxyXG4gICAgICAgICAgICAnYmFja2dyb3VuZC1jb2xvcjpibHVlOyBjb2xvcjp5ZWxsb3c7J1xyXG4gICAgICAgICAgKTtcclxuICAgICAgICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICAgICAgICBgJWNQbGVhc2Ugc2VlIG91ciBkZXZlbG9wZXIgZG9jdW1lbnRhdGlvbiBmb3IgaGVscCB3aXRoIHlvdXIgYXBwIGNvbmZpZ3VyYXRpb246IGh0dHBzOi8vZGV2ZWxvcGVyLnJldmVsZGlnaXRhbC5jb21gLFxyXG4gICAgICAgICAgICAnYmFja2dyb3VuZC1jb2xvcjpyZWQ7IGNvbG9yOnllbGxvdzsnXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgfSlcclxuICAgICAgfVxyXG4gICAgICByZXNvbHZlKCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG5cclxuICBwcml2YXRlIGdldEZhbWlseU5hbWUoY3NzKSB7XHJcblxyXG4gICAgbGV0IEZPTlRfRkFNSUxZX1JFR0VYID0gL2ZvbnQtZmFtaWx5OlxccyooPzpbJiMzOTsmIzM0O10pKlsnXCJdKiguKz8pWydcIl0qKD86WyYjMzk7JiMzNDtdKSpcXHMqOy9pO1xyXG4gICAgaWYgKEZPTlRfRkFNSUxZX1JFR0VYLnRlc3QoY3NzKSkge1xyXG4gICAgICB2YXIgbWF0Y2hlcyA9IGNzcy5tYXRjaChGT05UX0ZBTUlMWV9SRUdFWCk7XHJcbiAgICAgIHJldHVybiBtYXRjaGVzWzFdLnNwbGl0KCcsJylbMF07XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gJyc7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBMb2FkcyB0aGUgZ2l2ZW4gZm9udCBmcm9tIEdvb2dsZSBXZWIgRm9udHMuXHJcbiAgICovXHJcbiAgcHJpdmF0ZSBsb2FkRm9udHMoKTogdm9pZCB7XHJcblxyXG4gICAgY29uc3QgcGFyYW1ldGVycyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMod2luZG93LmxvY2F0aW9uLnNlYXJjaCk7XHJcbiAgICBwYXJhbWV0ZXJzLmZvckVhY2goKHZhbCwga2V5KSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbGV0IGZvbnRGYW1pbHkgPSB0aGlzLmdldEZhbWlseU5hbWUodmFsKTtcclxuICAgICAgICBpZiAoZm9udEZhbWlseSAhPT0gJycpIHtcclxuICAgICAgICAgIFdlYkZvbnQubG9hZCh7XHJcbiAgICAgICAgICAgIGdvb2dsZToge1xyXG4gICAgICAgICAgICAgIGZhbWlsaWVzOiBbZm9udEZhbWlseV1cclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgZm9udGFjdGl2ZTogKGZhbWlseU5hbWUpID0+IHtcclxuICAgICAgICAgICAgICBjb25zb2xlLmxvZyhgJWNBY3RpdmF0aW5nIGZvbnQ6ICR7ZmFtaWx5TmFtZX1gLFxyXG4gICAgICAgICAgICAgICAgJ2JhY2tncm91bmQtY29sb3I6Ymx1ZTsgY29sb3I6eWVsbG93OycpO1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBmb250aW5hY3RpdmU6IChmYW1pbHlOYW1lKSA9PiB7XHJcbiAgICAgICAgICAgICAgY29uc29sZS5sb2coYCVjRm9udCBpbmFjdGl2ZTogJHtmYW1pbHlOYW1lfWAsXHJcbiAgICAgICAgICAgICAgICAnYmFja2dyb3VuZC1jb2xvcjpyZWQ7IGNvbG9yOnllbGxvdzsnKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGNhdGNoIChlKSB7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH1cclxufVxyXG4iXX0=
940
+ const isLocal = /localhost/.test(document.location.host);
941
+ !isLocal && enableProdMode();
942
+ /** @ignore */
943
+ class AppInitService {
944
+ constructor(http, _route, _router) {
945
+ this.http = http;
946
+ this._route = _route;
947
+ this._router = _router;
948
+ }
949
+ init() {
950
+ return new Promise(async (resolve) => {
951
+ this.loadFonts();
952
+ if (isDevMode()) {
953
+ console.log('%cRunning in development mode', 'background-color:blue; color:yellow;');
954
+ /**
955
+ * Shim the shindig prefs functionality for dev mode
956
+ */
957
+ window.gadgets = {
958
+ Prefs: class {
959
+ getString(key) { return this.getParameterByName(key); }
960
+ getArray(key) { return this.getParameterByName(key).split(','); }
961
+ getBool(key) { return this.getParameterByName(key) === 'true'; }
962
+ getCountry() { }
963
+ getFloat(key) { return parseFloat(this.getParameterByName(key)); }
964
+ getInt(key) { return parseInt(this.getParameterByName(key)); }
965
+ getLang() { return this.getParameterByName('lang') === '' ? 'en' : this.getParameterByName('lang'); }
966
+ getParameterByName(name, search = window.location.href) {
967
+ name = name.replace(/[\[\]]/g, '\\$&');
968
+ let regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'), results = regex.exec(search);
969
+ if (!results)
970
+ return '';
971
+ if (!results[2])
972
+ return '';
973
+ return decodeURIComponent(results[2].replace(/\+/g, ' '));
974
+ }
975
+ }
976
+ };
977
+ this.http.get('assets/gadget.yaml', {
978
+ responseType: 'text'
979
+ }).subscribe({
980
+ next: (data) => {
981
+ const doc = yaml.load(data);
982
+ let params = {};
983
+ for (const val of doc.prefs) {
984
+ params[val.name] = val.default_value;
985
+ }
986
+ this._router.navigate([], {
987
+ relativeTo: this._route,
988
+ queryParams: params,
989
+ });
990
+ console.log(`%cUser prefs loaded successfully`, 'background-color:blue; color:yellow;');
991
+ },
992
+ error: (err) => {
993
+ console.log(`%cUnable to load user preferences YAML definition file: ${err}`, 'background-color:blue; color:yellow;');
994
+ console.log(`%cPlease see our developer documentation for help with your app configuration: https://developer.reveldigital.com`, 'background-color:red; color:yellow;');
995
+ }
996
+ });
997
+ }
998
+ resolve();
999
+ });
1000
+ }
1001
+ getFamilyName(css) {
1002
+ let FONT_FAMILY_REGEX = /font-family:\s*(?:[&#39;&#34;])*['"]*(.+?)['"]*(?:[&#39;&#34;])*\s*;/i;
1003
+ if (FONT_FAMILY_REGEX.test(css)) {
1004
+ var matches = css.match(FONT_FAMILY_REGEX);
1005
+ return matches[1].split(',')[0];
1006
+ }
1007
+ else {
1008
+ return '';
1009
+ }
1010
+ }
1011
+ /**
1012
+ * Loads the given font from Google Web Fonts.
1013
+ */
1014
+ loadFonts() {
1015
+ const parameters = new URLSearchParams(window.location.search);
1016
+ parameters.forEach((val, key) => {
1017
+ try {
1018
+ let fontFamily = this.getFamilyName(val);
1019
+ if (fontFamily !== '') {
1020
+ WebFont.load({
1021
+ google: {
1022
+ families: [fontFamily]
1023
+ },
1024
+ fontactive: (familyName) => {
1025
+ console.log(`%cActivating font: ${familyName}`, 'background-color:blue; color:yellow;');
1026
+ },
1027
+ fontinactive: (familyName) => {
1028
+ console.log(`%cFont inactive: ${familyName}`, 'background-color:red; color:yellow;');
1029
+ }
1030
+ });
1031
+ }
1032
+ }
1033
+ catch (e) {
1034
+ }
1035
+ });
1036
+ }
1037
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AppInitService, deps: [{ token: i1.HttpClient }, { token: i2.ActivatedRoute }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
1038
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AppInitService, providedIn: 'root' }); }
1039
+ }
1040
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AppInitService, decorators: [{
1041
+ type: Injectable,
1042
+ args: [{
1043
+ providedIn: 'root'
1044
+ }]
1045
+ }], ctorParameters: () => [{ type: i1.HttpClient }, { type: i2.ActivatedRoute }, { type: i2.Router }] });
1044
1046
 
1045
- /**
1046
- * The safe style pipe is used when custom styles are defined for a gadget and must be applied to an Angular
1047
- * component. This pipe will ensure the style can be appied safely by utilizing the DomSanitizer.
1048
- *
1049
- * ```html
1050
- * <h2 [style]="style | safeStyle">Sample Pref: {{ prefs.getString('myStringPref') }}</h2>
1051
- * ```
1052
- */
1053
- class SafeStylePipe {
1054
- constructor(sanitized) {
1055
- this.sanitized = sanitized;
1056
- }
1057
- transform(value) {
1058
- return this.sanitized.bypassSecurityTrustStyle(value);
1059
- }
1060
- }
1061
- SafeStylePipefac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: SafeStylePipe, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe });
1062
- SafeStylePipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: SafeStylePipe, name: "safeStyle" });
1063
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: SafeStylePipe, decorators: [{
1064
- type: Pipe,
1065
- args: [{
1066
- name: 'safeStyle',
1067
- }]
1068
- }], ctorParameters: function () { return [{ type: i1$1.DomSanitizer }]; } });
1069
- class NgSafeStylePipeModule {
1070
- }
1071
- NgSafeStylePipeModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: NgSafeStylePipeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1072
- NgSafeStylePipeModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: NgSafeStylePipeModule, declarations: [SafeStylePipe], exports: [SafeStylePipe] });
1073
- NgSafeStylePipeModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: NgSafeStylePipeModule });
1074
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: NgSafeStylePipeModule, decorators: [{
1075
- type: NgModule,
1076
- args: [{
1077
- declarations: [SafeStylePipe],
1078
- exports: [SafeStylePipe],
1079
- }]
1047
+ /**
1048
+ * The safe style pipe is used when custom styles are defined for a gadget and must be applied to an Angular
1049
+ * component. This pipe will ensure the style can be appied safely by utilizing the DomSanitizer.
1050
+ *
1051
+ * ```html
1052
+ * <h2 [style]="style | safeStyle">Sample Pref: {{ prefs.getString('myStringPref') }}</h2>
1053
+ * ```
1054
+ */
1055
+ class SafeStylePipe {
1056
+ constructor(sanitized) {
1057
+ this.sanitized = sanitized;
1058
+ }
1059
+ transform(value) {
1060
+ return this.sanitized.bypassSecurityTrustStyle(value);
1061
+ }
1062
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SafeStylePipe, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
1063
+ static { thispipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: SafeStylePipe, isStandalone: true, name: "safeStyle" }); }
1064
+ }
1065
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: SafeStylePipe, decorators: [{
1066
+ type: Pipe,
1067
+ args: [{
1068
+ name: 'safeStyle',
1069
+ standalone: true,
1070
+ }]
1071
+ }], ctorParameters: () => [{ type: i1$1.DomSanitizer }] });
1072
+ class NgSafeStylePipeModule {
1073
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgSafeStylePipeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1074
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: NgSafeStylePipeModule, imports: [SafeStylePipe], exports: [SafeStylePipe] }); }
1075
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgSafeStylePipeModule }); }
1076
+ }
1077
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NgSafeStylePipeModule, decorators: [{
1078
+ type: NgModule,
1079
+ args: [{
1080
+ imports: [SafeStylePipe],
1081
+ exports: [SafeStylePipe],
1082
+ }]
1080
1083
  }] });
1081
1084
 
1082
- class PlayerClientModule {
1083
- }
1084
- PlayerClientModulefac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: PlayerClientModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1085
- PlayerClientModulemod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: PlayerClientModule, imports: [HttpClientModule, i2.RouterModule, NgSafeStylePipeModule], exports: [NgSafeStylePipeModule] });
1086
- PlayerClientModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: PlayerClientModule, providers: [{
1087
- provide: APP_INITIALIZER,
1088
- useFactory: initializeApp,
1089
- deps: [AppInitService, PlayerClientService],
1090
- multi: true
1091
- },
1092
- {
1093
- provide: LOCALE_ID,
1094
- useFactory: () => {
1095
- try {
1096
- return new gadgets.Prefs().getLang();
1097
- }
1098
- catch {
1099
- return 'en';
1100
- }
1101
- }
1102
- },
1103
- { provide: APP_BASE_HREF, useValue: '/gadgets/ifr' }], imports: [[
1104
- HttpClientModule,
1105
- RouterModule.forRoot([]),
1106
- NgSafeStylePipeModule
1107
- ], NgSafeStylePipeModule] });
1108
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.12", ngImport: i0, type: PlayerClientModule, decorators: [{
1109
- type: NgModule,
1110
- args: [{
1111
- imports: [
1112
- HttpClientModule,
1113
- RouterModule.forRoot([]),
1114
- NgSafeStylePipeModule
1115
- ],
1116
- exports: [
1117
- NgSafeStylePipeModule
1118
- ],
1119
- providers: [{
1120
- provide: APP_INITIALIZER,
1121
- useFactory: initializeApp,
1122
- deps: [AppInitService, PlayerClientService],
1123
- multi: true
1124
- },
1125
- {
1126
- provide: LOCALE_ID,
1127
- useFactory: () => {
1128
- try {
1129
- return new gadgets.Prefs().getLang();
1130
- }
1131
- catch {
1132
- return 'en';
1133
- }
1134
- }
1135
- },
1136
- { provide: APP_BASE_HREF, useValue: '/gadgets/ifr' }]
1137
- }]
1138
- }] });
1139
- function initializeApp(appInitService) {
1140
- return async () => {
1141
- PlayerClientService.init({});
1142
- await appInitService.init();
1143
- };
1144
- }
1145
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGxheWVyLWNsaWVudC5tb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9yZXZlbGRpZ2l0YWwvcGxheWVyLWNsaWVudC9zcmMvbGliL3BsYXllci1jbGllbnQubW9kdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxlQUFlLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNyRSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM5RCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDcEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDeEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQzs7O0FBZ0MxRCxNQUFNLE9BQU8sa0JBQWtCOztnSEFBbEIsa0JBQWtCO2lIQUFsQixrQkFBa0IsWUF6QjNCLGdCQUFnQixtQkFFaEIscUJBQXFCLGFBR3JCLHFCQUFxQjtpSEFvQlosa0JBQWtCLGFBbEJsQixDQUFDO1lBQ1YsT0FBTyxFQUFFLGVBQWU7WUFDeEIsVUFBVSxFQUFFLGFBQWE7WUFDekIsSUFBSSxFQUFFLENBQUMsY0FBYyxFQUFFLG1CQUFtQixDQUFDO1lBQzNDLEtBQUssRUFBRSxJQUFJO1NBQ1o7UUFDRDtZQUNFLE9BQU8sRUFBRSxTQUFTO1lBQ2xCLFVBQVUsRUFBRSxHQUFHLEVBQUU7Z0JBQ2YsSUFBSTtvQkFDRixPQUFPLElBQUksT0FBTyxDQUFDLEtBQUssRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDO2lCQUN0QztnQkFBQyxNQUFNO29CQUNOLE9BQU8sSUFBSSxDQUFDO2lCQUNiO1lBQ0gsQ0FBQztTQUNGO1FBQ0QsRUFBRSxPQUFPLEVBQUUsYUFBYSxFQUFFLFFBQVEsRUFBRSxjQUFjLEVBQUUsQ0FBQyxZQXhCNUM7WUFDUCxnQkFBZ0I7WUFDaEIsWUFBWSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDeEIscUJBQXFCO1NBQ3RCLEVBRUMscUJBQXFCOzRGQW9CWixrQkFBa0I7a0JBM0I5QixRQUFRO21CQUFDO29CQUNSLE9BQU8sRUFBRTt3QkFDUCxnQkFBZ0I7d0JBQ2hCLFlBQVksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO3dCQUN4QixxQkFBcUI7cUJBQ3RCO29CQUNELE9BQU8sRUFBRTt3QkFDUCxxQkFBcUI7cUJBQ3RCO29CQUNELFNBQVMsRUFBRSxDQUFDOzRCQUNWLE9BQU8sRUFBRSxlQUFlOzRCQUN4QixVQUFVLEVBQUUsYUFBYTs0QkFDekIsSUFBSSxFQUFFLENBQUMsY0FBYyxFQUFFLG1CQUFtQixDQUFDOzRCQUMzQyxLQUFLLEVBQUUsSUFBSTt5QkFDWjt3QkFDRDs0QkFDRSxPQUFPLEVBQUUsU0FBUzs0QkFDbEIsVUFBVSxFQUFFLEdBQUcsRUFBRTtnQ0FDZixJQUFJO29DQUNGLE9BQU8sSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUM7aUNBQ3RDO2dDQUFDLE1BQU07b0NBQ04sT0FBTyxJQUFJLENBQUM7aUNBQ2I7NEJBQ0gsQ0FBQzt5QkFDRjt3QkFDRCxFQUFFLE9BQU8sRUFBRSxhQUFhLEVBQUUsUUFBUSxFQUFFLGNBQWMsRUFBRSxDQUFDO2lCQUN0RDs7QUFHRCxTQUFTLGFBQWEsQ0FBQyxjQUE4QjtJQUNuRCxPQUFPLEtBQUssSUFBSSxFQUFFO1FBQ2hCLG1CQUFtQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUM3QixNQUFNLGNBQWMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUM5QixDQUFDLENBQUE7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQVBQX0lOSVRJQUxJWkVSLCBMT0NBTEVfSUQsIE5nTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBQbGF5ZXJDbGllbnRTZXJ2aWNlIH0gZnJvbSAnLi9wbGF5ZXItY2xpZW50LnNlcnZpY2UnO1xuaW1wb3J0IHsgQXBwSW5pdFNlcnZpY2UgfSBmcm9tICcuL2FwcC1pbml0LnNlcnZpY2UnO1xuaW1wb3J0IHsgSHR0cENsaWVudE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IFJvdXRlck1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBBUFBfQkFTRV9IUkVGIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IE5nU2FmZVN0eWxlUGlwZU1vZHVsZSB9IGZyb20gJy4vc2FmZS1zdHlsZS5waXBlJztcblxuZGVjbGFyZSB2YXIgZ2FkZ2V0czogYW55O1xuXG5cbkBOZ01vZHVsZSh7XG4gIGltcG9ydHM6IFtcbiAgICBIdHRwQ2xpZW50TW9kdWxlLFxuICAgIFJvdXRlck1vZHVsZS5mb3JSb290KFtdKSxcbiAgICBOZ1NhZmVTdHlsZVBpcGVNb2R1bGVcbiAgXSxcbiAgZXhwb3J0czogW1xuICAgIE5nU2FmZVN0eWxlUGlwZU1vZHVsZVxuICBdLFxuICBwcm92aWRlcnM6IFt7XG4gICAgcHJvdmlkZTogQVBQX0lOSVRJQUxJWkVSLFxuICAgIHVzZUZhY3Rvcnk6IGluaXRpYWxpemVBcHAsXG4gICAgZGVwczogW0FwcEluaXRTZXJ2aWNlLCBQbGF5ZXJDbGllbnRTZXJ2aWNlXSxcbiAgICBtdWx0aTogdHJ1ZVxuICB9LFxuICB7XG4gICAgcHJvdmlkZTogTE9DQUxFX0lELFxuICAgIHVzZUZhY3Rvcnk6ICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBuZXcgZ2FkZ2V0cy5QcmVmcygpLmdldExhbmcoKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm4gJ2VuJztcbiAgICAgIH1cbiAgICB9XG4gIH0sXG4gIHsgcHJvdmlkZTogQVBQX0JBU0VfSFJFRiwgdXNlVmFsdWU6ICcvZ2FkZ2V0cy9pZnInIH1dXG59KVxuZXhwb3J0IGNsYXNzIFBsYXllckNsaWVudE1vZHVsZSB7IH1cblxuZnVuY3Rpb24gaW5pdGlhbGl6ZUFwcChhcHBJbml0U2VydmljZTogQXBwSW5pdFNlcnZpY2UpIHtcbiAgcmV0dXJuIGFzeW5jICgpID0+IHtcbiAgICBQbGF5ZXJDbGllbnRTZXJ2aWNlLmluaXQoe30pO1xuICAgIGF3YWl0IGFwcEluaXRTZXJ2aWNlLmluaXQoKTtcbiAgfVxufVxuIl19
1085
+ class PlayerClientModule {
1086
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PlayerClientModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1087
+ static { thismod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.14", ngImport: i0, type: PlayerClientModule, imports: [HttpClientModule, i2.RouterModule, NgSafeStylePipeModule], exports: [NgSafeStylePipeModule] }); }
1088
+ static { thisinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PlayerClientModule, providers: [{
1089
+ provide: APP_INITIALIZER,
1090
+ useFactory: initializeApp,
1091
+ deps: [AppInitService, PlayerClientService],
1092
+ multi: true
1093
+ },
1094
+ {
1095
+ provide: LOCALE_ID,
1096
+ useFactory: () => {
1097
+ try {
1098
+ return new gadgets.Prefs().getLang();
1099
+ }
1100
+ catch {
1101
+ return 'en';
1102
+ }
1103
+ }
1104
+ },
1105
+ { provide: APP_BASE_HREF, useValue: '/gadgets/ifr' }], imports: [HttpClientModule,
1106
+ RouterModule.forRoot([]),
1107
+ NgSafeStylePipeModule, NgSafeStylePipeModule] }); }
1108
+ }
1109
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PlayerClientModule, decorators: [{
1110
+ type: NgModule,
1111
+ args: [{
1112
+ imports: [
1113
+ HttpClientModule,
1114
+ RouterModule.forRoot([]),
1115
+ NgSafeStylePipeModule
1116
+ ],
1117
+ exports: [
1118
+ NgSafeStylePipeModule
1119
+ ],
1120
+ providers: [{
1121
+ provide: APP_INITIALIZER,
1122
+ useFactory: initializeApp,
1123
+ deps: [AppInitService, PlayerClientService],
1124
+ multi: true
1125
+ },
1126
+ {
1127
+ provide: LOCALE_ID,
1128
+ useFactory: () => {
1129
+ try {
1130
+ return new gadgets.Prefs().getLang();
1131
+ }
1132
+ catch {
1133
+ return 'en';
1134
+ }
1135
+ }
1136
+ },
1137
+ { provide: APP_BASE_HREF, useValue: '/gadgets/ifr' }]
1138
+ }]
1139
+ }] });
1140
+ function initializeApp(appInitService) {
1141
+ return async () => {
1142
+ PlayerClientService.init({});
1143
+ await appInitService.init();
1144
+ };
1145
+ }
1146
1146
 
1147
- /*
1148
- * Public API Surface of player-client
1149
- */
1150
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3JldmVsZGlnaXRhbC9wbGF5ZXItY2xpZW50L3NyYy9wdWJsaWMtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyw2QkFBNkIsQ0FBQztBQUM1QyxjQUFjLDRCQUE0QixDQUFDO0FBQzNDLGNBQWMsdUJBQXVCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogUHVibGljIEFQSSBTdXJmYWNlIG9mIHBsYXllci1jbGllbnRcbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2xpYi9wbGF5ZXItY2xpZW50LnNlcnZpY2UnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvcGxheWVyLWNsaWVudC5tb2R1bGUnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvc2FmZS1zdHlsZS5waXBlJzsiXX0=
1147
+ /*
1148
+ * Public API Surface of player-client
1149
+ */
1151
1150
 
1152
- /**
1153
- * Generated bundle index. Do not edit.
1154
- */
1155
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmV2ZWxkaWdpdGFsLXBsYXllci1jbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9yZXZlbGRpZ2l0YWwvcGxheWVyLWNsaWVudC9zcmMvcmV2ZWxkaWdpdGFsLXBsYXllci1jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLGNBQWMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9wdWJsaWMtYXBpJztcbiJdfQ==
1151
+ /**
1152
+ * Generated bundle index. Do not edit.
1153
+ */
1156
1154
 
1157
1155
  export { NgSafeStylePipeModule, PlayerClientModule, PlayerClientService, SafeStylePipe };
1158
1156
  //# sourceMappingURL=reveldigital-player-client.mjs.map