HEX
Server: LiteSpeed
System: Linux server315.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: globfdxw (6114)
PHP: 8.1.34
Disabled: NONE
Upload Files
File: //home/globfdxw/www/wp-content/plugins/wpforms-google-calendar/assets/js/builder.js
/* global WPForms, wpf, wpforms_builder, WPFormsBuilder, Choices */

/**
 * WPForms Providers Builder Google Calendar module.
 *
 * @since 1.0.0
 *
 * @property {Object} wpforms_builder                                    WPForms Builder i18n strings.
 * @property {Object} wpforms_builder.google_calendar                    WPForms Google Calendar i18n strings.
 * @property {string} wpforms_builder.google_calendar.duration_options   List of duration options.
 * @property {string} wpforms_builder.google_calendar.recurrence_options List of recurrence options.
 */
WPForms.Admin.Builder.Providers.GoogleCalendar = WPForms.Admin.Builder.Providers.GoogleCalendar || ( function( document, window, $ ) {
	/**
	 * Public functions and properties.
	 *
	 * @since 1.0.0
	 *
	 * @type {Object}
	 */
	const app = {

		/**
		 * CSS selectors.
		 *
		 * @since 1.0.0
		 *
		 * @type {Object}
		 */
		selectors: {
			settingsPanel: '#wpforms-panel-settings',
			authButton: '.wpforms-google-sign-in-button-url',
			connection: '.wpforms-builder-provider-connection',
			accountField: '.js-wpforms-builder-google-calendar-provider-connection-account',
			accountFields: '.js-wpforms-builder-google-calendar-provider-account-fields',
			calendarFieldWrapper: '.js-wpforms-builder-google-calendar-provider-connection-calendar-wrapper',
			calendarField: '.js-wpforms-builder-google-calendar-provider-connection-calendar',
			calendarFieldDescription: '.js-wpforms-builder-google-calendar-provider-connection-calendar-description',
			calendarFieldDatetimePreview: '.js-wpforms-builder-google-calendar-provider-connection-calendar-datetime-preview',
			calendarFields: '.js-wpforms-builder-google-calendar-provider-calendar-fields',
			fieldWrapper: '.wpforms-builder-provider-connection-block',
			startDateTimeField: '.js-wpforms-builder-google-calendar-provider-connection-start-datetime',
			durationField: '.js-wpforms-builder-google-calendar-provider-connection-duration',
			endDateTimeField: '.js-wpforms-builder-google-calendar-provider-connection-end-datetime',
			endDateTimeFieldWrapper: '.js-wpforms-builder-google-calendar-provider-end-datetime',
			alert: '.wpforms-alert',
			alertContent: '.wpforms-alert-content',
			optionRow: '.wpforms-field-option-row',
			panelField: '.wpforms-panel-field',
			seeGuestField: '.js-wpforms-builder-google-calendar-provider-connection-see-guest-list',
			inviteOthersField: '.js-wpforms-builder-google-calendar-provider-connection-invite-others',
			modifyEventField: '.js-wpforms-builder-google-calendar-provider-connection-modify-event',
			dateFormatOption: '.wpforms-field-option-row-format select',
			choiceJS: '.choicesjs-select',
		},

		/**
		 * List of used classes.
		 *
		 * @since 1.0.0
		 */
		classes: {
			hide: 'wpforms-hidden',
			required: 'wpforms-required',
			disabled: 'wpforms-disabled',
			guestsField: 'js-wpforms-builder-google-calendar-provider-connection-guests',
			warningAlert: 'wpforms-alert-warning',
			errorAlert: 'wpforms-alert-danger',
		},

		/**
		 * jQuery elements.
		 *
		 * @since 1.0.0
		 *
		 * @type {Object}
		 */
		$elements: {
			$builder: $( '#wpforms-builder' ),
			$panel: $( '#google-calendar-provider' ),
			$connections: $( '#google-calendar-provider .wpforms-builder-provider-connections' ),
		},

		/**
		 * Current provider slug.
		 *
		 * @since 1.0.0
		 *
		 * @type {string}
		 */
		provider: 'google-calendar',

		/**
		 * This is a shortcut to the 'WPForms.Admin.Builder.Providers' object
		 * that handles the parent all-providers functionality.
		 *
		 * @since 1.0.0
		 *
		 * @type {Object}
		 */
		Providers: {},

		/**
		 * This is a shortcut to the 'WPForms.Admin.Builder.Templates' object
		 * that handles all the template management.
		 *
		 * @since 1.0.0
		 *
		 * @type {Object}
		 */
		Templates: {},

		/**
		 * This is a shortcut to the 'WPForms.Admin.Builder.Providers.cache' object
		 * that handles all the cache management.
		 *
		 * @since 1.0.0
		 *
		 * @type {Object}
		 */
		Cache: {},

		/**
		 * This is a flag for the ready state.
		 *
		 * @since 1.0.0
		 *
		 * @type {boolean}
		 */
		isReady: false,

		/**
		 * Start the engine.
		 *
		 * Run initialization on the Settings panel only.
		 *
		 * @since 1.0.0
		 */
		init() {
			// We are requesting/loading the Settings panel.
			if ( wpf.getQueryString( 'view' ) === 'settings' ) {
				$( app.selectors.settingsPanel ).on( 'WPForms.Admin.Builder.Providers.ready', app.ready );
			}

			// We have switched to the Settings panel.
			$( document ).on( 'wpformsPanelSwitched', function( event, panel ) {
				if ( panel === 'settings' ) {
					app.ready();
				}
			} );
		},

		/**
		 * Initialized once the DOM and Providers are fully loaded.
		 *
		 * @since 1.0.0
		 */
		ready() {
			if ( app.isReady ) {
				return;
			}

			app.Providers = WPForms.Admin.Builder.Providers;
			app.Templates = WPForms.Admin.Builder.Templates;
			app.Cache = app.Providers.cache;

			app.Templates.add( [
				'wpforms-google-calendar-builder-content-connection',
				'wpforms-google-calendar-builder-content-connection-calendar-field',
				'wpforms-google-calendar-builder-content-connection-conditionals',
			] );

			// Events registration.
			app.bindUIActions();
			app.bindTriggers();
			app.processInitial();

			// Save a flag for ready state.
			app.isReady = true;
		},

		/**
		 * Process various events as a response to UI interactions.
		 *
		 * @since 1.0.0
		 */
		bindUIActions() {
			app.$elements.$panel
				.on( 'connectionCreate', app.connection.create )
				.on( 'connectionDelete', app.connection.delete )
				.on( 'click', app.selectors.authButton, app.account.add )
				.on( 'change', app.selectors.accountField, app.ui.accountField.change )
				.on( 'change', app.selectors.calendarField, app.ui.calendarField.change )
				.on( 'change', app.selectors.durationField, app.ui.durationField.change )
				.on( 'change', app.selectors.startDateTimeField, app.ui.dateTimeFields.change )
				.on( 'change', app.selectors.endDateTimeField, app.ui.dateTimeFields.change )
				.on( 'change', app.selectors.modifyEventField, app.ui.modifyEventField.change );

			app.$elements.$builder
				.on( 'wpformsFieldSelectMapped', app.ui.guestsField.update )
				.on( 'change', app.selectors.dateFormatOption, app.ui.dateTimeFields.changeFormat );
		},

		/**
		 * Fire certain events on certain actions, specifically for related connections.
		 * These are not directly caused by user manipulations.
		 *
		 * @since 1.0.0
		 */
		bindTriggers() {
			app.$elements.$connections.on( 'connectionsDataLoaded', function( event, data ) {
				if ( _.isEmpty( data.connections ) ) {
					return;
				}

				for ( const connectionId in data.connections ) {
					app.connection.renderConnections( {
						connection: data.connections[ connectionId ],
						conditional: data.conditionals[ connectionId ],
					} );
				}
			} );

			app.$elements.$connections.on( 'connectionGenerated', function( event, data ) {
				const $connection = app.connection.getById( data.connection.id );

				if ( _.has( data.connection, 'isNew' ) && data.connection.isNew ) {
					app.connection.replaceIds( data.connection.id, $connection );

					return;
				}

				$( app.selectors.accountField, $connection ).trigger( 'change', [ $connection ] );
				$( app.selectors.startDateTimeField, $connection ).trigger( 'change', [ $connection ] );
				$( app.selectors.endDateTimeField, $connection ).trigger( 'change', [ $connection ] );
				$( app.selectors.modifyEventField, $connection ).trigger( 'change', [ $connection ] );
			} );
		},

		/**
		 * Compile template with data if any and display them on a page.
		 *
		 * @since 1.0.0
		 */
		processInitial() {
			const error = app.Templates.get( `wpforms-${ app.provider }-builder-content-connection-error` );

			app.$elements.$connections.prepend( error() );
			app.connection.dataLoad();
		},

		/**
		 * Connection property.
		 *
		 * @since 1.0.0
		 */
		connection: {

			/**
			 * Sometimes we might need to get a connection DOM element by its ID.
			 *
			 * @since 1.0.0
			 *
			 * @param {string} connectionId Connection ID to search for a DOM element by.
			 *
			 * @return {jQuery} jQuery object for connection.
			 */
			getById( connectionId ) {
				return app.$elements.$connections.find( '.wpforms-builder-provider-connection[data-connection_id="' + connectionId + '"]' );
			},

			/**
			 * Sometimes in DOM we might have placeholders or temporary connection IDs.
			 * We need to replace them with actual values.
			 *
			 * @since 1.0.0
			 *
			 * @param {string} connectionId New connection ID to replace to.
			 * @param {Object} $connection  jQuery DOM connection element.
			 */
			replaceIds( connectionId, $connection ) {
				// Replace the old temporary% connection_id% from PHP code with the new one.
				$connection.find( 'input, select, label' ).each( function() {
					const $this = $( this );

					if ( $this.attr( 'name' ) ) {
						$this.attr( 'name', $this.attr( 'name' ).replace( /%connection_id%/gi, connectionId ) );
					}

					if ( $this.attr( 'id' ) ) {
						$this.attr( 'id', $this.attr( 'id' ).replace( /%connection_id%/gi, connectionId ) );
					}

					if ( $this.attr( 'for' ) ) {
						$this.attr( 'for', $this.attr( 'for' ).replace( /%connection_id%/gi, connectionId ) );
					}

					if ( $this.attr( 'data-name' ) ) {
						$this.attr( 'data-name', $this.attr( 'data-name' ).replace( /%connection_id%/gi, connectionId ) );
					}
				} );
			},

			/**
			 * Create a connection using the user-entered name.
			 *
			 * @since 1.0.0
			 *
			 * @param {Object} event Event object.
			 * @param {string} name  Connection name.
			 */
			create( event, name ) {
				const connectionId = new Date().getTime().toString( 16 ),
					connection = {
						id: connectionId,
						name,
						isNew: true,
					};

				app.Cache.addTo( app.provider, 'connections', connectionId, connection );

				app.connection.renderConnections( {
					connection,
				} );
			},

			/**
			 * Connection is deleted - delete a cache as well.
			 *
			 * @since 1.0.0
			 *
			 * @param {Object} event       Event object.
			 * @param {Object} $connection jQuery DOM element for a connection.
			 */
			delete( event, $connection ) {
				const $eHolder = app.Providers.getProviderHolder( app.provider );

				if ( ! $connection.closest( $eHolder ).length ) {
					return;
				}

				const connectionId = $connection.data( 'connection_id' );

				if ( _.isString( connectionId ) ) {
					app.Cache.deleteFrom( app.provider, 'connections', connectionId );
				}

				app.$elements.$connections.trigger( 'connectionDeleted' );
			},

			/**
			 * Render connections.
			 *
			 * @since 1.0.0
			 *
			 * @param {Object} data Connection data.
			 */
			renderConnections( data ) {
				const accounts = app.Cache.get( app.provider, 'accounts' );

				if ( ! app.account.isExists( data.connection.account_id, accounts ) ) {
					return;
				}

				const tmplConnection = app.Templates.get( `wpforms-${ app.provider }-builder-content-connection` );
				const tmplConditional = $( `#tmpl-wpforms-${ app.provider }-builder-content-connection-conditionals` ).length ? app.Templates.get( `wpforms-${ app.provider }-builder-content-connection-conditionals` ) : app.Templates.get( 'wpforms-providers-builder-content-connection-conditionals' );
				const conditional = _.has( data.connection, 'isNew' ) && data.connection.isNew ? tmplConditional() : data.conditional;
				const emailFields = wpf.getFields( [ 'email' ], true, true );
				const dateTimeFields = wpf.getFields( [ 'date-time' ], true );

				app.$elements.$connections
					.prepend(
						tmplConnection( {
							durationOptions: wpforms_builder.google_calendar.duration_options,
							recurrenceOptions: wpforms_builder.google_calendar.recurrence_options,
							emailFields,
							dateTimeFields,
							accounts,
							connection: data.connection,
							conditional,
							provider: app.provider,
						} ) );

				// When we added a new connection with its accounts - trigger next steps.
				app.$elements.$connections.trigger( 'connectionGenerated', [ data ] );

				app.ui.initChoicesJS( app.connection.getById( data.connection.id ) );

				app.$elements.$connections.trigger( 'connectionRendered', [ app.provider, data.connection.id ] );
			},

			/**
			 * Fire AJAX-request to retrieve the list of all saved connections.
			 *
			 * @since 1.0.0
			 */
			dataLoad() {
				app
					.Providers.ajax
					.request( app.provider, {
						data: {
							task: 'connections_get',
						},
					} )
					.done( function( response ) {
						if (
							! response.success ||
							! _.has( response.data, 'connections' )
						) {
							return;
						}

						app.connection.updateCache( response.data );

						app.$elements.$connections.trigger( 'connectionsDataLoaded', [ response.data ] );
					} );
			},

			/**
			 * Set cache data after AJAX requests.
			 *
			 * @since 1.0.0
			 *
			 * @param {Object} data Response data.
			 */
			updateCache( data ) {
				[
					'connections',
					'calendars',
					'conditionals',
					'accounts',
				].forEach( ( dataType ) => {
					app.Cache.set( app.provider, dataType, jQuery.extend( {}, data[ dataType ] ) );
				} );
			},
		},

		/**
		 * Account property.
		 *
		 * @since 1.0.0
		 */
		account: {

			/**
			 * Check if a provided account is listed inside an account list.
			 *
			 * @since 1.0.0
			 *
			 * @param {string} accountId Connection account ID to check.
			 * @param {Object} accounts  Array of objects, usually received from API.
			 *
			 * @return {boolean} True if an account exists.
			 */
			isExists( accountId, accounts ) {
				if ( _.isEmpty( accounts ) ) {
					return false;
				}

				// New connections that have not been saved don't have the account ID yet.
				if ( _.isEmpty( accountId ) ) {
					return true;
				}

				return _.has( accounts, accountId );
			},

			/**
			 * Redirect the customer to the Google Calendar authorization consent screen.
			 *
			 * @since 1.0.0
			 *
			 * @param {Event} e Event.
			 */
			add( e ) {
				if ( WPFormsBuilder.formIsSaved() ) {
					return;
				}

				e.preventDefault();

				// eslint-disable-next-line camelcase
				wpforms_builder.exit_url = $( this ).attr( 'href' );

				WPFormsBuilder.formSave( true );
			},
		},

		/**
		 * All methods that modify the UI of a page.
		 *
		 * @since 1.0.0
		 */
		ui: {

			/**
			 * Account field methods.
			 *
			 * @since 1.0.0
			 */
			accountField: {
				/**
				 * Callback-function on change event.
				 *
				 * @since 1.0.0
				 */
				change() {
					const $this = $( this );
					const accountId = $this.val();
					const $connection = $this.closest( app.selectors.connection );
					const $accountFields = $( app.selectors.accountFields, $connection );
					const connectionId = $connection.data( 'connection_id' );
					const connection = app.Cache.getById( app.provider, 'connections', connectionId );

					// eslint-disable-next-line camelcase
					connection.account_id = accountId;

					$accountFields.toggleClass( app.classes.hide, accountId === '' );

					app.ui.calendarField.render( connection );
				},
			},

			/**
			 * Calendar field methods.
			 *
			 * @since 1.0.0
			 */
			calendarField: {
				/**
				 * Render HTML template.
				 *
				 * @since 1.0.0
				 *
				 * @param {Object} connection Connection data.
				 */
				render( connection ) {
					const calendars = connection.account_id ? app.Cache.getById( app.provider, 'calendars', connection.account_id ) : {};
					const tmpl = app.Templates.get( `wpforms-${ app.provider }-builder-content-connection-calendar-field` );
					const $connection = app.connection.getById( connection.id );
					const $calendarFieldWrapper = $( app.selectors.calendarFieldWrapper, $connection );

					$calendarFieldWrapper.html(
						tmpl( {
							calendars,
							connection,
							provider: app.provider,
						} )
					);

					const $calendarField = $( app.selectors.calendarField, $connection );

					$calendarField.trigger( 'change' );
				},

				/**
				 * Callback-function on change event.
				 *
				 * @since 1.0.0
				 */
				change() {
					const $this = $( this );
					const $connection = $this.closest( app.selectors.connection );
					const $calendarFields = $( app.selectors.calendarFields, $connection );
					const $calendarFieldDescription = $( app.selectors.calendarFieldDescription, $connection );
					const isEmpty = $this.val() === '' || $this.val() === null;

					$calendarFields.toggleClass( app.classes.hide, isEmpty );
					$calendarFieldDescription.toggleClass( app.classes.hide, isEmpty );

					if ( ! isEmpty ) {
						app.ui.calendarField.updateDatetimePreview( $this );
					}
				},

				/**
				 * Update datetime preview.
				 *
				 * @since 1.0.0
				 *
				 * @param {jQuery} $el Element.
				 */
				updateDatetimePreview( $el ) {
					const $connection = $el.closest( app.selectors.connection );
					const $calendarFieldDatetimePreview = $( app.selectors.calendarFieldDatetimePreview, $connection );
					const timeZone = $el.find( 'option:selected' ).data( 'timezone' );
					const now = new Date();
					const timeString = now.toLocaleString( 'en', { timeZone, dateStyle: 'short', timeStyle: 'short' } );

					$calendarFieldDatetimePreview.html( timeString );
				},
			},

			/**
			 * Guests field methods.
			 *
			 * @since 1.0.0
			 */
			guestsField: {
				/**
				 * Update value for choiceJS field.
				 *
				 * @since 1.0.0
				 *
				 * @param {Event}  e       Event.
				 * @param {jQuery} $select Select field.
				 */
				update( e, $select ) {
					if ( ! $select.hasClass( app.classes.guestsField ) ) {
						return;
					}

					let choicesObj = $select.data( 'choicesjs' );

					if ( ! choicesObj ) {
						return;
					}

					const choices = app.ui.guestsField.getSelectFieldChoices( $select );
					const currentValues = choicesObj.getValue( true ).filter( ( value ) =>
						choices.some( ( choice ) => choice.value === value )
					);

					// Workaround to display a placeholder when no activate values.
					if ( currentValues.length === 0 ) {
						choicesObj.destroy();
						$select.removeData( 'choicesjs' );
						app.ui.initChoicesJS( $select.closest( app.selectors.connection ) );
						choicesObj = $select.data( 'choicesjs' );
					}

					// noinspection JSVoidFunctionReturnValueUsed
					choicesObj
						.clearChoices( true, true )
						.removeActiveItems()
						.setChoices( choices, 'value', 'label', true )
						.setChoiceByValue( currentValues );
				},

				/**
				 * Get select field options and convert them to an array for ChoiceJS choices format.
				 *
				 * @since 1.0.0
				 *
				 * @param {jQuery} $select Select field.
				 *
				 * @return {Array} Choices.
				 */
				getSelectFieldChoices( $select ) {
					const choices = [];

					$select.find( 'option' ).each( function() {
						const $option = $( this );
						const value = $option.val();

						if ( value === '' ) {
							return;
						}

						choices.push(
							{ value, label: $option.text() }
						);
					} );

					return choices;
				},
			},

			/**
			 * Duration field methods.
			 *
			 * @since 1.0.0
			 */
			durationField: {

				/**
				 * Change field event.
				 *
				 * @since 1.0.0
				 */
				change() {
					const val = $( this ).val();
					const $connection = $( this ).closest( app.selectors.connection );
					const $endDateTimeFieldWrapper = $( app.selectors.endDateTimeFieldWrapper, $connection );
					const $endDateTimeField = $( app.selectors.endDateTimeField, $connection );
					const isUserDefined = val === 'user_defined';

					$endDateTimeFieldWrapper.toggleClass( app.classes.hide, ! isUserDefined );
					$endDateTimeField.toggleClass( app.classes.required, isUserDefined );
				},
			},

			/**
			 * Start/End Date/Time fields methods.
			 *
			 * @since 1.0.0
			 */
			dateTimeFields: {

				/**
				 * Trigger Start/End Date/Time fields when a Date field format is changed.
				 *
				 * @since 1.0.0
				 */
				changeFormat() {
					const fieldId = +$( this ).closest( app.selectors.optionRow ).data( 'field-id' );

					$( `${ app.selectors.startDateTimeField }, ${ app.selectors.endDateTimeField }` ).each( function() {
						const $this = $( this );

						if ( +$this.val() === fieldId ) {
							$this.trigger( 'change' );
						}
					} );
				},

				/**
				 * Change Start/End Date/Time fields.
				 */
				change() {
					const $field = $( this );
					const fieldId = $field.val();
					const $fieldWrapper = $field.closest( app.selectors.fieldWrapper );
					const fieldFormat = $( `#wpforms-field-option-${ fieldId }-format` ).val();
					const $alert = $fieldWrapper.find( app.selectors.alert );
					const $alertContent = $alert.find( app.selectors.alertContent );

					$alert.removeClass( app.classes.warningAlert );
					$alert.removeClass( app.classes.errorAlert );

					if ( fieldId === '' || fieldFormat === 'date-time' ) {
						$alert.addClass( app.classes.hide );
						$alertContent.text( '' );

						return;
					}

					if ( fieldFormat === 'date' ) {
						$alert.addClass( app.classes.warningAlert );
						$alertContent.text( wpforms_builder.google_calendar.date_format_warning );

						$alert.removeClass( app.classes.hide );

						return;
					}

					if ( fieldFormat === 'time' ) {
						$alert.addClass( app.classes.errorAlert );
						$alertContent.text( wpforms_builder.google_calendar.time_format_error );

						$alert.removeClass( app.classes.hide );
					}
				},
			},

			/**
			 * Modify Event field methods.
			 */
			modifyEventField: {

				/**
				 * Change field event.
				 *
				 * @since 1.0.0
				 */
				change() {
					const $this = $( this );
					const $connection = $this.closest( app.selectors.connection );
					const $dependedFields = $( `${ app.selectors.seeGuestField }, ${ app.selectors.inviteOthersField }`, $connection );
					const isChecked = $this.is( ':checked' );

					$dependedFields.closest( app.selectors.panelField ).toggleClass( app.classes.disabled, isChecked );

					if ( isChecked ) {
						$dependedFields.prop( 'checked', isChecked );
					}
				},
			},

			/**
			 * Initialize Choices.js library.
			 *
			 * @since 1.0.0
			 *
			 * @param {Object} $connection jQuery connection selector.
			 */
			initChoicesJS( $connection ) {
				// Load if the function exists.
				if ( typeof window.Choices !== 'function' ) {
					return;
				}

				const $choices = $( app.selectors.choiceJS, $connection );

				$choices.each( function( index, element ) {
					const $this = $( element );

					if ( 'undefined' !== typeof $this.data( 'choicesjs' ) ) {
						return;
					}

					$this.data( 'choicesjs', new Choices( $this[ 0 ], {
						shouldSort: false,
						removeItemButton: true,
						fuseOptions:{
							threshold: 0.1,
							distance: 1000,
						},
						callbackOnInit() {
							wpf.initMultipleSelectWithSearch( this );
							wpf.showMoreButtonForChoices( this.containerOuter.element );
						},
					} ) );
				} );
			},
		},
	};

	// Provide access to public functions/properties.
	return app;
}( document, window, jQuery ) );

// Initialize.
WPForms.Admin.Builder.Providers.GoogleCalendar.init();