1/** 2 * WP-Polls front end. 3 * 4 * Nothing here is exported. Poll markup asks for behaviour through 5 * data-poll-action / data-poll-id attributes, which are picked up by the 6 * delegated listener at the bottom of this file. 7 */ 8( function() { 9 'use strict'; 10 11 const l10n = window.wpPollsL10n || {}; 12 13 // Matches the fade duration used before. 14 const FADE_DURATION = 400; 15 16 /** 17 * Whether the visitor has asked for less movement. 18 * 19 * The fade is an inline transition, which a stylesheet media query cannot 20 * reach. Read on every call, since the setting can change while open. 21 * 22 * @return {boolean} True when motion should be skipped. 23 */ 24 function prefersReducedMotion() { 25 return ( 26 typeof window.matchMedia === 'function' && 27 window.matchMedia( '(prefers-reduced-motion: reduce)' ).matches 28 ); 29 } 30 31 // The Poll Container For A Given Poll 32 function pollContainer( currentPollId ) { 33 return document.getElementById( 'polls-' + currentPollId ); 34 } 35 36 // Show Or Hide The Loading Indicator 37 // The indicator is hidden by a stylesheet rule, so it needs an explicit 38 // display value rather than just clearing the inline one. 39 function setLoading( currentPollId, visible ) { 40 const loading = document.getElementById( 41 'polls-' + currentPollId + '-loading', 42 ); 43 if ( loading ) { 44 loading.style.display = visible ? 'block' : 'none'; 45 } 46 } 47 48 // Fade An Element To The Given Opacity 49 function fadeTo( element, opacity ) { 50 if ( ! element ) { 51 return; 52 } 53 54 // Straight to the end state when motion is unwelcome: the poll still 55 // dims, it just does not travel there. 56 element.style.transition = prefersReducedMotion() 57 ? '' 58 : 'opacity ' + FADE_DURATION + 'ms'; 59 element.style.opacity = opacity; 60 } 61 62 // Make Sure A Poll Is Fully Visible 63 // Only clears opacity, never animates to it: starting at zero would leave 64 // the poll invisible in a background tab, where animations freeze. 65 function show( element ) { 66 if ( element ) { 67 element.style.transition = ''; 68 element.style.opacity = ''; 69 } 70 } 71 72 // When User Vote For Poll 73 function pollVote( currentPollId ) { 74 const form = document.getElementById( 'polls_form_' + currentPollId ); 75 if ( ! form ) { 76 return; 77 } 78 79 const multipleField = document.getElementById( 80 'poll_multiple_ans_' + currentPollId, 81 ); 82 const pollMultipleAns = multipleField 83 ? parseInt( multipleField.value, 10 ) 84 : 0; 85 86 const selected = []; 87 const choices = form.querySelectorAll( 88 'input[type="checkbox"], input[type="radio"], option', 89 ); 90 Array.prototype.forEach.call( choices, function( choice ) { 91 // Inputs expose 'checked', options expose 'selected'. 92 if ( choice.checked || choice.selected ) { 93 selected.push( choice.value ); 94 } 95 } ); 96 97 if ( pollMultipleAns > 0 ) { 98 if ( selected.length === 0 ) { 99 alert( l10n.text_valid ); 100 } else if ( selected.length > pollMultipleAns ) { 101 alert( l10n.text_multiple + ' ' + pollMultipleAns ); 102 } else { 103 pollProcess( currentPollId, selected.join( ',' ) ); 104 } 105 return; 106 } 107 108 const pollAnswerId = selected.length 109 ? parseInt( selected[ selected.length - 1 ], 10 ) 110 : 0; 111 if ( pollAnswerId > 0 ) { 112 pollProcess( currentPollId, pollAnswerId ); 113 } else { 114 alert( l10n.text_valid ); 115 } 116 } 117 118 // Send A Poll Request And Swap In The Markup That Comes Back 119 function pollRequest( currentPollId, view, extraFields ) { 120 const nonceField = document.getElementById( 121 'poll_' + currentPollId + '_nonce', 122 ); 123 124 const body = new URLSearchParams(); 125 body.append( 'action', 'polls' ); 126 body.append( 'view', view ); 127 body.append( 'poll_id', currentPollId ); 128 body.append( 129 'poll_' + currentPollId + '_nonce', 130 nonceField ? nonceField.value : '', 131 ); 132 if ( extraFields ) { 133 Object.keys( extraFields ).forEach( function( name ) { 134 body.append( name, extraFields[ name ] ); 135 } ); 136 } 137 138 fadeTo( pollContainer( currentPollId ), 0 ); 139 setLoading( currentPollId, true ); 140 141 fetch( l10n.ajax_url, { 142 method: 'POST', 143 credentials: 'include', 144 cache: 'no-cache', 145 body, 146 } ) 147 .then( function( response ) { 148 return response.text(); 149 } ) 150 .then( function( data ) { 151 pollProcessSuccess( currentPollId, data ); 152 } ) 153 .catch( function() { 154 // Leave the poll readable rather than stuck faded out behind a spinner.
155 setLoading( currentPollId, false ); 156 show( pollContainer( currentPollId ) ); 157 } ); 158 } 159 160 // Process Poll (User Click "Vote" Button) 161 function pollProcess( currentPollId, pollAnswerId ) { 162 const fields = {}; 163 fields[ 'poll_' + currentPollId ] = pollAnswerId; 164 pollRequest( currentPollId, 'process', fields ); 165 } 166 167 // Poll's Result (User Click "View Results" Link) 168 function pollResult( currentPollId ) { 169 pollRequest( currentPollId, 'result' ); 170 } 171 172 // Poll's Voting Booth (User Click "Vote" Link) 173 function pollBooth( currentPollId ) { 174 pollRequest( currentPollId, 'booth' ); 175 } 176 177 // Poll Process Successfully 178 function pollProcessSuccess( currentPollId, data ) { 179 const container = pollContainer( currentPollId ); 180 if ( container ) { 181 const parsed = document.createElement( 'div' ); 182 parsed.innerHTML = data; 183 container.replaceWith.apply( 184 container, 185 Array.prototype.slice.call( parsed.childNodes ), 186 ); 187 } 188 189 setLoading( currentPollId, false ); 190 191 // The old poll was faded out and has now been thrown away, so all that is 192 // left to do is make sure the markup that replaced it is visible. 193 show( pollContainer( currentPollId ) ); 194 } 195 196 // On Click Events 197 document.addEventListener( 'click', function( event ) { 198 const target = event.target; 199 if ( ! target || typeof target.closest !== 'function' ) { 200 return; 201 } 202 203 const trigger = target.closest( '[data-poll-action]' ); 204 if ( ! trigger ) { 205 return; 206 } 207 208 const pollId = trigger.getAttribute( 'data-poll-id' ); 209 210 // The result and booth templates use anchors, so stop the browser 211 // from following the placeholder href while the request runs. 212 if ( trigger.tagName === 'A' ) { 213 event.preventDefault(); 214 } 215 216 switch ( trigger.getAttribute( 'data-poll-action' ) ) { 217 case 'vote': 218 pollVote( pollId ); 219 break; 220 case 'result': 221 pollResult( pollId ); 222 break; 223 case 'booth': 224 pollBooth( pollId ); 225 break; 226 } 227 } ); 228}() );
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.