PageSourceSearch

https://www.gedenkstaette-porta.de/wp-content/plugins/double-opt-i…/assets/doi-error-notification.js?ver=3.7.2

js gedenkstaette-porta.de collected 2026-10-02 08:07:29 UTC 8,063 bytes, 247 lines download raw bytes

1/**
2 * Double Opt-In — Universal Error Notification
3 *
4 * Listens for form submission events from any supported form plugin
5 * and checks the server-side AJAX endpoint for OptIn creation errors.
6 * Displays a toast notification if an error is found.
7 *
8 * @since 4.2.0
9 */
10(function () {
11	'use strict';
12
13	if ( typeof doiErrorNotification === 'undefined' ) {
14		return;
15	}
16
17	var config   = doiErrorNotification;
18	var checking = false;
19	var cooldown = false;
20
21	/**
22	 * Check the AJAX endpoint for a stored submission error.
23	 */
24	function checkForError() {
25		if ( checking || cooldown ) {
26			return;
27		}
28		checking = true;
29
30		var xhr = new XMLHttpRequest();
31		xhr._doiInternal = true; // Prevent the XHR interceptor from re-triggering scheduleCheck
32		xhr.open( 'POST', config.ajaxUrl, true );
33		xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
34
35		xhr.onreadystatechange = function () {
36			if ( xhr.readyState !== 4 ) {
37				return;
38			}
39			checking = false;
40
41			if ( xhr.status !== 200 ) {
42				return;
43			}
44
45			try {
46				var response = JSON.parse( xhr.responseText );
47			} catch ( e ) {
48				return;
49			}
50
51			if ( response.success && response.data && response.data.error ) {
52				// Hide form confirmation messages when validation error should be visible
53				if ( response.data.error.hide_confirmation ) {
54					hideFormConfirmations();
55				}
56
57				// Redirect to error page if configured, otherwise show toast
58				if ( response.data.redirect_url ) {
59					window.location.href = response.data.redirect_url;
60					return;
61				}
62
63				showNotification( response.data.error.message );
64
65				// Prevent duplicate checks for 5 seconds
66				cooldown = true;
67				setTimeout( function () {
68					cooldown = false;
69				}, 5000 );
70			}
71		};
72
73		xhr.send(
74			'action=doi_check_submission_error&nonce=' + encodeURIComponent( config.nonce )
75		);
76	}
77
78	/**
79	 * Schedule an error check with a short delay to ensure
80	 * the server-side form processing has completed.
81	 */
82	function scheduleCheck() {
83		setTimeout( checkForError, 800 );
84	}
85
86	/**
87	 * Hide form plugin confirmation/success messages.
88	 *
89	 * Called when a validation error should be visible (block/redirect mode)
90	 * so the user does not see a contradictory success message.
91	 */
92	function hideFormConfirmations() {
93		// WPForms confirmation containers
94		var wpfSelectors = '.wpforms-confirmation-container-full, .wpforms-confirmation-container';
95		document.querySelectorAll( wpfSelectors ).forEach( function ( el ) {
96			el.style.display = 'none';
97		} );
98
99		// Gravity Forms confirmation wrapper
100		document.querySelectorAll( '.gform_confirmation_wrapper' ).forEach( function ( el ) {
101			el.style.display = 'none';
102		} );
103
104		// CF7 success response (only hide the success state, not error state)
105		document.querySelectorAll( '.wpcf7-response-output.wpcf7-mail-sent-ok' ).forEach( function ( el ) {
106			el.style.display = 'none';
107		} );
108
109		// Elementor Forms success message
110		document.querySelectorAll( '.elementor-message.elementor-message-success' ).forEach( function ( el ) {
111			el.style.display = 'none';
112		} );
113	}
114
115	/**
116	 * Show a toast notification with the error message.
117	 *
118	 * @param {string} message The error message to display.
119	 */
120	function showNotification( message ) {
121		var existing = document.querySelector( '.doi-error-notification' );
122		if ( existing ) {
123			existing.remove();
124		}
125
126		var notification = document.createElement( 'div' );
127		notification.className = 'doi-error-notification';
128		notification.setAttribute( 'role', 'alert' );
129
130		var content = document.createElement( 'div' );
131		content.className = 'doi-error-notification__content';
132
133		var icon = document.createElement( 'span' );
134		icon.className = 'doi-error-notification__icon';
135		icon.innerHTML = '⚠';
136
137		var text = document.createElement( 'p' );
138		text.className = 'doi-error-notification__message';
139		text.textContent = message;
140
141		var closeBtn = document.createElement( 'button' );
142		closeBtn.className = 'doi-error-notification__close';
143		closeBtn.setAttribute( 'type', 'button' );
144		closeBtn.innerHTML = '×';
145		closeBtn.addEventListener( 'click', function () {
146			dismiss( notification );
147		} );
148
149		content.appendChild( icon );
150		content.appendChild( text );
151		content.appendChild( closeBtn );
152		notification.appendChild( content );
153		document.body.appendChild( notification );
154
155		// Trigger enter animation
156		requestAnimationFrame( function () {
157			notification.classList.add( 'doi-error-notification--visible' );
158		} );
159
160		// Auto-dismiss after 10 seconds
161		setTimeout( function () {
162			dismiss( notification );
163		}, 10000 );
164	}
165
166	/**
167	 * Dismiss a notification with exit animation.
168	 *
169	 * @param {HTMLElement} el The notification element.
170	 */
171	function dismiss( el ) {
172		if ( ! el || ! el.parentNode ) {
173			return;
174		}
175		el.classList.remove( 'doi-error-notification--visible' );
176		el.classList.add( 'doi-error-notification--exit' );
177		setTimeout( function () {
178			if ( el.parentNode ) {
179				el.parentNode.removeChild( el );
180			}
181		}, 300 );
182	}
183
184	// -------------------------------------------------------------------------
185	// Form plugin event listeners
186	// -------------------------------------------------------------------------
187
188	// Contact Form 7 (native DOM events)
189	document.addEventListener( 'wpcf7mailsent', scheduleCheck );
190	document.addEventListener( 'wpcf7invalid', scheduleCheck );
191	document.addEventListener( 'wpcf7spam', scheduleCheck );
192	document.addEventListener( 'wpcf7mailfailed', scheduleCheck );
193
194	// WPForms + Gravity Forms (jQuery events — not caught by native addEventListener)
195	if ( typeof jQuery !== 'undefined' ) {
196		jQuery( document ).on( 'wpformsAjaxSubmitSuccess', scheduleCheck );
197		jQuery( document ).on( 'wpformsAjaxSubmitError', scheduleCheck );
198		jQuery( document ).on( 'gform_confirmation_loaded', scheduleCheck );
199	}
200
201	// -------------------------------------------------------------------------
202	// Universal: catch ANY form submission on the page (capture phase)
203	// This is the most reliable way to detect form submissions regardless
204	// of which form plugin is used. It covers AJAX, standard, and custom flows.
205	// -------------------------------------------------------------------------
206	document.addEventListener( 'submit', function () {
207		// Use a longer delay for standard (non-AJAX) submissions
208		// because the server needs time to process the request.
209		setTimeout( checkForError, 1500 );
210	}, true );
211
212	// -------------------------------------------------------------------------
213	// Generic AJAX interception
214	// Catches all AJAX calls to detect form submissions from plugins
215	// that don't fire specific events (e.g., Avada, Elementor).
216	// -------------------------------------------------------------------------
217
218	// Intercept fetch()
219	if ( typeof window.fetch === 'function' ) {
220		var originalFetch = window.fetch;
221		window.fetch = function () {
222			// Capture URL before the async call — `arguments` inside .then()
223			// refers to the callback's own arguments, not the fetch arguments.
224			var fetchUrl = ( typeof arguments[0] === 'string' )
225				? arguments[0]
226				: ( arguments[0] && arguments[0].url ) || '';
227
228			return originalFetch.apply( this, arguments ).then( function ( response ) {
229				if ( fetchUrl && fetchUrl.indexOf( 'admin-ajax.php' ) !== -1 ) {
230					scheduleCheck();
231				}
232				return response;
233			} );
234		};
235	}
236
237	// Intercept XMLHttpRequest for jQuery.ajax based form plugins
238	var origOpen = XMLHttpRequest.prototype.open;
239	XMLHttpRequest.prototype.open = function ( method, url ) {
240		// Skip our own internal error-check requests to prevent infinite polling loops
241		if ( typeof url === 'string' && url.indexOf( 'admin-ajax.php' ) !== -1 && ! this._doiInternal ) {
242			this.addEventListener( 'load', scheduleCheck );
243		}
244		return origOpen.apply( this, arguments );
245	};
246
247})();

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.