Passed
Push — master ( 554ad1...33081a )
by Paul
04:37
created

GLSR.Forms   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
/** global: CustomEvent, GLSR, HTMLFormElement, StarRating */
2
;(function() {
3
4
	'use strict';
5
6
	var Form = function( formEl, buttonEl ) { // HTMLElement, HTMLElement
7
		this.button = buttonEl;
8
		this.enableButton = this.enableButton_.bind( this );
9
		this.form = formEl;
10
		this.init = this.init_.bind( this );
11
		this.recaptcha = new GLSR.Recaptcha( this );
12
		this.submitForm = this.submitForm_.bind( this );
13
	};
14
15
	Form.prototype = {
16
		config: {
17
			fieldErrorsClass: 'glsr-field-errors',
18
			fieldSelector: '.glsr-field',
19
			formMessagesClass: 'glsr-form-messages',
20
			hasErrorClass: 'glsr-has-error',
21
		},
22
23
		/** @return void */
24
		addRemoveClass_: function( el, classValue, bool ) { // HTMLElement, string, bool
25
			el.classList[bool ? 'add' : 'remove']( classValue );
26
		},
27
28
		/** @return void */
29
		clearFieldError_: function( el ) { // HTMLElement
30
			var fieldEl = el.closest( this.config.fieldSelector );
31
			if( fieldEl === null )return;
32
			fieldEl.classList.remove( this.config.hasErrorClass );
33
			var errorEl = fieldEl.querySelector( this.config.fieldErrorsSelector );
34
			if( errorEl !== null ) {
35
				errorEl.parentNode.removeChild( errorEl );
36
			}
37
		},
38
39
		/** @return void */
40
		clearFormErrors_: function() {
41
			this.getResultsEl_().innerHTML = '';
42
			for( var i = 0; i < this.form.length; i++ ) {
43
				this.clearFieldError_( this.form[i] );
44
			}
45
		},
46
47
		/** @return void */
48
		disableButton_: function() {
49
			this.button.setAttribute( 'disabled', '' );
50
		},
51
52
		/** @return void */
53
		enableButton_: function() {
54
			this.button.removeAttribute( 'disabled' );
55
		},
56
57
		/** @return void */
58
		fallbackSubmit_: function() {
59
			if( GLSR.Ajax.isFileAPISupported() && GLSR.Ajax.isFormDataSupported() && GLSR.Ajax.isUploadSupported() )return;
60
			this.form.submit();
61
		},
62
63
		/** @return void */
64
		handleResponse_: function( response ) { // object
65
			console.log( response );
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
66
			if( response.recaptcha === true ) {
67
				console.log( 'executing recaptcha' );
68
				this.recaptcha.execute();
69
				return;
70
			}
71
			if( response.recaptcha === 'reset' ) {
72
				console.log( 'reseting failed recaptcha' );
73
				this.recaptcha.reset();
74
			}
75
			if( response.errors === false ) {
76
				console.log( 'reseting recaptcha' );
77
				this.recaptcha.reset();
78
				this.form.reset();
79
			}
80
			console.log( 'submission finished' );
81
			this.showFieldErrors_( response.errors );
82
			this.showResults_( response );
83
			this.enableButton_();
84
			response.form = this.form;
85
			document.dispatchEvent( new CustomEvent( 'site-reviews/after/submission', { detail: response }));
86
		},
87
88
		/** @return HTMLDivElement */
89
		getFieldErrorsEl_: function( fieldEl ) { // HTMLElement
90
			var errorsEl = fieldEl.querySelector( '.' + this.config.fieldErrorsClass );
91
			if( errorsEl === null ) {
92
				errorsEl = document.createElement( 'div' );
93
				errorsEl.setAttribute( 'class', this.config.fieldErrorsClass );
94
				fieldEl.appendChild( errorsEl );
95
			}
96
			return errorsEl;
97
		},
98
99
		/** @return object */
100
		getFormData_: function( recaptchaToken ) { // string|null
101
			recaptchaToken = recaptchaToken || '';
102
			var formData = new FormData( this.form );
103
			formData.append( 'g-recaptcha-response', recaptchaToken );
104
			return formData;
105
		},
106
107
		/** @return HTMLDivElement */
108
		getResultsEl_: function() {
109
			var resultsEl = this.form.querySelector( '.' + this.config.formMessagesClass );
110
			if( resultsEl === null ) {
111
				resultsEl = document.createElement( 'div' );
112
				resultsEl.setAttribute( 'class', this.config.formMessagesClass );
113
				this.button.parentNode.insertBefore( resultsEl, this.button.nextSibling );
114
			}
115
			return resultsEl;
116
		},
117
118
		/** @return void */
119
		init_: function() {
120
			this.button.addEventListener( 'click', this.onClick_.bind( this ));
121
			this.form.addEventListener( 'change', this.onChange_.bind( this ));
122
			this.form.addEventListener( 'submit', this.onSubmit_.bind( this ));
123
			this.initStarRatings_();
124
		},
125
126
		/** @return void */
127
		initStarRatings_: function() {
128
			new StarRating( 'select.glsr-star-rating', {
129
				clearable: false,
130
				showText: false,
131
				onClick: this.clearFieldError_.bind( this ),
132
			});
133
		},
134
135
		/** @return void */
136
		onChange_: function( ev ) { // Event
137
			this.clearFieldError_( ev.target );
138
		},
139
140
		/**
141
		 * This event method handles the mayhem caused by the invisible-recaptcha plugin
142
		 * and is triggered on the invisible-recaptcha callback
143
		 * @return void */
144
		onClick_: function() {
145
			var form = this;
146
			this.form.onsubmit = null;
147
			HTMLFormElement.prototype._submit = HTMLFormElement.prototype.submit;
148
			HTMLFormElement.prototype.submit = function() {
149
				var token = this.querySelector( '#g-recaptcha-response' );
150
				if( null !== token && this.querySelector( form.config.fieldSelector )) {
151
					form.submitForm_( token.value );
152
					return;
153
				}
154
				this._submit();
155
			};
156
		},
157
158
		/** @return void */
159
		onSubmit_: function( ev ) { // HTMLEvent
160
			if( this.form.classList.contains( 'no-ajax' ))return;
161
			ev.preventDefault();
162
			this.recaptcha.addListeners();
163
			this.clearFormErrors_();
164
			this.submitForm_();
165
		},
166
167
		/** @return void */
168
		showFieldErrors_: function( errors ) { // object
169
			if( !errors )return;
170
			var fieldEl, errorsEl;
171
			for( var error in errors ) {
172
				fieldEl = this.form.querySelector( '[name=' + error + ']' ).closest( this.config.fieldSelector );
173
				fieldEl.classList.add( this.config.hasErrorClass );
174
				errorsEl = this.getFieldErrorsEl_( fieldEl );
175
				for( var i = 0; i < errors[error].errors.length; i++ ) {
176
					errorsEl.innerHTML += errors[error].errors[i];
177
				}
178
			}
179
		},
180
181
		/** @return void */
182
		showResults_: function( response ) { // object
183
			var resultsEl = this.getResultsEl_();
184
			this.addRemoveClass_( resultsEl, 'gslr-has-errors', !!response.errors );
185
			resultsEl.innerHTML = response.message;
186
		},
187
188
		/** @return void */
189
		submitForm_: function( recaptchaToken ) { // string|null
190
			this.disableButton_();
191
			this.fallbackSubmit_();
192
			GLSR.Ajax.post( this.getFormData_( recaptchaToken ), this.handleResponse_.bind( this ), {
193
				'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
194
			});
195
		},
196
	};
197
198
	GLSR.Forms = function( shouldInit ) { // bool
199
		var form, submitButton;
200
		this.nodeList = document.querySelectorAll( 'form.glsr-form' );
201
		this.forms = [];
202
		for( var i = 0; i < this.nodeList.length; i++ ) {
203
			submitButton = this.nodeList[i].querySelector( '[type=submit]' );
204
			if( !submitButton )continue;
205
			form = new Form( this.nodeList[i], submitButton );
206
			if( shouldInit ) {
207
				form.init();
208
			}
209
			this.forms.push( form );
210
		}
211
		this.renderRecaptcha = function() {
212
			this.forms.forEach( function( form ) {
213
				form.recaptcha.render();
214
			});
215
		};
216
	};
217
})();
218