PageSourceSearch

https://gebarenles.nl/wp-content/plugins/audienceplayer/templates/js/audienceplayer-core.js?ver=1776312445

js gebarenles.nl collected 2026-10-01 23:59:03 UTC 66,645 bytes, 1,734 lines download raw bytes

1window.AudiencePlayerCore = {};
2
3jQuery(function ($) {
4
5    window.AudiencePlayerCore = {
6
7        /**
8         * Main config, hydrated in template "templates/audienceplayer-core-javascript.php", is kept here
9         */
10        CONFIG: {
11            isLoggedIn: false,
12            isSynchronised: false
13        },
14
15        /**
16         * Ajax-synchronised API-data is kept here
17         */
18        STORE: {
19            UserDetails: {
20                key: 'UserDetails',
21                value: null,
22                operation: 'query{UserDetails{id,nomadic_articles{id,appr},history_articles{id,appr},entitled_articles{id},user_subscriptions{id,subscription_id,is_valid}}}'
23            },
24        },
25
26        ERROR_CODE_TRANSLATIONS: {
27            3600: 'dialogue_voucher_code_invalid',
28            3601: 'dialogue_general_payment_error',
29            3602: 'dialogue_voucher_code_not_applicable',
30            3603: 'dialogue_voucher_code_applicable_subscription_unknown',
31            3604: 'dialogue_voucher_code_not_applicable',
32            3605: 'dialogue_voucher_code_usage_not_allowed',
33            3606: 'dialogue_amount_balance_usage_not_allowed',
34            3607: 'dialogue_voucher_code_claim_limit_overflow',
35            3608: 'dialogue_voucher_code_user_email_not_allowed',
36            3609: 'dialogue_voucher_code_subscription_not_allowed',
37            3610: 'dialogue_voucher_code_user_subscription_not_allowed',
38            3611: 'dialogue_voucher_code_product_not_allowed',
39            3612: 'dialogue_voucher_code_product_intersect_not_allowed',
40            3613: 'dialogue_voucher_code_product_type_not_allowed'
41        },
42
43        genericImplementationErrorCode: 2001,
44
45        $currentActiveModal: null,
46
47        /**
48         * Initialise Fetch UserDetails in order to set nomadic progress
49         */
50        init: function () {
51
52            let self = this;
53
54            // Hydrate global AudiencePlayer Library/Config
55            self.CONFIG = window.AudiencePlayerLib;
56
57            if (self.CONFIG && self.CONFIG.isLoggedIn) {
58
59                let callback = function () {
60                    self.initArticleProgressIndication();
61                    self.initEntitledArticleActions();
62                };
63
64                // Initialise article play progress indication
65                if (self.STORE.UserDetails.value = self.fetchCache(self.STORE.UserDetails.key)) {
66                    callback();
67                } else {
68                    self.refreshStoreUserDetails(callback);
69                }
70
71            } else {
72                // user not authenticated, clear cache
73                self.clearCache();
74            }
75
76            // Initialise event listeners
77            self.initEventListeners();
78
79            // Set session refresh after 1h inactivity
80            self.refreshSession(3600);
81        },
82
83        /**
84         * Initialise progress indicators on already rendered article carousels/grids
85         */
86        initArticleProgressIndication: function () {
87
88            let self = this;
89
90            if (self.CONFIG.isNomadicWatchingEnabled) {
91
92                try {
93
94                    let articles = [];
95
96                    // Parse nomadic and history Articles
97                    for (let i in this.STORE.UserDetails.value.nomadic_articles) {
98                        articles.push(this.STORE.UserDetails.value.nomadic_articles[i]);
99                    }
100                    for (let i in this.STORE.UserDetails.value.history_articles) {
101                        articles.push(this.STORE.UserDetails.value.history_articles[i]);
102                    }
103
104                    // Update progress indicators
105                    for (let i in articles) {
106                        let article = articles[i];
107                        let progressPc = article.appr ? parseInt(article.appr * 100) : 0;
108
109                        if (progressPc) {
110                            $('.article-id-' + article.id + '.progress-bar')
111                                .fadeIn();
112                            $('.article-id-' + article.id + '.progress')
113                                .animate({width: progressPc + '%'}, 1000);
114                        }
115                    }
116
117                } catch (e) {
118                    // silent
119                }
120            }
121        },
122
123        /**
124         * Initialise entitled article actions
125         */
126        initEntitledArticleActions: function () {
127
128            try {
129                for (let i in this.STORE.UserDetails.value.entitled_articles) {
130                    let article = this.STORE.UserDetails.value.entitled_articles[i];
131                    // hide product buttons for entitled items
132                    let productButton = $('.audienceplayer-purchase-product-button.article-id-' + article.id);
133                    $(productButton).hide();
134                }
135            } catch (e) {
136                // silent
137            }
138        },
139
140        /**
141         * Initialise event listeners
142         */
143        initEventListeners: function () {
144
145            let self = this;
146
147            // Setup listeners for modal close buttons
148            let $modalButtons = $('.audienceplayer-modal button.close');
149            $modalButtons.unbind();
150            $modalButtons.click(function () {
151                self.closeModal(true);
152                return false;
153            });
154
155            // Set up keyup events to close modals: Currently only map the ESC key (27)
156            $(document).unbind('keyup.key27');
157            $(document).bind('keyup.key27', function (event) {
158                // escape key
159                if (event.which === 27) {
160                    if (self.getActiveModal()) {
161                        self.closeModal(true);
162                    }
163                }
164                return false;
165            });
166        },
167
168        /**
169         * Call AudiencePlayer API
170         * @param action
171         * @param operation
172         * @param callbackSuccess
173         * @param callbackFailure
174         */
175        callApi: function (action, operation, postData, callbackSuccess, callbackFailure) {
176
177            let data = {
178                action: action,
179                operation: operation,
180            };
181
182            if (postData) {
183                for (let key in postData) {
184                    data[key] = postData[key];
185                }
186            }
187
188            $.ajax({
189                url: this.CONFIG.siteBaseUrl + '/wp-admin/admin-ajax.php',
190                type: 'post',
191                dataType: 'json',
192                data: data,
193            })
194                .done(function (response) {
195                    if (callbackSuccess) {
196                        callbackSuccess(response);
197                    }
198                })
199                .fail(function (response) {
200                    if (callbackFailure) {
201                        callbackFailure(response);
202                    }
203                });
204        },
205
206        /**
207         * Refresh the store UserDetails
208         * @param callbackSuccess
209         */
210        refreshStoreUserDetails: function (callbackSuccess) {
211
212            let self = this;
213
214            // first clear all cache before fetching UserDetails
215            self.clearCache();
216
217            if (self.isAuthenticated()) {
218
219                self.callApi(
220                    'audienceplayer_api_call',
221                    self.STORE.UserDetails.operation,
222                    null,
223                    function (response) {
224                        self.STORE.UserDetails.value = response.data.UserDetails;
225                        self.setCache(self.STORE.UserDetails.key, self.STORE.UserDetails.value);
226                        if (callbackSuccess) {
227                            callbackSuccess(response);
228                        }
229                    },
230                    function (response) {
231                        if (response.responseJSON.errors[0].code === 401) {
232                            self.clearCache();
233                        }
234                    }
235                );
236            }
237
238        },
239
240        refreshSession: function (ttl, isForceSync, onSuccessCallback, onFailureCallback) {
241
242            let self = this;
243
244            let refreshCallback = function () {
245
246                self.callApi(
247                    'audienceplayer_sync_session',
248                    null,
249                    {is_force_sync: isForceSync ? 1 : 0},
250                    function (response) {
251                        if (self.CONFIG && response.data.token) {
252                            self.CONFIG.userBearerToken = response.data.token;
253                        }
254                        if (self.CONFIG && response.data.expires_in) {
255                            self.CONFIG.userBearerTokenTtl = (response.data.expires_in - 60) * 1000;
256                        }
257                        // Trigger a new refreshSession after given ttl
258                        if (self.CONFIG.userBearerTokenTtl && ttl) {
259                            self.refreshSession(ttl);
260                        }
261
262                        if (onSuccessCallback) {
263                            onSuccessCallback();
264                        }
265                    },
266                    onFailureCallback
267                );
268            };
269
270            if (ttl > 0) {
271                setTimeout(refreshCallback, (self.CONFIG && self.CONFIG.userBearerTokenTtl) ? self.CONFIG.userBearerTokenTtl : ttl * 1000);
272            } else {
273                refreshCallback();
274            }
275        },
276
277        /**
278         * Check if the user is authenticated (based on presence of bearerToken)
279         * @returns {string|boolean}
280         */
281        isAuthenticated: function () {
282            return (this.CONFIG.userBearerToken || false) && this.CONFIG.isLoggedIn && this.CONFIG.isSynchronised;
283        },
284
285        redirectNonAuthenticatedUser: function () {
286
287            let callbackNonAuthenticated = arguments[0];
288
289            if (!this.CONFIG.isLoggedIn) {
290
291                // user in not logged in, execute redirect action
292                this.handleApiErrorCallback(event, this.parseTranslationKey('dialogue_user_not_authenticated'), 401, callbackNonAuthenticated);
293
294            } else if (!this.CONFIG.isSynchronised) {
295
296                // user is logged in, but not correctly synchronised!
297                this.handleApiErrorCallback(event, this.parseTranslationKey('dialogue_user_not_synchronised'), 407);
298
299            } else {
300
301                // try to forcefully refresh the session
302                this.refreshSession(0, true);
303            }
304        },
305
306        /**
307         * Open the AudiencePlayer EmbedPlayer in a modal window
308         * @param articleId
309         * @param assetId
310         */
311        openModalPlayer: function (event, articleId, assetId) {
312
313            let self = this;
314
315            // Check browser support before opening modal
316            if (!self.isSupportedBrowser()) {
317                self.openModalBrowserNotSupported(event);
318                return;
319            }
320
321            let callbackNonAuthenticated = arguments[3];
322            let callbackNonAuthorised = arguments[4];
323            let callbackError = arguments[5];
324
325            try {
326                document.querySelector('.media-player').classList.remove('media-player--overlay');
327
328                if (self.CONFIG.EmbedPlayer.isConnected()) {
329
330                    self.CONFIG.EmbedPlayer
331                        .castVideo({
332                            articleId: articleId,
333                            assetId: assetId,
334                            token: self.CONFIG.userBearerToken,
335                            continueFromPreviousPosition: self.CONFIG.isNomadicWatchingEnabled,
336                        })
337                        .catch(function (error) {
338                            self.handleApiErrorCallback(event, error.message, error.code, callbackNonAuthenticated, callbackNonAuthorised, callbackError);
339                        })
340                        .finally(() => {
341                            document.querySelector('.media-player').classList.remove('media-player--loading');
342                            self.clearCache();
343                        });
344
345                } else {
346
347                    // Hide the main EmbedPlayer wrapper
348                    $('.audienceplayer-modal-video-player-wrapper').hide();
349                    // Show the modal
350                    self.setActiveModal($('#audienceplayer-modal-video-player'));
351
352                    self.CONFIG.EmbedPlayer
353                        .play({
354                            selector: '.media-player__video-player',
355                            options: self.CONFIG.videoPlayerOptions,
356                            articleId,
357                            assetId,
358                            token: self.CONFIG.userBearerToken,
359                            continueFromPreviousPosition: self.CONFIG.isNomadicWatchingEnabled,
360                        })
361                        .catch(function (error) {
362                            $('#audienceplayer-modal-video-player').hide();
363                            //alert(error.message + ' [' + error.code + ']');
364                            self.handleApiErrorCallback(event, error.message, error.code, callbackNonAuthenticated, callbackNonAuthorised, callbackError);
365                        })
366                        .finally(() => {
367
368                            // Show the main EmbedPlayer wrapper
369                            $('.audienceplayer-modal-video-player-wrapper').fadeIn();
370                            self.clearCache();
371
372                            try {
373                                // Automatically close modal after player "ended" event has triggered
374                                const playerInstance = self.CONFIG.EmbedPlayer.getVideoPlayer();
375                                playerInstance.on('ended', () => {
376                                    self.closeModal(true);
377                                });
378                            } catch (e) {
379                                //
380                            }
381                        });
382                }
383            } catch (e) {
384                // @TODO
385            }
386        },
387
388        /**
389         * Open purchase modal for products and subscriptions
390         * @param event
391         * @param type
392         * @param resourceId
393         * @param message
394         * @param currency
395         * @param price
396         * @param purchaseNum
397         * @param isVoucherValidation
398         * @returns {boolean}
399         */
400        openModalPurchase: function (event, type, resourceId, message, currency, price, purchaseNum, isVoucherValidation) {
401
402            let self = this;
403            purchaseNum = parseInt(purchaseNum) ? parseInt(purchaseNum) : 1;
404
405            // Check browser support before opening modal
406            if (!self.isSupportedBrowser()) {
407                self.openModalBrowserNotSupported(event);
408                return false;
409            }
410
411            let callbackNonAuthenticated = arguments[8];
412            let callbackNonAuthorised = arguments[9];
413            let afterPurchaseRedirectAction = arguments[10];
414            let callbackError = arguments[11];
415
416            let $currentModal = $('#audienceplayer-modal-dialog-purchase');
417            let $voucherCodeInput = $currentModal.find('.voucher-code-input');
418            let $validateButton = $currentModal.find('.voucher-validate-button');
419            let $acceptButton = $currentModal.find('.ok');
420            let $validationResult = $currentModal.find('.voucher-code-validation-result');
421            let $price = $currentModal.find('.price');
422
423            try {
424                $validateButton.unbind();
425                $acceptButton.unbind();
426                $voucherCodeInput.val('');
427                $currentModal.find('.message').html(message);
428                $validationResult.html('');
429                $price.html(price);
430            } catch (e) {
431                // @TODO
432            }
433
434            if (!self.isAuthenticated()) {
435                self.redirectNonAuthenticatedUser(callbackNonAuthenticated);
436                return false;
437            }
438
439            if (isVoucherValidation && type !== 'payment_method') {
440
441                let onSuccessCallback = function (response) {
442                    if (response.data.UserPurchaseIntentAcquire) {
443                        $validationResult.removeClass('error');
444                        $validationResult.html(response.data['UserPurchaseIntentAcquire'].description);
445                        $price.html(response.data['UserPurchaseIntentAcquire'].currency_symbol + ' ' + response.data['UserPurchaseIntentAcquire'].printable_price);
446                    }
447                };
448
449                let onFailureCallback = function (response) {
450                    let errorResponse = self.parseGraphqlErrorResponse(response);
451                    let errorMsg = self.parseErrorCodeTranslationKey(errorResponse.code, 'dialogue_voucher_code_invalid') ?
452                        self.parseTranslationKey(self.parseErrorCodeTranslationKey(errorResponse.code, 'dialogue_voucher_code_invalid')) :
453                        errorResponse.message;
454
455                    // show validation result inline
456                    $validationResult.addClass('error');
457                    $validationResult.html(errorMsg);
458                };
459
460                $validateButton.click(function () {
461                    self.validateVoucherCode(
462                        $validateButton,
463                        $voucherCodeInput.val(),
464                        '[{id:' + resourceId + ',currency:' + currency + ',resource_type:' + type + ',purchase_num:' + purchaseNum + '}]',
465                        onSuccessCallback,
466                        onFailureCallback
467                    );
468                });
469
470                $currentModal.find('.voucher').show();
471            } else {
472                $currentModal.find('.voucher').hide();
473            }
474
475            $acceptButton.click(function (event) {
476
477                if ($acceptButton.isWorking) {
478                    return;
479                } else {
480                    self.toggleElementIsWorking([$acceptButton], true);
481                }
482
483                let operation = '';
484                let responseProperty = '';
485                let voucherCodeOperation = $voucherCodeInput.val() ?
486                    'voucher_code:"' + $voucherCodeInput.val() + '"' :
487                    '';
488
489                switch (type) {
490
491                    case 'product':
492                    case 'subscription':
493                        operation = 'mutation{UserPurchaseIntentAcquire(' +
494                            voucherCodeOperation +
495                            ',is_execute_dry_run:false' +
496                            ',operator_context:web' +
497                            ',purchase_intent_stack:' + '[{id:' + resourceId + ',currency:' + currency + ',resource_type:' + type + ',purchase_num:' + purchaseNum + '}]' +
498                            ',redirect_url_path:"' + self.fetchCurrentUrl({product_id: resourceId}, afterPurchaseRedirectAction, ['purchase_product_id', 'purchase_subscription_id']) + '"' +
499                            '){payment_url,price}}';
500                        responseProperty = 'UserPurchaseIntentAcquire';
501                        break;
502
503                    case 'payment_method':
504                        operation = 'mutation{UserPaymentAccountPaymentMethodUpdate(' +
505                            'user_payment_account_id:' + resourceId +
506                            ',redirect_url_path:"' + self.fetchCurrentUrl({user_payment_account_id: resourceId}, afterPurchaseRedirectAction) + '"' +
507                            '){payment_url,price,user_payment_account_order_id,status}}';
508                        responseProperty = 'UserPaymentAccountPaymentMethodUpdate';
509                        break;
510                }
511
512                self.callApi(
513                    'audienceplayer_api_call',
514                    operation,
515                    null,
516                    function (response) {
517
518                        self.toggleElementIsWorking([$acceptButton], false);
519
520                        // clear cache
521                        window.AudiencePlayerCore.clearCache();
522
523                        // Acquisition was successful
524                        if (response.data[responseProperty].payment_url) {
525                            // redirect to payment provider
526                            self.closeModal();
527                            window.location.replace(response.data[responseProperty].payment_url);
528                        } else {
529                            // payment is not necessary
530                            self.closeModal();
531                            self.openModalAlert(
532                                event,
533                                self.parseTranslationKey(response.data[responseProperty].price ? 'dialogue_product_purchased' : 'dialogue_product_purchased_without_payment'),
534                                null,
535                                self.reloadCurrentPage
536                            );
537                            self.init();
538                        }
539                    },
540                    function (response) {
541
542                        self.toggleElementIsWorking([$acceptButton], false);
543
544                        let errorResponse = self.parseGraphqlErrorResponse(response);
545                        let errorMsg = self.parseErrorCodeTranslationKey(errorResponse.code) ?
546                            self.parseTranslationKey(self.parseErrorCodeTranslationKey(errorResponse.code)) :
547                            errorResponse.message;
548
549                        self.handleApiErrorCallback(
550                            event,
551                            errorMsg,
552                            errorResponse.code,
553                            callbackNonAuthenticated,
554                            callbackNonAuthorised,
555                            callbackError
556                        );
557                    }
558                );
559            });
560
561            self.setActiveModal($currentModal);
562
563            return false;
564        },
565
566
567        /**
568         * Open subscription-switch modal
569         *
570         * @param event
571         * @param userSubscriptionId
572         */
573        openModalSubscriptionSwitch: function (event, userSubscriptionId) {
574
575            let self = this;
576
577            if (userSubscriptionId) {
578
579                // Check browser support before opening modal
580                if (!self.isSupportedBrowser()) {
581                    self.openModalBrowserNotSupported(event);
582                    return;
583                }
584
585                let $currentModal = $('#audienceplayer-modal-dialog-subscription-switch');
586                self.setActiveModal($currentModal);
587
588                let $switchSubscriptionButtons = $currentModal.find('button.switch-subscription-button:not(:disabled)');
589
590                let onClickSubscriptionSwitchCallback = function ($targetButton, switchToSubscriptionId) {
591
592                    // Set targetButton to isWorking and unbind all buttons to prevent clicks
593                    self.toggleElementIsWorking([$targetButton], true);
594                    $switchSubscriptionButtons.unbind();
595
596                    self.callApi(
597                        'audienceplayer_api_call',
598                        'mutation{UserSubscriptionSwitch(' +
599                        'id:' + userSubscriptionId + ',switch_to_subscription_id:' + switchToSubscriptionId +
600                        ')}',
601                        null,
602                        function (response) {
603
604                            // clear cache
605                            window.AudiencePlayerCore.clearCache();
606
607                            // Acquisition was successful
608                            if (response.data['UserSubscriptionSwitch']) {
609                                // reload current page
610                                self.reloadCurrentPage();
611                            } else {
612                                self.toggleElementIsWorking([$targetButton], false);
613                                self.handleApiErrorCallback(null, self.CONFIG.translations.dialogue_error_occurred, 500);
614                            }
615                        },
616                        function (response) {
617
618                            self.toggleElementIsWorking([$targetButton], false);
619
620                            let errorMsg = response.responseJSON.errors[0].message;
621                            let errorCode = response.responseJSON.errors[0].code;
622                            self.handleApiErrorCallback(event, errorMsg, errorCode);
623                        }
624                    );
625                };
626
627                $switchSubscriptionButtons.each(function () {
628
629                    let targetButtonElement = this;
630                    let $targetButton = $(targetButtonElement);
631                    let switchToSubscriptionId = targetButtonElement.value;
632
633                    if (switchToSubscriptionId) {
634                        $targetButton.click(function (event) {
635                            onClickSubscriptionSwitchCallback($targetButton, switchToSubscriptionId);
636                            return false;
637                        });
638                    }
639                });
640
641            } else {
642                // malformed call
643                self.openModalErrorMessage('', self.genericImplementationErrorCode);
644            }
645
646            return false;
647        },
648
649        /**
650         * Open a modal alert dialog
651         * @param event
652         * @param message
653         */
654        openModalAlert: function (event, message) {
655
656            let self = this;
657            let buttonOkLabel = arguments[2];
658            let buttonOkOnClick = arguments[3];
659            let buttonCancelLabel = arguments[4];
660            let buttonCancelOnClick = arguments[5];
661            let valueInput = arguments[6];
662
663            let $currentModal = $('#audienceplayer-modal-dialog-alert');
664
665            $currentModal.customCancelAction = null;
666            $currentModal.find('.value-validation-message').removeClass('error');
667            self.setModalProperty($currentModal, 'value-validation-message', '');
668
669            if (typeof valueInput !== 'undefined') {
670                self.setModalProperty($currentModal, 'value-character-input', typeof valueInput === 'string' ? valueInput : '');
671                self.setModalProperty($currentModal, 'value-input-container', null, true);
672            } else {
673                self.setModalProperty($currentModal, 'value-character-input', '');
674                self.setModalProperty($currentModal, 'value-input-container', null, false);
675            }
676
677            // OK button
678            let $modalButtonOk = $currentModal.find('.ok');
679            $modalButtonOk.unbind();
680            $modalButtonOk.html(buttonOkLabel ? buttonOkLabel : self.parseTranslationKey('button_ok'));
681
682            if (buttonOkOnClick) {
683                $modalButtonOk.click(function (event) {
684                    buttonOkOnClick(event, $modalButtonOk);
685                    return false;
686                });
687            } else {
688                $modalButtonOk.click(function () {
689                    self.closeModal();
690                    return false;
691                });
692            }
693
694            // Cancel button
695            let $modalButtonCancel = $currentModal.find('.cancel');
696            $modalButtonCancel.unbind();
697
698            if (buttonCancelLabel || buttonCancelOnClick) {
699
700                $modalButtonCancel.html(buttonCancelLabel ? buttonCancelLabel : self.parseTranslationKey('button_cancel'));
701
702                // Define custom cancel action, which will also be executed by closeModal
703                if (buttonCancelOnClick) {
704                    $currentModal.customCancelAction = buttonCancelOnClick;
705                }
706
707                $modalButtonCancel.click(function () {
708                    window.AudiencePlayerCore.closeModal(true);
709                    return false;
710                });
711
712                $modalButtonCancel.show();
713            } else {
714                $modalButtonCancel.hide();
715            }
716
717            // Set message and show
718            self.setModalProperty($currentModal, 'message', message);
719            self.setActiveModal($currentModal);
720        },
721
722        openModalBrowserNotSupported: function (event) {
723
724            let message = window.AudiencePlayerBrowserNotSupportedError;
725
726            try {
727                if (this.CONFIG.translations.dialogue_not_optimised_for_current_browser) {
728                    message = this.parseTranslationKey('dialogue_not_optimised_for_current_browser');
729                } else if (window.AudiencePlayerLib.translations.dialogue_not_optimised_for_current_browser) {
730                    message = window.AudiencePlayerLib.translations.dialogue_not_optimised_for_current_browser;
731                } else if (window.AudiencePlayerBrowserNotSupportedError) {
732                    message = window.AudiencePlayerBrowserNotSupportedError;
733                }
734            } catch (e) {
735                //
736            }
737
738            this.openModalAlert(event, message, 'OK');
739        },
740
741        openModalErrorMessage: function (errorMessage, errorCode) {
742            let self = this;
743            self.closeModal(true);
744            self.openModalAlert(null, self.assembleDefaultErrorMsg(errorMessage, errorCode));
745        },
746
747        /**
748         * Close any open modal window
749         * @param isExecuteCustomCancelAction
750         */
751        closeModal: function (isExecuteCustomCancelAction) {
752
753            let $currentModal = this.getActiveModal();
754
755            try {
756
757                if (isExecuteCustomCancelAction && $currentModal.customCancelAction) {
758                    $currentModal.customCancelAction();
759                }
760
761                $currentModal.fadeOut();
762
763                // if current modal is the video player, ensure it is properly destroyed
764                if ($currentModal[0].id === 'audienceplayer-modal-video-player') {
765                    this.CONFIG.EmbedPlayer.destroy();
766                    this.clearCache();
767                }
768
769                this.setActiveModal(null);
770
771            } catch (e) {
772                // @TODO
773            }
774        },
775
776        setActiveModal: function ($modal) {
777            if ($modal) {
778                $modal.fadeIn();
779            }
780            this.$currentActiveModal = $modal;
781        },
782
783        getActiveModal: function () {
784            return this.$currentActiveModal;
785        },
786
787        setModalProperty: function ($modal, targetClass, targetValue, isShow) {
788
789            let $targetModal = $modal ? $modal : this.getActiveModal();
790
791            if ($targetModal) {
792
793                let $property = $targetModal.find('.' + targetClass);
794
795                if (targetValue !== null && targetValue !== undefined) {
796                    if ($property.is('input')) {
797                        $property.val(targetValue);
798                    } else {
799                        $property.html(targetValue);
800                    }
801                }
802
803                if (true === isShow) {
804                    $property.show();
805                } else if (false === isShow) {
806                    $property.hide();
807                }
808            }
809        },
810
811        /**
812         * Validate a voucher code
813         * @param $validateButton
814         * @param voucherCode
815         * @param purchaseIntentStack
816         * @param onSuccessCallback
817         * @param onFailureCallback
818         */
819        validateVoucherCode: function ($validateButton, voucherCode, purchaseIntentStack, onSuccessCallback, onFailureCallback) {
820
821            let self = this;
822
823            if ($validateButton.isWorking) {
824                return;
825            } else {
826                self.toggleElementIsWorking([$validateButton], true);
827            }
828
829            voucherCode = voucherCode ? voucherCode.trim() : '';
830
831            if (voucherCode) {
832
833                let operation = 'mutation{UserPurchaseIntentAcquire(' +
834                    'is_execute_dry_run:true' +
835                    ',operator_context:web' +
836                    ',purchase_intent_stack:' + (purchaseIntentStack ? purchaseIntentStack : '[]') +
837                    ',voucher_code:"' + voucherCode + '"' +
838                    '){' +
839                    'validation_messages{message,code}' +
840                    ',description,price,printable_price,price_before,price_voucher_diff,validation_status,currency,currency_symbol}' +
841                    '}';
842
843                self.callApi(
844                    'audienceplayer_api_call',
845                    operation,
846                    null,
847                    function (response) {
848                        self.toggleElementIsWorking([$validateButton], false);
849                        if (response.data['UserPurchaseIntentAcquire'].validation_messages.length) {
850                            // Validation messages detected on dry-run, mark as failure
851                            onFailureCallback(response);
852                        } else {
853                            // Acquisition was successful
854                            onSuccessCallback(response);
855                        }
856                    },
857                    function (response) {
858                        self.toggleElementIsWorking([$validateButton], false);
859                        onFailureCallback(response);
860                    }
861                );
862
863            } else {
864                self.toggleElementIsWorking([$validateButton], false);
865                try {
866                    onFailureCallback({responseJSON: {errors: [{code: 400}]}});
867                } catch (e) {
868                    //
869                }
870            }
871        },
872
873        assembleDefaultErrorMsg: function (errorMessage, errorCode) {
874            let self = this;
875            return self.parseTranslation(self.CONFIG.translations.dialogue_error_occurred + ': ' + errorMessage, {error_code: errorCode});
876        },
877
878        /**
879         * Handle api error callbacks
880         * @param event
881         * @param errorMessage
882         * @param errorCode
883         * @param callbackNonAuthenticated
884         * @param callbackNonAuthorised
885         * @param callbackError
886         */
887        handleApiErrorCallback: function (event, errorMessage, errorCode, callbackNonAuthenticated, callbackNonAuthorised, callbackError) {
888
889            let self = this;
890
891            //alert(errorMessage + ' [' + errorCode + ']');
892            let errorMsg = self.assembleDefaultErrorMsg(errorMessage, errorCode);
893
894            if (errorCode === 401) {
895
896                // if user is assumed be (lazily) authenticated, the stored accessToken is likely corrupt/invalid
897                if (self.isAuthenticated()) {
898
899                    // try to forcefully refresh the session
900                    self.refreshSession(0, true, function (response) {
901                        self.closeModal(true);
902                        self.openModalAlert(null, 'Please try again!');
903                    }, function (response) {
904                        self.closeModal(true);
905                        if (response.responseJSON.errors[0].code === 404) {
906                            // user was not found during forced synchronisation, admin likely needs to resync
907                            self.openModalAlert(null, self.parseTranslationKey('dialogue_user_not_synchronised'));
908                        } else {
909                            if (callbackNonAuthenticated) {
910                                callbackNonAuthenticated();
911                            } else {
912                                self.openModalAlert(null, self.parseTranslationKey('dialogue_user_not_authenticated'));
913                            }
914                        }
915                    });
916                    return;
917
918                } else if (callbackNonAuthenticated) {
919
920                    self.closeModal(true);
921                    try {
922                        callbackNonAuthenticated();
923                    } catch (e) {
924                    }
925                    return;
926
927                } else {
928
929                    self.closeModal(true);
930                    errorMsg = self.parseTranslationKey('dialogue_user_not_authenticated');
931                }
932
933            } else if (errorCode === 402) {
934
935                self.closeModal(true);
936                if (callbackNonAuthorised) {
937                    try {
938                        callbackNonAuthorised();
939                    } catch (e) {
940                    }
941                    return;
942                } else {
943                    errorMsg = self.parseTranslationKey('dialogue_payment_required_for_video');
944                }
945
946            } else if (errorCode === 403) {
947
948                self.closeModal(true);
949                errorMsg = self.parseTranslationKey('dialogue_video_not_available_in_regi
949on');
950
951            } else if (errorCode === 407) {
952
953                self.closeModal(true);
954                errorMsg = self.parseTranslationKey('dialogue_user_not_synchronised');
955
956            } else if (errorCode === 3201) {
957
958                self.closeModal(true);
959                errorMsg = self.parseTranslationKey('dialogue_subscription_already_valid');
960
961            } else if (errorCode === 3800 || errorCode === 409) {
962
963                self.closeModal(true);
964                errorMsg = self.parseTranslationKey('dialogue_product_already_purchased');
965
966            } else if (callbackError) {
967
968                self.closeModal(true);
969                try {
970                    callbackError();
971                } catch (e) {
972                }
973
974            } else {
975                self.closeModal(false);
976            }
977
978            self.openModalAlert(null, errorMsg ? errorMsg : errorMessage);
979        },
980
981        /**
982         * Toggle user-subscription status
983         * @param event
984         * @param type
985         * @param resourceId
986         * @param message
987         * @param price
988         * @param isVoucherValidation
989         */
990        toggleUserSubscriptionStatus: function (event, userSubscriptionId, isRenew) {
991
992            let self = this;
993            let $elementToggle = $(event);
994
995            let callbackNonAuthenticated = arguments[3];
996            let callbackError = arguments[4];
997
998            if (!self.isAuthenticated()) {
999                self.redirectNonAuthenticatedUser(callbackNonAuthenticated);
1000                return;
1001            } else if ($elementToggle.isWorking) {
1002                return;
1003            } else {
1004                self.toggleGenericModalLoader(true);
1005                self.toggleElementIsWorking([$elementToggle], true);
1006            }
1007
1008            let operation = '';
1009            let responseProperty = '';
1010
1011            if (isRenew) {
1012                operation = 'mutation{UserSubscriptionUnSuspend(id:' + userSubscriptionId + ')}';
1013                responseProperty = 'UserSubscriptionUnSuspend';
1014            } else {
1015                operation = 'mutation{UserSubscriptionSuspend(id:' + userSubscriptionId + ')}';
1016                responseProperty = 'UserSubscriptionSuspend';
1017            }
1018
1019            self.callApi(
1020                'audienceplayer_api_call',
1021                operation,
1022                null,
1023                function (response) {
1024
1025                    if (isRenew) {
1026                        $('.subscription-info .invoiced-at .value').removeClass('disabled');
1027                    } else {
1028                        $('.subscription-info .invoiced-at .value').addClass('disabled');
1029                    }
1030
1031                    self.toggleGenericModalLoader(false);
1032                    self.toggleElementIsWorking([$elementToggle], false);
1033                },
1034                function (response) {
1035
1036                    // revert toggle status
1037                    $elementToggle.prop('checked', !isRenew);
1038
1039                    self.toggleGenericModalLoader(false);
1040                    self.toggleElementIsWorking([$elementToggle], false);
1041
1042                    let errorMsg = response.responseJSON.errors[0].message;
1043                    let errorCode = response.responseJSON.errors[0].code;
1044
1045                    self.handleApiErrorCallback(
1046                        event,
1047                        errorMsg,
1048                        errorCode,
1049                        callbackNonAuthenticated,
1050                        null,
1051                        callbackError
1052                    );
1053                }
1054            );
1055        },
1056
1057        /**
1058         * Toggle user notifiable status
1059         * @param event
1060         * @param isNotifiable
1061         * @param $phoneNumber
1062         */
1063        toggleUserNotifiableStatus: function (event, isNotifiable, $phoneNumber) {
1064
1065            let self = this;
1066            let $elementToggle = $(event);
1067            let callbackNonAuthenticated = arguments[3];
1068            let callbackError = arguments[4];
1069
1070            // if notifiable, proceed with step 1/2 and validate phoneNumber. Else fall-through and attempt to set notifiable:none
1071            if (isNotifiable) {
1072
1073                self.notifiableVerifyUserPhoneNumber(event, isNotifiable, $phoneNumber, 
1073callbackNonAuthenticated, callbackError);
1074
1075            } else if (!self.isAuthenticated()) {
1076
1077                self.redirectNonAuthenticatedUser(callbackNonAuthenticated);
1078
1079            } else if (!$elementToggle.isWorking) {
1080
1081                self.toggleGenericModalLoader(true);
1082                self.toggleElementIsWorking([$elementToggle], true);
1083
1084                self.callApi(
1085                    'audienceplayer_api_call',
1086                    'mutation{UserDetailsUpdate(notifiable:none){id,notifiable}}',
1087                    null,
1088                    function (response) {
1089
1090                        self.toggleGenericModalLoader(false);
1091                        self.toggleElementIsWorking([$elementToggle], false);
1092                    },
1093                    function (response) {
1094
1095                        // revert toggle status
1096                        $elementToggle.prop('checked', !isNotifiable);
1097
1098                        self.toggleGenericModalLoader(false);
1099                        self.toggleElementIsWorking([$elementToggle], false);
1100
1101                        let errorMsg = response.responseJSON.errors[0].message;
1102                        let errorCode = response.responseJSON.errors[0].code;
1103
1104                        self.handleApiErrorCallback(
1105                            event,
1106                            errorMsg,
1107                            errorCode,
1108                            callbackNonAuthenticated,
1109                            null,
1110                            callbackError
1111                        );
1112                    }
1113                );
1114            }
1115        },
1116
1117        /**
1118         * toggleUserNotifiableStatus - step 1/2: verify phone number
1119         * @param event
1120         * @param isNotifiable
1121         * @param $phoneNumber
1122         * @param callbackNonAuthenticated
1123         * @param callbackError
1124         */
1125        notifiableVerifyUserPhoneNumber: function (event, isNotifiable, $phoneNumber, callbackNonAuthenticated, callbackError) {
1126
1127            let self = this;
1128            let $elementToggle = $(event);
1129
1130            if ($elementToggle.isWorking) {
1131
1132                return;
1133
1134            } else if (!self.isAuthenticated()) {
1135
1136                self.redirectNonAuthenticatedUser(callbackNonAuthenticated);
1137                return;
1138
1139            } else {
1140
1141                let cancelAction = function () {
1142                    // revert toggle status
1143                    $elementToggle.prop('checked', !isNotifiable);
1144                };
1145
1146                let okAction = function (ev, $okButton, $currentModal) {
1147
1148                    if ($okButton.isWorking) {
1149                        return;
1150                    } else {
1151                        self.toggleElementIsWorking([$okButton], true);
1152                    }
1153
1154                    // update phone number
1155                    $phoneNumber.val($('#audienceplayer-modal-dialog-alert-value-input').val());
1156
1157                    let continueAction = function () {
1158                        self.openModalAlert(
1159                            event,
1160                            self.parseTranslationKey('dialogue_phone_number_change_request'),
1161                            self.parseTranslationKey('button_next'),
1162                            function () {
1163                                self.notifiableVerifyPairingCode(event, isNotifiable, $phoneNumber, callbackNonAuthenticated, callbackError);
1164                            },
1165                            self.parseTranslationKey('button_cancel'),
1166                            cancelAction
1167                        );
1168                    };
1169
1170                    self.callApi(
1171                        'audienceplayer_api_call',
1172                        'mutation{UserDetailsUpdate(phone:"' + $phoneNumber.val() +
1173                        '",notifiable:' + (isNotifiable ? 'sms' : 'none') + '){id,phone,notifiable}}',
1174                        null,
1175                        function (response) {
1176
1177                            self.toggleElementIsWorking([$elementToggle, $okButton], false);
1178
1179                            if (response.data.UserDetailsUpdate.notifiable === 'sms') {
1180                                self.closeModal();
1181                            } else {
1182                                // phone number has likely changed, since notifiable hasn't been set to 'sms'
1183                                continueAction();
1184                            }
1185                        },
1186                        function (response) {
1187
1188                            self.toggleElementIsWorking([$elementToggle, $okButton], false);
1189
1190                            let errorMsg = response.responseJSON.errors[0].message;
1191                            let errorCode = response.responseJSON.errors[0].code;
1192
1193                            if (errorCode === 400) {
1194                                // phone number incorrect
1195                                self.getActiveModal().find('.value-validation-message').addClass('error');
1196                                self.setModalProperty(null, 'value-validation-message', self.parseTranslationKey('form_validation_error_phone_number'));
1197                            } else if (errorCode === 402) {
1198                                self.openModalErrorMessage(self.parseTranslationKey('dialogue_notification_enabling_not_authorised'), errorCode);
1199                            } else if (errorCode === 403) {
1200                                continueAction();
1201                            } else {
1202                                self.handleApiErrorCallback(
1203                                    event,
1204                                    errorMsg,
1205                                    errorCode,
1206                                    callbackNonAuthenticated,
1207                                    null,
1208                                    callbackError
1209                                );
1210                            }
1211                        }
1212                    );
1213                };
1214
1215                self.openModalAlert(
1216                    event,
1217                    self.parseTranslationKey('form_validation_error_phone_number_fill_first'),
1218                    self.parseTranslationKey('button_ok'),
1219                    okAction,
1220                    self.parseTranslationKey('button_cancel'),
1221                    cancelAction,
1222                    $phoneNumber.val()
1223                );
1224            }
1225        },
1226
1227        /**
1228         * toggleUserNotifiableStatus - step 2/2: verify code
1229         * @param event
1230         * @param isNotifiable
1231         * @param $phoneNumber
1232         * @param callbackNonAuthenticated
1233         * @param callbackError
1234         */
1235        notifiableVerifyPairingCode: function (event, isNotifiable, $phoneNumber, 
1235callbackNonAuthenticated, callbackError) {
1236
1237            let self = this;
1238            let $elementToggle = $(event);
1239
1240            if ($elementToggle.isWorking) {
1241
1242                return;
1243
1244            } else if (!self.isAuthenticated()) {
1245
1246                self.redirectNonAuthenticatedUser(callbackNonAuthenticated);
1247                return;
1248
1249            } else {
1250
1251                let errorCallback = function (response) {
1252
1253                    let errorMsg = response.responseJSON.errors[0].message;
1254                    let errorCode = response.responseJSON.errors[0].code;
1255
1256                    self.handleApiErrorCallback(
1257                        event,
1258                        errorMsg,
1259                        errorCode,
1260                        callbackNonAuthenticated
1261                    );
1262                };
1263
1264                self.callApi(
1265                    'audienceplayer_api_call',
1266                    'mutation{UserDetailsPhoneVerifyRequest}',
1267                    null,
1268                    function (response) {
1269
1270                        self.toggleElementIsWorking([$elementToggle], false);
1271
1272                        let okAction = function (ev, $okButton, $currentModal) {
1273
1274                            if ($okButton.isWorking) {
1275                                return;
1276                            } else {
1277                                self.toggleElementIsWorking([$okButton], true);
1278                            }
1279
1280                            let operation = 'mutation{' +
1281                                'resultVerify:UserDetailsPhoneVerifyValidate(code:"' + $('#audienceplayer-modal-dialog-alert-value-input').val() + '")' +
1282                                'resultUpdate:UserDetailsUpdate(phone:"' + $phoneNumber.val() + '",notifiable:' + (isNotifiable ? 'sms' : 'none') + '){id,phone,notifiable}' +
1283                                '}';
1284
1285                            self.callApi(
1286                                'audienceplayer_api_call',
1287                                operation,
1288                                null,
1289                                function (response) {
1290
1291                                    self.toggleElementIsWorking([$elementToggle, $okButton], false);
1292                                    self.openModalAlert(event, self.parseTranslationKey('dialogue_phone_number_verified'));
1293
1294                                },
1295                                function (response) {
1296                                    if (!response.responseJSON.data.resultVerify) {
1297                                        self.getActiveModal().find('.value-validation-message').addClass('error');
1298                                        self.setModalProperty(null, 'value-validation-message', self.parseTranslationKey('dialogue_error_phone_number_pairing_code_not_valid'));
1299                                        self.toggleElementIsWorking([$okButton], false);
1300                                    } else {
1301                                        errorCallback();
1302                                    }
1303                                }
1304                            );
1305                        };
1306
1307                        let cancelAction = function () {
1308                            // revert toggle status
1309                            $elementToggle.prop('checked', !isNotifiable);
1310                        };
1311
1312                        self.openModalAlert(
1313                            event,
1314                            self.parseTranslationKey('dialogue_phone_number_verify_via_text_message'),
1315                            self.parseTranslationKey('button_ok'),
1316                            okAction,
1317                            self.parseTranslationKey('button_cancel'),
1318                            cancelAction,
1319                            true
1320                        );
1321                    },
1322                    errorCallback
1323                );
1324            }
1325        },
1326
1327        /**
1328         * Redeem user account voucher code
1329         * @param event
1330         * @param voucherCode
1331         */
1332        redeemUserAccountVoucherCode: function (event, voucherCode) {
1333
1334            let self = this;
1335            let $validateButton = $(event);
1336            voucherCode = voucherCode ? voucherCode.trim() : '';
1337
1338            let onFailureCallback = function (response) {
1339
1340                let errorResponse = self.parseGraphqlErrorResponse(response);
1341                if (self.parseErrorCodeTranslationKey(errorResponse.code)) {
1342                    self.openModalErrorMessage(self.parseTranslationKey(self.parseErrorCodeTranslationKey(errorResponse.code, 'dialogue_voucher_code_invalid')), errorResponse.code);
1343                } else if (errorResponse.code === 422) {
1344                    self.openModalErrorMessage(self.parseTranslationKey('dialogue_voucher_code_applicable_subscription_unknown'), errorResponse.code);
1345                } else {
1346                    self.handleApiErrorCallback(event, errorResponse.message, errorResponse.code);
1347                }
1348
1349            };
1350
1351            let onSuccessCallback = function (response) {
1352
1353                self.openModalAlert(
1354                    null,
1355                    response.data['UserPurchaseIntentAcquire'].description,
1356                    self.parseTranslationKey('button_payment_accept_complete'),
1357                    function (event, $modalButton) {
1358
1359                        if ($modalButton.isWorking) {
1360                            return;
1361                        } else {
1362                            self.toggleElementIsWorking([$modalButton], true);
1363                        }
1364
1365                        let operation = 'mutation{UserPurchaseIntentAcquire(' +
1366                            'is_execute_dry_run:false' +
1367                            ',operator_context:web' +
1368                            ',purchase_intent_stack:[]' +
1369                            ',voucher_code:"' + voucherCode + '"' +
1370                            ',redirect_url_path:"' + self.fetchCurrentUrl() + '"' +
1371                            '){payment_url,price}}';
1372
1373                        self.callApi(
1374                            'audienceplayer_api_call',
1375                            operation,
1376                            null,
1377                            function (response) {
1378                                self.toggleElementIsWorking([$modalButton], false);
1379
1380                                // clear cache
1381                                window.AudiencePlayerCore.clearCache();
1382
1383                                // Acquisition was successful
1384                                if (response.data['UserPurchaseIntentAcquire'].payment_url) {
1385                                    // redirect to payment provider
1386                                    window.location.replace(response.data['UserPurchaseIntentAcquire'].payment_url);
1387                                } else {
1388                                    // payment is not necessary
1389                                    self.closeModal();
1390                                    self.openModalAlert(
1391                                        event,
1392                                        self.parseTranslationKey(response.data['UserPurchaseIntentAcquire'].price ? 'dialogue_product_purchased' : 'dialogue_product_purchased_without_payment'),
1393                                        null,
1394                                        self.reloadCurrentPage
1395                                    );
1396                                    self.init();
1397                                }
1398                            },
1399                            function (response) {
1400                                self.toggleElementIsWorking([$modalButton], false);
1401                                onFailureCallback(response);
1402                            }
1403                        );
1404                    }
1405                );
1406            };
1407
1408            self.validateVoucherCode($validateButton, voucherCode, '[]', onSuccessCallback, onFailureCallback);
1409        },
1410
1411        /**
1412         * Claim device pairing code
1413         * @param event
1414         * @param pairingCode
1415         */
1416        claimDevicePairingCode: function (event, pairingCode) {
1417
1418            let self = this;
1419            let $validateButton = $(event);
1420
1421            if (pairingCode = pairingCode.trim()) {
1422
1423                if ($validateButton.isWorking) {
1424                    return;
1425                } else {
1426                    self.toggleElementIsWorking([$validateButton], true);
1427                }
1428
1429                let operation = 'mutation{UserDevicePairingClaim(' +
1430                    'pairing_code:"' + pairingCode + '"' +
1431                    '){uuid name created_at}}';
1432
1433                self.callApi(
1434                    'audienceplayer_api_call',
1435                    operation,
1436                    null,
1437                    function (response) {
1438                        self.toggleElementIsWorking([$validateButton], false);
1439                        self.closeModal();
1440                        self.openModalAlert(
1441                            event,
1442                            self.parseTranslationKey('dialogue_device_successfully_paired'),
1443                            null,
1444                            self.reloadCurrentPage
1445                        );
1446                    },
1447                    function (response) {
1448                        self.toggleElementIsWorking([$validateButton], false);
1449
1450                        let errorMsg = response.responseJSON.errors[0].message;
1451                        let errorCode = response.responseJSON.errors[0].code;
1452                        if (errorCode === 400) {
1453                            self.openModalErrorMessage(self.parseTranslationKey('dialogue_pairing_code_not_val
1453id'), errorCode);
1454                        } else {
1455                            self.handleApiErrorCallback(event, errorMsg, errorCode);
1456                        }
1457                    }
1458                );
1459            }
1460        },
1461
1462        /**
1463         * Remove an already paired device
1464         * @param event
1465         * @param deviceId
1466         * @param deviceName
1467         */
1468        removePairedDevice: function (event, deviceId, deviceName) {
1469
1470            let self = this;
1471
1472            if (deviceId) {
1473
1474                let deviceNameText = deviceName ? '<br/><div class="device-name">"' + deviceName + '"</div>' : '';
1475
1476                self.openModalAlert(
1477                    null,
1478                    self.parseTranslationKey('dialogue_device_confirm_unpairing') + deviceNameText,
1479                    null,
1480                    function (event, $modalButton) {
1481
1482                        self.toggleElementIsWorking([$modalButton], true);
1483
1484                        let operation = 'mutation{UserDevicePairingDelete(device_id:' + deviceId + ')}';
1485
1486                        self.callApi(
1487                            'audienceplayer_api_call',
1488                            operation,
1489                            null,
1490                            function (response) {
1491                                self.toggleElementIsWorking([$modalButton], false);
1492                                self.closeModal();
1493                                self.openModalAlert(
1494                                    event,
1495                                    self.parseTranslationKey('dialogue_device_successfully_unpaired'),
1496                                    null,
1497                                    self.reloadCurrentPage
1498                                );
1499                            },
1500                            function (response) {
1501                                self.toggleElementIsWorking([$modalButton], false);
1502                                let errorMsg = self.parseTranslationKey('dialogue_device_not_unpaired');
1503                                let errorCode = response.responseJSON.errors[0].code;
1504                                self.handleApiErrorCallback(event, errorMsg, errorCode);
1505                            }
1506                        );
1507                    },
1508                    self.parseTranslationKey('button_cancel')
1509                );
1510            }
1511        },
1512
1513        /* ### HELPERS ### */
1514
1515        isset: function () {
1516            if (arguments.length > 0) {
1517                for (let i = 0; i < arguments.length; i++) {
1518                    if (typeof arguments[i] === 'undefined') {
1519                        return false;
1520                    }
1521                }
1522                return true;
1523            } else {
1524                return false;
1525            }
1526        },
1527
1528        isSupportedBrowser: function () {
1529
1530            // Nasic check to ensure browser is in the Internet Explorer family (version <= 11)
1531            let isIE = /MSIE|Trident/.test(window.navigator.userAgent);
1532            return !isIE;
1533        },
1534
1535        setCache: function (key, value) {
1536            try {
1537                //if (typeof value === 'object' || typeof value === 'array') {}
1538                return window.localStorage.setItem(key, JSON.stringify(value));
1539            } catch (e) {
1540                return null;
1541            }
1542        },
1543
1544        fetchCache: function (key) {
1545            try {
1546                return JSON.parse(window.localStorage.getItem(key));
1547            } catch (e) {
1548                return null;
1549            }
1550        },
1551
1552        clearCache: function () {
1553            for (let i in this.STORE) {
1554                this.removeCache(this.STORE[i].key);
1555            }
1556        },
1557
1558        removeCache: function (key) {
1559            try {
1560                return window.localStorage.removeItem(key);
1561            } catch (e) {
1562                return null;
1563            }
1564        },
1565
1566        parseCurrentUrlQsa: function (paramsObject) {
1567
1568            let qsa = window.location.search;
1569
1570            for (let key in paramsObject) {
1571
1572                if (qsa) {
1573
1574                    let re = new RegExp('(\\?|&)' + key + '=([^&]*)(&|$)');
1575
1576                    if (re.test(qsa)) {
1577                        qsa = qsa.replace(re, '$1' + key + '=' + paramsObject[ke
1577y] + '$3');
1578                    } else {
1579                        qsa += '&' + key + '=' + paramsObject[key];
1580                    }
1581
1582                } else {
1583                    qsa += '?' + key + '=' + paramsObject[key];
1584                }
1585            }
1586
1587            return qsa;
1588        },
1589
1590        removeQsaParametersFromString: function (paramsObject) {
1591            let qsa = arguments[1] ? arguments[1] : window.location.search;
1592
1593            if (qsa) {
1594
1595                for (let key in paramsObject) {
1596
1597                    let param = Array.isArray(paramsObject) ? paramsObject[key] : key;
1598
1599                    let re = new RegExp('(\\?|&)(' + param + '=[^&]*(&|$))');
1600
1601                    if (re.test(qsa)) {
1602                        qsa = qsa.replace(re, '$1');
1603                    }
1604                }
1605            }
1606
1607            return qsa;
1608        },
1609
1610        removeQsaParametersFromCurrentLocation: function (paramsObject) {
1611
1612            if (paramsObject) {
1613
1614                let sanitisedUrl = new URL(window.location);
1615
1616                for (let key in paramsObject) {
1617
1618                    let param = Array.isArray(paramsObject) ? paramsObject[key] : key;
1619                    sanitisedUrl.searchParams.delete(param);
1620                }
1621
1622                window.history.pushState({}, "", sanitisedUrl);
1623            }
1624        },
1625
1626        fetchCurrentUrl: function (queryParamObject) {
1627
1628            let ret = window.location.href.split('?')[0];
1629
1630            if (queryParamObject && arguments[1]) {
1631                queryParamObject.after_purchase_action = arguments[1];
1632            } else if (arguments[1]) {
1633                queryParamObject = {after_purchase_action: arguments[1]};
1634            }
1635
1636            let qsa = this.parseCurrentUrlQsa(queryParamObject);
1637
1638            if (qsa) {
1639                ret += qsa;
1640            }
1641
1642            if (arguments[2]) {
1643                ret = this.removeQsaParametersFromString(arguments[2], ret);
1644            }
1645
1646            return ret;
1647        },
1648
1649        toggleElementIsWorking: function ($elements, status) {
1650
1651            let className = arguments[2] ? arguments[2] : 'audienceplayer-button-loading';
1652
1653            for (let i in $elements) {
1654                if (status) {
1655                    $elements[i].isWorking = true;
1656                    $elements[i].addClass(className);
1657                    $elements[i].attr("disabled", true);
1658                } else {
1659                    $elements[i].isWorking = false;
1660                    $elements[i].removeClass(className);
1661                    $elements[i].attr("disabled", false);
1662                }
1663            }
1664        },
1665
1666        toggleGenericModalLoader: function (status) {
1667            if (status) {
1668                $('#audienceplayer-modal-generic-loader').fadeIn();
1669            } else {
1670                $('#audienceplayer-modal-generic-loader').fadeOut();
1671            }
1672        },
1673
1674        reloadCurrentPage: function () {
1675            window.location.reload();
1676        },
1677
1678        parseTranslation: function (translation, vars) {
1679
1680            if (translation) {
1681
1682                // replaced given variables
1683                for (let key in vars) {
1684
1685                    let re = new RegExp('{{\\s*' + key + '\\s*}}');
1686
1687                    if (re.test(translation)) {
1688                        translation = translation.replace(re, vars[key]);
1689                    }
1690                }
1691
1692                // remove all unused variables
1693                let re = new RegExp('{{.*}}');
1694                translation = translation.replace(re, '');
1695            }
1696
1697            return translation;
1698        },
1699
1700        parseTranslationKey: function (key, vars) {
1701            return this.parseTranslation(this.CONFIG.translations[key], vars);
1702        },
1703
1704        parseErrorCodeTranslationKey: function (errorCode, fallbackTranslation) {
1705            return this.ERROR_CODE_TRANSLATIONS[errorCode] ?
1706                this.ERROR_CODE_TRANSLATIONS[errorCode] :
1707                (fallbackTranslation = fallbackTranslation ? fallbackTranslation.trim() : '');
1708        },
1709
1710        parseGraphqlErrorResponse: function (response) {
1711
1712            let errorMessage = response.statusText;
1713            let errorCode = response.status;
1714
1715            if (response.responseJSON && response.responseJSON.errors) {
1716                errorMessage = response.responseJSON.errors[0].message;
1717                errorCode = response.responseJSON.errors[0].code;
1718            } else if (response.data['UserPurchaseIntentAcquire'] && response.data['UserPurchaseIntentAcquire'].validation_messages.length) {
1719                errorMessage = response.data['UserPurchaseIntentAcquire'].validation_messages[0].message;
1720                errorCode = response.data['UserPurchaseIntentAcquire'].validation_messages[0].code;
1721            }
1722
1723            return {
1724                message: errorMessage,
1725                code: errorCode,
1726            };
1727        }
1728
1729    };
1730
1731    // Initialise AudiencePlayerCore
1732    window.AudiencePlayerCore.init();
1733
1734});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.