/** * Copyright since 2007 PrestaShop SA and Contributors * PrestaShop is an International Registered Trademark & Property of PrestaShop SA * * NOTICE OF LICENSE * * This source file is subject to the Open Software License (OSL 3.0) * that is bundled with this package in the file LICENSE.md. * It is also available through the world-wide-web at this URL: * https://opensource.org/licenses/OSL-3.0 * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@prestashop.com so we can send you a copy immediately. * * DISCLAIMER * * Do not edit or add to this file if you wish to upgrade PrestaShop to newer * versions in the future. If you wish to customize PrestaShop for your * needs please refer to https://devdocs.prestashop.com/ for more information. * * @author PrestaShop SA and Contributors * @copyright Since 2007 PrestaShop SA and Contributors * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) */ import IframeModal, { IframeModalParams, IframeModalType, InputIframeModalParams, } from '@components/modal/iframe-modal'; export type FormIframeModalType = IframeModalType export type FormIframeCallbackFunction = ( form: HTMLFormElement, formData: FormData, dataAttributes: DOMStringMap | null, event: Event, ) => void; export type FormIframeConfirmCallback = ( form: HTMLFormElement, iframe: HTMLIFrameElement, event: Event ) => void; export type FormIframeModalParams = Omit & { formUrl: string; formSelector: string; cancelButtonSelector: string; modalTitle?: string; onFormLoaded?: FormIframeCallbackFunction, formConfirmCallback?: FormIframeConfirmCallback, } export type InputFormIframeModalParams = Partial & { formUrl: string; // formUrl is mandatory in params }; /** * This modal opens an url containing a form inside a modal and watches for the submit (via iframe loading) * On each load it is able to return data from the form via the onFormLoaded callback */ export class FormIframeModal extends IframeModal implements FormIframeModalType { constructor( params: InputFormIframeModalParams, ) { const iframeParams: InputIframeModalParams = { iframeUrl: params.formUrl, onLoaded: (iframe: HTMLIFrameElement, event: Event) => { this.onIframeLoaded( iframe, event, params.onFormLoaded, params.cancelButtonSelector ?? '.cancel-btn', params.formSelector ?? 'form', ); }, confirmCallback: (iframe: HTMLIFrameElement, event: Event) => { this.onConfirmCallback(iframe, event, params.formConfirmCallback, params.formSelector ?? 'form'); }, ...params, }; super(iframeParams); } private onIframeLoaded( iframe: HTMLIFrameElement, event: Event, onFormLoaded: FormIframeCallbackFunction | undefined, cancelButtonSelector: string, formSelector: string, ): void { if (!onFormLoaded) { return; } const iframeForm: HTMLFormElement | null = this.getForm(iframe, formSelector); if (!iframeForm) { return; } // Close modal when cancel button is clicked const cancelButtons = iframeForm.querySelectorAll(cancelButtonSelector); cancelButtons.forEach((cancelButton) => { cancelButton.addEventListener('click', () => { this.hide(); }); }); onFormLoaded(iframeForm, new FormData(iframeForm), iframeForm.dataset ?? null, event); } private onConfirmCallback( iframe: HTMLIFrameElement, event: Event, formConfirmCallback: FormIframeConfirmCallback | undefined, formSelector: string, ): void { if (!formConfirmCallback) { return; } const iframeForm: HTMLFormElement | null = this.getForm(iframe, formSelector); if (!iframeForm) { return; } formConfirmCallback(iframeForm, iframe, event); } private getForm(iframe: HTMLIFrameElement, formSelector: string): HTMLFormElement | null { if (!iframe.contentWindow) { return null; } return iframe.contentWindow.document.querySelector(formSelector); } }