| Conditions | 1 |
| Paths | 48 |
| Total Lines | 283 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 2 | ||
| Bugs | 0 | Features | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | /** global: GLSR, grecaptcha, HTMLFormElement, StarRating */ |
||
| 2 | ;(function() { |
||
| 3 | |||
| 4 | 'use strict'; |
||
| 5 | |||
| 6 | var Form = function( formEl, buttonEl ) { // HTMLElement, HTMLElement |
||
| 7 | this.button = buttonEl; |
||
| 8 | this.form = formEl; |
||
| 9 | this.init_(); |
||
| 10 | }; |
||
| 11 | |||
| 12 | Form.prototype = { |
||
| 13 | config: { |
||
| 14 | fieldErrorsClass: 'glsr-field-errors', |
||
| 15 | fieldSelector: '.glsr-field', |
||
| 16 | formMessagesClass: 'glsr-form-messages', |
||
| 17 | hasErrorClass: 'glsr-has-error', |
||
| 18 | }, |
||
| 19 | |||
| 20 | /** @return void */ |
||
| 21 | addRemoveClass_: function( el, classValue, bool ) { // HTMLElement, string, bool |
||
| 22 | el.classList[bool ? 'add' : 'remove']( classValue ); |
||
| 23 | }, |
||
| 24 | |||
| 25 | /** @return void */ |
||
| 26 | clearFieldError_: function( el ) { // HTMLElement |
||
| 27 | var fieldEl = el.closest( this.config.fieldSelector ); |
||
| 28 | if( fieldEl === null )return; |
||
| 29 | fieldEl.classList.remove( this.config.hasErrorClass ); |
||
| 30 | var errorEl = fieldEl.querySelector( this.config.fieldErrorsSelector ); |
||
| 31 | if( errorEl !== null ) { |
||
| 32 | errorEl.parentNode.removeChild( errorEl ); |
||
| 33 | } |
||
| 34 | }, |
||
| 35 | |||
| 36 | /** @return void */ |
||
| 37 | clearFormErrors_: function() { |
||
| 38 | this.getResultsEl_().innerHTML = ''; |
||
| 39 | for( var i = 0; i < this.form.length; i++ ) { |
||
| 40 | this.clearFieldError_( this.form[i] ); |
||
| 41 | } |
||
| 42 | }, |
||
| 43 | |||
| 44 | /** @return void */ |
||
| 45 | disableButton_: function() { |
||
| 46 | this.button.setAttribute( 'disabled', '' ); |
||
| 47 | }, |
||
| 48 | |||
| 49 | /** @return void */ |
||
| 50 | enableButton_: function() { |
||
| 51 | this.button.removeAttribute( 'disabled' ); |
||
| 52 | }, |
||
| 53 | |||
| 54 | /** @return void */ |
||
| 55 | fallbackSubmit_: function() { |
||
| 56 | if( GLSR.Ajax.isFileAPISupported() && GLSR.Ajax.isFormDataSupported() && GLSR.Ajax.isUploadSupported() )return; |
||
| 57 | this.form.submit(); |
||
| 58 | }, |
||
| 59 | |||
| 60 | /** @return void */ |
||
| 61 | handleResponse_: function( response ) { // object |
||
| 62 | console.log( response ); |
||
|
|
|||
| 63 | if( response.recaptcha === true ) { |
||
| 64 | console.log( 'executing recaptcha' ); |
||
| 65 | return this.recaptchaExecute_(); |
||
| 66 | } |
||
| 67 | if( response.recaptcha === 'reset' ) { |
||
| 68 | console.log( 'reseting failed recaptcha' ); |
||
| 69 | this.recaptchaReset_(); |
||
| 70 | } |
||
| 71 | if( response.errors === false ) { |
||
| 72 | console.log( 'reseting recaptcha' ); |
||
| 73 | this.recaptchaReset_(); |
||
| 74 | this.form.reset(); |
||
| 75 | } |
||
| 76 | console.log( 'submission finished' ); |
||
| 77 | this.showFieldErrors_( response.errors ); |
||
| 78 | this.showResults_( response ); |
||
| 79 | this.enableButton_(); |
||
| 80 | response.form = this.form; |
||
| 81 | document.dispatchEvent( new CustomEvent( 'site-reviews/after/submission', { detail: response })); |
||
| 82 | }, |
||
| 83 | |||
| 84 | /** @return HTMLDivElement */ |
||
| 85 | getFieldErrorsEl_: function( fieldEl ) { // HTMLElement |
||
| 86 | var errorsEl = fieldEl.querySelector( '.' + this.config.fieldErrorsClass ); |
||
| 87 | if( errorsEl === null ) { |
||
| 88 | errorsEl = document.createElement( 'div' ); |
||
| 89 | errorsEl.setAttribute( 'class', this.config.fieldErrorsClass ); |
||
| 90 | fieldEl.appendChild( errorsEl ); |
||
| 91 | } |
||
| 92 | return errorsEl; |
||
| 93 | }, |
||
| 94 | |||
| 95 | /** @return object */ |
||
| 96 | getFormData_: function( recaptchaToken ) { // string|null |
||
| 97 | recaptchaToken = recaptchaToken || ''; |
||
| 98 | var formData = new FormData( this.form ); |
||
| 99 | formData.append( 'g-recaptcha-response', recaptchaToken ); |
||
| 100 | return formData; |
||
| 101 | }, |
||
| 102 | |||
| 103 | /** @return HTMLDivElement */ |
||
| 104 | getResultsEl_: function() { |
||
| 105 | var resultsEl = this.form.querySelector( '.' + this.config.formMessagesClass ); |
||
| 106 | if( resultsEl === null ) { |
||
| 107 | resultsEl = document.createElement( 'div' ); |
||
| 108 | resultsEl.setAttribute( 'class', this.config.formMessagesClass ); |
||
| 109 | this.button.parentNode.insertBefore( resultsEl, this.button.nextSibling ); |
||
| 110 | } |
||
| 111 | return resultsEl; |
||
| 112 | }, |
||
| 113 | |||
| 114 | /** @return void */ |
||
| 115 | init_: function() { |
||
| 116 | this.button.addEventListener( 'click', this.onClick_.bind( this )); |
||
| 117 | this.form.addEventListener( 'change', this.onChange_.bind( this )); |
||
| 118 | this.form.addEventListener( 'submit', this.onSubmit_.bind( this )); |
||
| 119 | this.initStarRatings_(); |
||
| 120 | }, |
||
| 121 | |||
| 122 | /** @return void */ |
||
| 123 | initStarRatings_: function() { |
||
| 124 | new StarRating( 'select.glsr-star-rating', { |
||
| 125 | clearable: false, |
||
| 126 | showText: false, |
||
| 127 | onClick: this.clearFieldError_.bind( this ), |
||
| 128 | }); |
||
| 129 | }, |
||
| 130 | |||
| 131 | /** @return void */ |
||
| 132 | onChange_: function( ev ) { // Event |
||
| 133 | this.clearFieldError_( ev.target ); |
||
| 134 | }, |
||
| 135 | |||
| 136 | /** |
||
| 137 | * This event method handles the mayhem caused by the invisible-recaptcha plugin |
||
| 138 | * and is triggered on the invisible-recaptcha callback |
||
| 139 | * @return void */ |
||
| 140 | onClick_: function() { |
||
| 141 | var form = this; |
||
| 142 | this.form.onsubmit = null; |
||
| 143 | HTMLFormElement.prototype._submit = HTMLFormElement.prototype.submit; |
||
| 144 | HTMLFormElement.prototype.submit = function() { |
||
| 145 | var token = this.querySelector( '#g-recaptcha-response' ); |
||
| 146 | if( null !== token && this.querySelector( form.config.fieldSelector )) { |
||
| 147 | form.submitForm_( token.value ); |
||
| 148 | return; |
||
| 149 | } |
||
| 150 | this._submit(); |
||
| 151 | }; |
||
| 152 | }, |
||
| 153 | |||
| 154 | /** @return void */ |
||
| 155 | onSubmit_: function( ev ) { // HTMLEvent |
||
| 156 | if( this.form.classList.contains( 'no-ajax' ))return; |
||
| 157 | ev.preventDefault(); |
||
| 158 | this.recaptchaAddListeners_(); |
||
| 159 | this.clearFormErrors_(); |
||
| 160 | this.submitForm_(); |
||
| 161 | }, |
||
| 162 | |||
| 163 | /** @return void */ |
||
| 164 | recaptchaAddListeners_: function() { |
||
| 165 | var overlayEl = this.recaptchaGetOverlay_(); |
||
| 166 | if( overlayEl === -1 )return; |
||
| 167 | overlayEl.addEventListener( 'click', this.enableButton_.bind( this )); |
||
| 168 | window.addEventListener( 'keyup', this.recaptchaOnKeyup_.bind( this, overlayEl )); |
||
| 169 | }, |
||
| 170 | |||
| 171 | /** @return void */ |
||
| 172 | recaptchaExecute_: function() { |
||
| 173 | var recaptchaId = this.recaptchaGetId_(); |
||
| 174 | if( recaptchaId !== -1 ) { |
||
| 175 | grecaptcha.execute( recaptchaId ); |
||
| 176 | return; |
||
| 177 | } |
||
| 178 | // recaptcha ID not found so pass through an error |
||
| 179 | this.submitForm_( false ); |
||
| 180 | }, |
||
| 181 | |||
| 182 | /** @return string|int (-1) */ |
||
| 183 | recaptchaGetId_: function() { |
||
| 184 | return this.recaptchaSearch_( function( value, id ) { |
||
| 185 | if( Object.prototype.toString.call( value ) !== '[object HTMLDivElement]' )return; |
||
| 186 | if( value.closest( 'form' ) === this.form ) { |
||
| 187 | return id; |
||
| 188 | } |
||
| 189 | }); |
||
| 190 | }, |
||
| 191 | |||
| 192 | /** @return HTMLDivElement|int (-1) */ |
||
| 193 | recaptchaGetOverlay_: function() { |
||
| 194 | return this.recaptchaSearch_( function( value ) { |
||
| 195 | if( Object.prototype.toString.call( value ) !== '[object Object]' )return; |
||
| 196 | for( var obj in value) { |
||
| 197 | if( !value.hasOwnProperty( obj ) || Object.prototype.toString.call( value[obj] ) !== '[object HTMLDivElement]' )continue; |
||
| 198 | if( value[obj].className === '' ) { |
||
| 199 | return value[obj].firstChild; |
||
| 200 | } |
||
| 201 | } |
||
| 202 | return false; |
||
| 203 | }); |
||
| 204 | }, |
||
| 205 | |||
| 206 | /** @return void */ |
||
| 207 | recaptchaOnKeyup_: function( ev ) { // KeyboardEvent |
||
| 208 | if( ev.keyCode !== 27 )return; |
||
| 209 | this.enableButton_(); |
||
| 210 | this.recaptchaRemoveListeners_( ev.target ); |
||
| 211 | }, |
||
| 212 | |||
| 213 | /** @return void */ |
||
| 214 | recaptchaRemoveListeners_: function( overlayEl ) { // HTMLDivElement |
||
| 215 | overlayEl.removeEventListener( 'click', this.enableButton_ ); |
||
| 216 | window.removeEventListener( 'keyup', this.recaptchaOnKeyup_ ); |
||
| 217 | }, |
||
| 218 | |||
| 219 | /** @return void */ |
||
| 220 | recaptchaReset_: function() { |
||
| 221 | var recaptchaId = this.recaptchaGetId_(); |
||
| 222 | if( recaptchaId !== -1 ) { |
||
| 223 | grecaptcha.reset( recaptchaId ); |
||
| 224 | } |
||
| 225 | }, |
||
| 226 | |||
| 227 | /** @return mixed|int (-1) */ |
||
| 228 | recaptchaSearch_: function( callback ) { // function |
||
| 229 | var result = -1; |
||
| 230 | if( window.hasOwnProperty( '___grecaptcha_cfg' )) { |
||
| 231 | var clients = window.___grecaptcha_cfg.clients; |
||
| 232 | var i, key; |
||
| 233 | for( i in clients ) { |
||
| 234 | for( key in clients[i] ) { |
||
| 235 | if( !( result = callback( clients[i][key], i ).bind( this )))continue; |
||
| 236 | return result; |
||
| 237 | } |
||
| 238 | } |
||
| 239 | } |
||
| 240 | return result; |
||
| 241 | }, |
||
| 242 | |||
| 243 | /** @return void */ |
||
| 244 | showFieldErrors_: function( errors ) { // object |
||
| 245 | if( !errors )return; |
||
| 246 | var fieldEl, errorsEl; |
||
| 247 | for( var error in errors ) { |
||
| 248 | if( !errors.hasOwnProperty( error ))continue; |
||
| 249 | fieldEl = this.form.querySelector( '[name=' + error + ']' ).closest( this.config.fieldSelector ); |
||
| 250 | fieldEl.classList.add( this.config.hasErrorClass ); |
||
| 251 | errorsEl = this.getFieldErrorsEl_( fieldEl ); |
||
| 252 | for( var i = 0; i < errors[error].errors.length; i++ ) { |
||
| 253 | errorsEl.innerHTML += errors[error].errors[i]; |
||
| 254 | } |
||
| 255 | } |
||
| 256 | }, |
||
| 257 | |||
| 258 | /** @return void */ |
||
| 259 | showResults_: function( response ) { // object |
||
| 260 | var resultsEl = this.getResultsEl_(); |
||
| 261 | this.addRemoveClass_( resultsEl, 'gslr-has-errors', !!response.errors ); |
||
| 262 | resultsEl.innerHTML = response.message; |
||
| 263 | }, |
||
| 264 | |||
| 265 | /** @return void */ |
||
| 266 | submitForm_: function( recaptchaToken ) { // string|null |
||
| 267 | this.disableButton_(); |
||
| 268 | this.fallbackSubmit_(); |
||
| 269 | GLSR.Ajax.post( this.getFormData_( recaptchaToken ), this.handleResponse_.bind( this ), { |
||
| 270 | 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', |
||
| 271 | }); |
||
| 272 | }, |
||
| 273 | }; |
||
| 274 | |||
| 275 | GLSR.Forms = function() { |
||
| 276 | this.nodeList = document.querySelectorAll( 'form.glsr-form' ); |
||
| 277 | this.forms = []; |
||
| 278 | for( var i = 0; i < this.nodeList.length; i++ ) { |
||
| 279 | var submitButton = this.nodeList[i].querySelector( '[type=submit]' ); |
||
| 280 | if( !submitButton )continue; |
||
| 281 | this.forms.push( new Form( this.nodeList[i], submitButton )); |
||
| 282 | } |
||
| 283 | }; |
||
| 284 | })(); |
||
| 285 |