PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.3.3
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.3.3
3.3.3 3.3.2 3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 All 158 releases
← All changes | assets/public/js/nx-elementor-form.js +69 -7 3.2.8 → 3.3.3 View file →
@@ -7,8 +7,49 @@
7 7 */
8 8 ( function () {
9 9 'use strict';
10 10
11 + // ── Per-session submission guard ──────────────────────────────────────
12 + // A visitor may submit a given campaign's form only once per browser
13 + // session; the flag is stored in sessionStorage keyed by campaign id.
14 + function sessionStore() {
15 + try { return window.sessionStorage; } catch ( e ) { return null; }
16 + }
17 + function submittedKey( nxId ) {
18 + return 'notificationx_form_submitted_' + nxId;
19 + }
20 + function hasSubmitted( nxId ) {
21 + var store = sessionStore();
22 + try { return !! ( store && store.getItem( submittedKey( nxId ) ) ); }
23 + catch ( e ) { return false; }
24 + }
25 + function markSubmitted( nxId ) {
26 + var store = sessionStore();
27 + try { if ( store ) store.setItem( submittedKey( nxId ), '1' ); }
28 + catch ( e ) {}
29 + }
30 +
31 + // Disable the form's submit button and show an "already submitted" notice.
32 + function lockForm( form, btn, msgEl ) {
33 + if ( btn ) btn.disabled = true;
34 + if ( msgEl && ! msgEl.textContent ) {
35 + msgEl.classList.add( 'is-success' );
36 + msgEl.textContent = form.getAttribute( 'data-already' )
37 + || 'You have already submitted this form.';
38 + }
39 + }
40 +
41 + // If the form is rendered inside an Exit Intent popup, ask the popup to
42 + // close itself (handled in ExitIntentPopup.tsx) shortly after a success.
43 + function closeExitIntent( form, nxId ) {
44 + if ( ! form.closest || ! form.closest( '.nx-exit-intent-overlay' ) ) return;
45 + setTimeout( function () {
46 + document.dispatchEvent( new CustomEvent( 'nx:exit-intent-close', {
47 + detail: { nxId: nxId },
48 + } ) );
49 + }, 1600 );
50 + }
51 +
11 52 function init( form ) {
12 53 if ( ! form || form.__nxBound ) return;
13 54 form.__nxBound = true;
14 55
@@ -13,12 +54,24 @@
13 54 form.__nxBound = true;
14 55
15 56 var msgEl = form.querySelector( '.nx-form-message' );
16 57 var btn = form.querySelector( '.nx-form-submit' );
58 + var nxId = form.getAttribute( 'data-nx-id' );
17 59
60 + // Already submitted this session? Lock the form up-front.
61 + if ( nxId && hasSubmitted( nxId ) ) {
62 + lockForm( form, btn, msgEl );
63 + }
64 +
18 65 form.addEventListener( 'submit', function ( ev ) {
19 66 ev.preventDefault();
20 67
68 + // Guard against repeat submissions within the same session.
69 + if ( nxId && hasSubmitted( nxId ) ) {
70 + lockForm( form, btn, msgEl );
71 + return;
72 + }
73 +
21 74 if ( msgEl ) {
22 75 msgEl.textContent = '';
23 76 msgEl.classList.remove( 'is-success', 'is-error' );
24 77 }
@@ -28,10 +81,9 @@
28 81 form.reportValidity();
29 82 return;
30 83 }
31 84
32 - var nxId = form.getAttribute( 'data-nx-id' );
33 - var url = form.getAttribute( 'data-rest-url' );
85 + var url = form.getAttribute( 'data-rest-url' );
34 86 if ( ! nxId || ! url ) return;
35 87
36 88 var payload = {
37 89 nx_id: nxId,
@@ -68,14 +120,22 @@
68 120 return { ok: res.ok, body: {} };
69 121 } );
70 122 } )
71 123 .then( function ( result ) {
72 - if ( ! msgEl ) return;
73 124 if ( result.ok ) {
74 - msgEl.classList.add( 'is-success' );
75 - msgEl.textContent = form.getAttribute( 'data-success' ) || 'Submitted.';
125 + // Remember the submission for the rest of the session and
126 + // keep the form locked so it can't be sent again.
127 + markSubmitted( nxId );
128 + if ( btn ) btn.disabled = true;
129 + if ( msgEl ) {
130 + msgEl.classList.add( 'is-success' );
131 + msgEl.textContent = form.getAttribute( 'data-success' ) || 'Submitted.';
132 + }
76 133 form.reset();
77 - } else {
134 + // When the form lives inside an Exit Intent popup, dismiss it
135 + // after the success message has had a moment to register.
136 + closeExitIntent( form, nxId );
137 + } else if ( msgEl ) {
78 138 msgEl.classList.add( 'is-error' );
79 139 msgEl.textContent = ( result.body && result.body.message )
80 140 || form.getAttribute( 'data-error' )
81 141 || 'Something went wrong.';
@@ -86,9 +146,11 @@
86 146 msgEl.classList.add( 'is-error' );
87 147 msgEl.textContent = form.getAttribute( 'data-error' ) || 'Something went wrong.';
88 148 } )
89 149 .finally( function () {
90 - if ( btn ) btn.disabled = false;
150 + // Leave the button disabled once a submission has gone through;
151 + // only re-enable it after a failed attempt.
152 + if ( btn && ! ( nxId && hasSubmitted( nxId ) ) ) btn.disabled = false;
91 153 } );
92 154 } );
93 155 }
94 156