1/** 2 * WP-PostRatings front end: posts the vote and swaps in the result. 3 * 4 * Hover and fill are CSS, so nothing here runs on mouse move. One delegated 5 * listener on document covers ratings added after load. 6 */ 7( function() { 8 'use strict'; 9 10 const l10n = window.wpPostRatingsL10n || {}; 11 12 /** Posts currently mid-vote, so a second click cannot double-submit. */ 13 const inFlight = new Set(); 14 15 /** 16 * Post a vote and replace the control with whatever comes back. 17 * 18 * @param {Element} control The fieldset or button group that was used. 19 * @param {number} rating Value chosen. 20 * @return {void} 21 */ 22 function vote( control, rating ) { 23 const postId = Number( control.dataset.postId ); 24 25 if ( ! postId || ! rating ) { 26 return; 27 } 28 29 if ( inFlight.has( postId ) ) { 30 // eslint-disable-next-line no-alert -- Long-standing behaviour: warns rather than queueing a second vote. 31 window.alert( l10n.textWait ); 32 return; 33 } 34 35 const container = document.getElementById( 'wp-postratings-' + postId ); 36 37 if ( ! container ) { 38 return; 39 } 40 41 const nonce = container.dataset.nonce || container.getAttribute( 'data-nonce' ); 42 43 inFlight.add( postId ); 44 45 // aria-busy, not an opacity tween: it dims through CSS and tells 46 // assistive technology the region is updating. 47 container.setAttribute( 'aria-busy', 'true' ); 48 49 const body = new URLSearchParams(); 50 51 body.append( 'action', 'wp_postratings' ); 52 body.append( 'pid', postId ); 53 body.append( 'rate', rating ); 54 body.append( 'wp_postratings_' + postId + '_nonce', nonce ); 55 56 /** 57 * Put the control back into a usable state. 58 * 59 * @param {string} [html] Replacement markup. 60 */ 61 function finish( html ) { 62 if ( 'string' === typeof html ) { 63 container.innerHTML = html; 64 } 65 66 container.removeAttribute( 'aria-busy' ); 67 inFlight.delete( postId ); 68 } 69 70 window 71 .fetch( l10n.ajaxUrl, { 72 method: 'POST', 73 credentials: 'same-origin', 74 headers: { 75 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 76 }, 77 body: body.toString(), 78 } ) 79 .then( function( response ) { 80 return response.text(); 81 } ) 82 .then( finish ) 83 .catch( function() { 84 finish(); 85 } ); 86 } 87 88 /** 89 * Attach the delegated listeners. 90 * 91 * @return {void} 92 */ 93 function start() { 94 // "change" covers click and arrow-key alike, so the scale is keyboard 95 // usable with no extra handling. 96 document.addEventListener( 'change', function( event ) { 97 const input = event.target.closest( '.wp-postratings-scale input[type="radio"]' ); 98 99 if ( ! input ) { 100 return; 101 } 102 103 const control = input.closest( '.wp-postratings-vote' ); 104 105 if ( control ) { 106 vote( control, Number( input.value ) ); 107 } 108 } ); 109 110 // An up/down pair is two buttons, not a scale. 111 document.addEventListener( 'click', function( event ) { 112 const button = event.target.closest( '.wp-postratings-updown button' ); 113 114 if ( ! button ) { 115 return; 116 } 117 118 event.preventDefault(); 119 120 const control = button.closest( '.wp-postratings-vote' ); 121 122 if ( control ) { 123 vote( control, Number( button.dataset.rating ) ); 124 } 125 } ); 126 } 127 128 if ( 'loading' === document.readyState ) { 129 document.addEventListener( 'DOMContentLoaded', start ); 130 } else { 131 start(); 132 } 133}() );
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.