UNPKG

@agencycoda/ngx-paypal

Version:
356 lines (348 loc) 12.9 kB
import { CommonModule } from '@angular/common'; import { Injectable, NgZone, EventEmitter, Component, ChangeDetectionStrategy, ChangeDetectorRef, Input, Output, ViewChild, NgModule } from '@angular/core'; import { Subject } from 'rxjs'; class ScriptService { constructor(zone) { this.zone = zone; } registerScript(url, globalVar, onReady) { const existingGlobalVar = window[globalVar]; if (existingGlobalVar) { // global variable is present = script was already loaded this.zone.run(() => { onReady(existingGlobalVar); }); return; } // prepare script elem const scriptElem = document.createElement('script'); scriptElem.id = this.getElemId(globalVar); scriptElem.innerHTML = ''; scriptElem.onload = () => { this.zone.run(() => { onReady(window[globalVar]); }); }; scriptElem.src = url; scriptElem.async = true; scriptElem.defer = true; // add script to header document.getElementsByTagName('head')[0].appendChild(scriptElem); } cleanup(globalVar) { // remove script from DOM const scriptElem = document.getElementById(this.getElemId(globalVar)); if (scriptElem) { scriptElem.remove(); } } getElemId(globalVar) { return `ngx-paypal-script-elem-${globalVar}`; } } ScriptService.decorators = [ { type: Injectable } ]; /** @nocollapse */ ScriptService.ctorParameters = () => [ { type: NgZone } ]; class PayPalScriptService { constructor(scriptService) { this.scriptService = scriptService; this.paypalWindowName = 'paypal'; } registerPayPalScript(config, onReady) { this.scriptService.registerScript(this.getUrlForConfig(config), this.paypalWindowName, onReady); } destroyPayPalScript() { this.scriptService.cleanup(this.paypalWindowName); } getUrlForConfig(config) { const params = [ { name: 'client-id', value: config.clientId } ]; if (config.currency) { params.push({ name: 'currency', value: config.currency }); } if (config.commit) { params.push({ name: 'commit', value: config.commit }); } if (config.vault) { params.push({ name: 'vault', value: config.vault }); } if (config.extraParams) { params.push(...config.extraParams); } return `https://www.paypal.com/sdk/js${this.getQueryString(params)}`; } getQueryString(queryParams) { let queryString = ''; for (let i = 0; i < queryParams.length; i++) { const queryParam = queryParams[i]; if (i === 0) { queryString += '?'; } else { queryString += '&'; } queryString += `${queryParam.name}=${queryParam.value}`; } return queryString; } } PayPalScriptService.decorators = [ { type: Injectable } ]; /** @nocollapse */ PayPalScriptService.ctorParameters = () => [ { type: ScriptService } ]; class NgxPaypalComponent { constructor(paypalScriptService, cdr, ngZone) { this.paypalScriptService = paypalScriptService; this.cdr = cdr; this.ngZone = ngZone; /** * If enabled, paypal SDK script will be loaded. Useful if you want to have multiple PayPal components on the same page * sharing base configuration. In such a case only a single component may register script. */ this.registerScript = true; /** * Emitted when paypal script is loaded */ this.scriptLoaded = new EventEmitter(); this.ngUnsubscribe = new Subject(); /** * Flag that indicates if paypal should be initialized (required for handling script load events and availability of DOM element) */ this.initializePayPal = true; } set payPalButtonContainer(content) { this.payPalButtonContainerElem = content; } ngOnChanges(changes) { if (!this.payPalButtonContainerId) { this.payPalButtonContainerId = this.generateElementId(); } // first time config setup const config = this.config; if (changes.config.isFirstChange()) { if (config && this.registerScript) { this.initPayPalScript(config, (payPal) => { // store reference to paypal global script this.payPal = payPal; this.doPayPalCheck(); }); } } // changes to config if (!changes.config.isFirstChange()) { this.reinitialize(config); } } ngOnDestroy() { this.paypalScriptService.destroyPayPalScript(); this.ngUnsubscribe.next(); this.ngUnsubscribe.complete(); } ngAfterViewInit() { this.doPayPalCheck(); } customInit(payPal) { this.payPal = payPal; this.doPayPalCheck(); } reinitialize(config) { this.config = config; this.payPal = undefined; this.paypalScriptService.destroyPayPalScript(); this.payPalButtonContainerId = this.generateElementId(); this.initializePayPal = true; if (this.payPalButtonContainerElem) { while (this.payPalButtonContainerElem.nativeElement.firstChild) { this.payPalButtonContainerElem.nativeElement.removeChild(this.payPalButtonContainerElem.nativeElement.firstChild); } } this.cdr.detectChanges(); if (this.config) { if (!this.payPal) { this.initPayPalScript(this.config, (payPal) => { // store reference to paypal global script this.payPal = payPal; this.doPayPalCheck(); }); } else { this.doPayPalCheck(); } } } doPayPalCheck() { if (this.initializePayPal && this.config && this.payPal && this.payPalButtonContainerElem) { // make sure that id is also set if (this.payPalButtonContainerElem.nativeElement.id) { this.initializePayPal = false; this.initPayPal(this.config, this.payPal); } } } initPayPalScript(config, initPayPal) { this.paypalScriptService.registerPayPalScript({ clientId: config.clientId, commit: config.advanced && config.advanced.commit ? config.advanced.commit : undefined, currency: config.currency, vault: config.vault, extraParams: config.advanced && config.advanced.extraQueryParams ? config.advanced.extraQueryParams : [] }, (paypal) => { this.scriptLoaded.next(paypal); initPayPal(paypal); }); } generateElementId() { return `ngx-captcha-id-${new Date().valueOf()}`; } initPayPal(config, paypal) { // Running outside angular zone prevents infinite ngDoCheck lifecycle calls this.ngZone.runOutsideAngular(() => { // https://developer.paypal.com/docs/checkout/integrate/#2-add-the-paypal-script-to-your-web-page const createOrder = (data, actions) => { return this.ngZone.run(() => { if (config.createOrderOnClient && config.createOrderOnServer) { throw Error(`Both 'createOrderOnClient' and 'createOrderOnServer' are defined. Please choose one or the other.`); } if (!config.createOrderOnClient && !config.createOrderOnServer) { throw Error(`Neither 'createOrderOnClient' or 'createOrderOnServer' are defined. Please define one of these to create order.`); } if (config.createOrderOnClient) { return actions.order.create(config.createOrderOnClient(data)); } if (config.createOrderOnServer) { return config.createOrderOnServer(data); } throw Error(`Invalid state for 'createOrder'.`); }); }; const createSubscription = (data, actions) => { return this.ngZone.run(() => { if (config.createSubscription) { return config.createSubscription(data, actions); } }); }; const onShippingChange = (data, actions) => { return this.ngZone.run(() => { if (config.onShippingChange) { return config.onShippingChange(data, actions); } }); }; const buttonsConfig = Object.assign(Object.assign(Object.assign({ style: config.style, onApprove: (data, actions) => { return this.ngZone.run(() => { if (config.onApprove) { config.onApprove(data, actions); } // capture on server if (config.authorizeOnServer) { return config.authorizeOnServer(data, actions); } // capture on client const onClientAuthorization = config.onClientAuthorization; if (onClientAuthorization) { actions.order.capture().then((details) => { this.ngZone.run(() => { onClientAuthorization(details); }); }); return; } }); }, onError: (error) => { this.ngZone.run(() => { if (config.onError) { config.onError(error); } }); }, onCancel: (data, actions) => { this.ngZone.run(() => { if (config.onCancel) { config.onCancel(data, actions); } }); }, onClick: (data, actions) => { this.ngZone.run(() => { if (config.onClick) { config.onClick(data, actions); } }); }, onInit: (data, actions) => { this.ngZone.run(() => { if (config.onInit) { config.onInit(data, actions); } }); } }, ((config.createOrderOnClient || config.createOrderOnServer) && { createOrder })), (config.createSubscription && { createSubscription })), (config.onShippingChange && { onShippingChange })); paypal.Buttons(buttonsConfig).render(`#${this.payPalButtonContainerId}`); }); } } NgxPaypalComponent.decorators = [ { type: Component, args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ngx-paypal', template: ` <div #payPalButtonContainer [id]="payPalButtonContainerId"></div> ` },] } ]; /** @nocollapse */ NgxPaypalComponent.ctorParameters = () => [ { type: PayPalScriptService }, { type: ChangeDetectorRef }, { type: NgZone } ]; NgxPaypalComponent.propDecorators = { config: [{ type: Input }], registerScript: [{ type: Input }], scriptLoaded: [{ type: Output }], payPalButtonContainer: [{ type: ViewChild, args: ['payPalButtonContainer', { static: false },] }] }; class NgxPayPalModule { } NgxPayPalModule.decorators = [ { type: NgModule, args: [{ imports: [ CommonModule ], declarations: [ NgxPaypalComponent, ], exports: [ NgxPaypalComponent, ], providers: [ ScriptService, PayPalScriptService ] },] } ]; /** Public API */ /** * Generated bundle index. Do not edit. */ export { NgxPayPalModule, NgxPaypalComponent, PayPalScriptService, ScriptService as ɵa }; //# sourceMappingURL=agencycoda-ngx-paypal.js.map