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.