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 source = form.querySelector( 'input[name="source"]' ); 30 var busy = false; 31 32 if ( ! message || ! input ) { 33 return; 34 } 35 36 var label = button ? button.textContent : ''; 37 38 function say( text, kind ) { 39 message.textContent = text; 40 message.hidden = false; 41 message.classList.remove( 'is-error', 'is-success' ); 42 message.classList.add( kind === 'error' ? 'is-error' : 'is-success' ); 43 } 44 45 function setBusy( state ) { 46 busy = state; 47 form.classList.toggle( 'is-busy', state ); 48 49 if ( button ) { 50 button.disabled = state; 51 button.textContent = state ? 'Subscribingâ¦' : label; 52 } 53 } 54 55 form.addEventListener( 'submit', function ( event ) { 56 event.preventDefault(); 57 58 if ( busy ) { 59 return; 60 } 61 62 var email = input.value.trim(); 63 var settings = config(); 64 65 if ( ! email ) { 66 say( 'Enter your email address first.', 'error' ); 67 input.focus(); 68 return; 69 } 70 71 // The browser's own check, before spending a request on it. 72 if ( input.checkValidity && ! input.checkValidity() ) { 73 say( 'That does not look like an email address.', 'error' ); 74 input.focus(); 75 return; 76 } 77 78 if ( ! settings.ajaxUrl ) { 79 say( 'The form is not available right now. Please try again later.', 'error' ); 80 return; 81 } 82 83 var body = new URLSearchParams(); 84 body.append( 'action', 'em_newsletter_subscribe' ); 85 body.append( 'nonce', settings.nonce ); 86 body.append( 'email', email ); 87 body.append( 'em_website', trap ? trap.value : '' ); 88 body.append( 'source', source ? source.value : '' ); 89 90 setBusy( true ); 91 92 fetch( settings.ajaxUrl, { 93 method: 'POST', 94 credentials: 'same-origin', 95 headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, 96 body: body.toString() 97 } ) 98 .then( function ( response ) { 99 // A rejection is still JSON; a nonce failure is the bare 100 // string "-1", which JSON.parse would throw on. 101 return response.text().then( function ( text ) { 102 try { 103 return { status: response.status, payload: JSON.parse( text ) }; 104 } catch ( e ) { 105 return { status: response.status, payload: null }; 106 } 107 } ); 108 } ) 109 .then( function ( result ) { 110 var payload = result.payload; 111 112 if ( payload && payload.success ) { 113 say( ( payload.data && payload.data.message ) || 'Subscribed!', 'success' ); 114 input.value = ''; 115 return; 116 } 117 118 if ( payload && payload.data && payload.data.message ) { 119 say( payload.data.message, 'error' ); 120 return; 121 } 122 123 say( 'That did not go through. Please reload the page and try again.', 'error' ); 124 } ) 125 .catch( function () { 126 say( 'Could not reach the server. Check your connection and try again.', 'error' ); 127 } ) 128 .then( function () { 129 setBusy( false ); 130 } ); 131 } ); 132 133 // Clear a refusal as soon as the reader starts fixing it. 134 input.addEventListener( 'input', function () { 135 if ( message.classList.contains( 'is-error' ) ) { 136 message.hidden = true; 137 message.textContent = ''; 138 message.classList.remove( 'is-error' ); 139 } 140 } ); 141 } 142 143 document.addEventListener( 'DOMContentLoaded', function () { 144 Array.prototype.forEach.call( document.querySelectorAll( '.em-newsletter-form' ), setUp ); 145 } ); 146}() );
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.