1/** 2 * Newsletter forms. 3 * 4 * Binds by class rather than by a list of IDs, so a form added anywhere works 5 * without anyone remembering to come back here -- which is how the sidebar 6 * widget ended up submitting as a plain POST and reloading the page. 7 * 8 * Every outcome is said out loud: the old handler wrote a message on success 9 * and, on failure, un-hid an empty paragraph, so a mistyped address produced 10 * a blank space and no reason. 11 */ 12( function () { 13 'use strict'; 14 15 function config() { 16 var data = window.EasyMasterData || {}; 17 18 return { 19 ajaxUrl: data.ajaxUrl || '', 20 nonce: data.nonce || '' 21 }; 22 } 23 24 function setUp( form ) { 25 var message = form.querySelector( '.em-newsletter-msg' ); 26 var input = form.querySelector( 'input[name="email"]' ); 27 var button = form.querySelector( 'button[type="submit"]' ); 28 var trap = form.querySelector( 'input[name="em_website"]' ); 29 var fields = form.querySelector( '.em-newsletter-fields' ); 30 var source = form.querySelector( 'input[name="source"]' ); 31 var busy = false; 32 33 if ( ! message || ! input ) { 34 return; 35 } 36 37 var label = button ? button.textContent : ''; 38 39 function say( text, kind ) { 40 var failed = kind === 'error'; 41 42 message.textContent = text; 43 message.hidden = false; 44 message.classList.remove( 'is-error', 'is-success' ); 45 message.classList.add( failed ? 'is-error' : 'is-success' ); 46 47 // On success the form has done its job, so the confirmation takes 48 // the field's place rather than hanging below it -- nothing moves, 49 // and nothing is left sitting there inviting a second go. A 50 // refusal keeps the field: it is what has to be corrected. 51 if ( fields ) { 52 fields.hidden = ! failed; 53 } 54 } 55 56 function setBusy( state ) { 57 busy = state; 58 form.classList.toggle( 'is-busy', state ); 59 60 if ( button ) { 61 button.disabled = state; 62 button.textContent = state ? 'Subscribingâ¦' : label; 63 } 64 } 65 66 form.addEventListener( 'submit', function ( event ) { 67 event.preventDefault(); 68 69 if ( busy ) { 70 return; 71 } 72 73 var email = input.value.trim(); 74 var settings = config(); 75 76 if ( ! email ) { 77 say( 'Enter your email address first.', 'error' ); 78 input.focus(); 79 return; 80 } 81 82 // The browser's own check, before spending a request on it. 83 if ( input.checkValidity && ! input.checkValidity() ) { 84 say( 'That does not look like an email address.', 'error' ); 85 input.focus(); 86 return; 87 } 88 89 if ( ! settings.ajaxUrl ) { 90 say( 'The form is not available right now. Please try again later.', 'error' ); 91 return; 92 } 93 94 var body = new URLSearchParams(); 95 body.append( 'action', 'em_newsletter_subscribe' ); 96 body.append( 'nonce', settings.nonce ); 97 body.append( 'email', email ); 98 body.append( 'em_website', trap ? trap.value : '' ); 99 body.append( 'source', source ? source.value : '' ); 100 101 setBusy( true ); 102 103 fetch( settings.ajaxUrl, { 104 method: 'POST', 105 credentials: 'same-origin', 106 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 107 body: body.toString() 108 } ) 109 .then( function ( response ) { 110 // A rejection is still JSON; a nonce failure is the bare 111 // string "-1", which JSON.parse would throw on. 112 return response.text().then( function ( text ) { 113 try { 114 return { status: response.status, payload: JSON.parse( text ) }; 115 } catch ( e ) { 116 return { status: response.status, payload: null }; 117 } 118 } ); 119 } ) 120 .then( function ( result ) { 121 var payload = result.payload; 122 123 if ( payload && payload.success ) { 124 say( ( payload.data && payload.data.message ) || 'Subscribed!', 'success' ); 125 input.value = ''; 126 return; 127 } 128 129 if ( payload && payload.data && payload.data.message ) { 130 say( payload.data.message, 'error' ); 131 return; 132 } 133 134 say( 'That did not go through. Please reload the page and try again.', 'error' ); 135 } ) 136 .catch( function () { 137 say( 'Could not reach the server. Check your connection and try again.', 'error' ); 138 } ) 139 .then( function () { 140 setBusy( false ); 141 } ); 142 } ); 143 144 // Clear a refusal as soon as the reader starts fixing it. 145 input.addEventListener( 'input', function () { 146 if ( message.classList.contains( 'is-error' ) ) { 147 message.hidden = true; 148 message.textContent = ''; 149 message.classList.remove( 'is-error' ); 150 } 151 } ); 152 153 // Nothing to clear on success: the field is gone by then. 154 155 } 156 157 document.addEventListener( 'DOMContentLoaded', function () { 158 Array.prototype.forEach.call( document.querySelectorAll( '.em-newsletter-form' ), setUp ); 159 } ); 160}() );
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.