PageSourceSearch

https://navajowhite-wildcat-737546.hostingersite.com/wp-content/pl…/js/jet-reviews-frontend.js?ver=2.3.7

js navajowhite-wildcat-737546.hostingersite.com collected 2026-10-03 04:44:36 UTC 48,629 bytes, 1,936 lines download raw bytes

1( function( $, publicConfig ) {
2	'use strict';
3
4	let JetReviews = {
5
6		eventBus: new Vue(),
7
8		initedInstance: [],
9
10		captchaToken: false,
11
12		init: function() {
13			JetReviews.defineVueComponents();
14
15			this.initInstances();
16
17			window.addEventListener( 'jetReviews/editor/templateRenderer/renderSuccess', ( event ) => {
18				this.initBlockInstances();
19			}, false );
20		},
21
22		initInstances: function() {
23			let instancesList = $( '.jet-reviews-advanced' );
24
25			if ( ! instancesList[0] ) {
26				return false;
27			}
28
29			instancesList.each( function() {
30				let $target    = $( this ),
31				    instanceId = $target.attr( 'id' ),
32				    uniqid     = $target.data( 'uniqid' ) || false,
33				    options    = window['jetReviewsWidget' + uniqid] || false;
34
35				if ( ! options ) {
36					let optionsScript =  document.getElementById( 'jetReviewsWidgetOptions' + uniqid );
37
38					if ( optionsScript ) {
39						eval( optionsScript.innerHTML );
40						options = window['jetReviewsWidget' + uniqid] || false;
41					}
42				}
43
44				if ( ! $target[0] || ! uniqid || ! options ) {
45					return;
46				}
47
48				window.JetReviews.createJetReviewAdvancedInstance( instanceId, options );
49			} );
50		},
51
52		initBlockInstances: function() {
53			const targetNode = document.querySelector( '.jet-reviews-block-holder' );
54
55			if ( ! targetNode ) return;
56
57			const observer = new MutationObserver( function ( mutationsList, observer ) {
58
59				for ( const mutation of mutationsList ) {
60
61					if ( mutation.type === 'childList' ) {
62						const event = new Event( 'jetReviews/editor/block/renderSuccess' );
63
64						document.dispatchEvent( event );
65						observer.disconnect();
66					}
67				}
68			} );
69
70			observer.observe( targetNode, { childList: true, subtree: true } );
71
72			document.addEventListener( 'jetReviews/editor/block/renderSuccess',  ( event ) => {
73				this.initInstances();
74			} );
75		},
76
77		defineVueComponents: function() {
78
79			Vue.component( 'jet-reviews-widget-pagination', {
80				template: '#jet-reviews-widget-pagination-template',
81				props: {
82					current: {
83						type: Number,
84						default: 1
85					},
86					total: {
87						type: Number,
88						default: 0
89					},
90					pageSize: {
91						type: Number,
92						default: 10
93					},
94					prevIcon: {
95						type: String,
96						default: '<svg width="7" height="12" viewBox="0 0 7 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M5.67089 0L-5.96046e-08 6L5.67089 12L7 10.5938L2.65823 6L7 1.40625L5.67089 0Z"/></svg>'
97					},
98					nextIcon: {
99						type: String,
100						default: '<svg width="7" height="12" viewBox="0 0 7 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.32911 0L7 6L1.32911 12L0 10.5938L4.34177 6L0 1.40625L1.32911 0Z"/></svg>'
101					},
102					customCss: {
103						type: String,
104						default: ''
105					},
106				},
107				data() {
108					return {
109						baseClass: 'jet-reviews-widget-pagination',
110						currentPage: this.current,
111						currentPageSize: this.pageSize
112					};
113				},
114
115				watch: {
116					total ( val ) {
117						let maxPage = Math.ceil( val / this.currentPageSize );
118
119						if ( maxPage < this.currentPage ) {
120							this.currentPage = ( maxPage === 0 ? 1 : maxPage );
121						}
122					},
123					current ( val ) {
124						this.currentPage = val;
125					},
126					pageSize ( val ) {
127						this.currentPageSize = val;
128					}
129				},
130
131				computed: {
132					classesList() {
133
134						let classesList = [
135							this.baseClass,
136						];
137
138						if ( this.customCss ) {
139							classesList.push( this.customCss );
140						}
141
142						return classesList;
143					},
144
145					prevClasses () {
146						return [
147							`${this.baseClass}__item`,
148							`${this.baseClass}__item--prev`,
149							{
150								[`${this.baseClass}__item--disabled`]: this.currentPage === 1 || false
151							}
152						];
153					},
154
155					nextClasses () {
156						return [
157							`${this.baseClass}__item`,
158							`${this.baseClass}__item--next`,
159							{
160								[`${this.baseClass}__item--disabled`]: this.currentPage === this.allPages || false
161							}
162						];
163					},
164
165					firstPageClasses () {
166						return [
167							`${this.baseClass}__item`,
168							{
169								[`${this.baseClass}__item--active`]: this.currentPage === 1
170							}
171						];
172					},
173
174					lastPageClasses () {
175						return [
176							`${this.baseClass}__item`,
177							{
178								[`${this.baseClass}__item--active`]: this.currentPage === this.allPages
179							}
180						];
181					},
182
183					allPages () {
184						const allPage = Math.ceil( this.total / this.currentPageSize );
185
186						return ( allPage === 0 ) ? 1 : allPage;
187					},
188				},
189				methods: {
190					changePage ( page ) {
191
192						if ( this.currentPage !== page ) {
193
194							this.currentPage = page;
195							this.$emit( 'update:current', page );
196							this.$emit( 'on-change', page );
197						}
198					},
199
200					prev () {
201						const current = this.currentPage;
202
203						if ( current <= 1 ) {
204							return false;
205						}
206
207						this.changePage( current - 1 );
208					},
209
210					next () {
211						const current = this.currentPage;
212
213						if ( current >= this.allPages ) {
214							return false;
215						}
216
217						this.changePage(current + 1);
218					},
219
220					fastPrev () {
221						const page = this.currentPage - 5;
222
223						if ( page > 0 ) {
224							this.changePage( page );
225						} else {
226							this.changePage( 1 );
227						}
228					},
229
230					fastNext () {
231						const page = this.currentPage + 5;
232
233						if ( page > this.allPages ) {
234							this.changePage( this.allPages );
235						} else {
236							this.changePage( page );
237						}
238					},
239				},
240
241			} );
242
243			Vue.component( 'jet-advanced-reviews-form', {
244				template: '#jet-advanced-reviews-form-template',
245
246				props: {
247					reviewFields: Array
248				},
249
250				data: function() {
251					return ( {
252						reviewSubmiting: false,
253						reviewTitle: '',
254						reviewContent: '',
255						reviewAuthorName: '',
256						reviewAuthorMail: '',
257						messageText: '',
258						fields: this.reviewFields
259					} );
260				},
261
262				mounted: function() {
263					let self = this;
264
265					Vue.nextTick().then( function () {
266						let reviewContent = self.$refs.reviewContent,
267						    textarea      = reviewContent.$refs.textarea;
268
269						textarea.focus();
270					} );
271
272					if ( this.$root.isUserGuest ) {
273						this.reviewAuthorName = JetReviews.getLocalStorageData( 'guestName', '' );
274						this.reviewAuthorMail = JetReviews.getLocalStorageData( 'guestMail', '' );
275					}
276				},
277
278				computed: {
279					formControlsVisible: function() {
280
281						if ( this.$root.isUserGuest ) {
282							return this.isValidReviewContent &&
283								this.isValidReviewTitle &&
284								this.isValidAuthorName &&
285								this.isValidAuthorEmail;
286						}
287
288						return this.isValidReviewContent && this.isValidReviewTitle;
289					},
290
291					formMessageVisible: function() {
292						return '' !== this.messageText;
293					},
294
295					reviewTitleVisible: function() {
296						return this.$root.options.reviewTitleInputVisible;
297					},
298
299					reviewContentVisible: function() {
300						return this.$root.options.reviewContentInputVisible;
301					},
302
303					isValidReviewTitle: function() {
304						return '' !== this.reviewTitle || ! this.$root.options.reviewTitleInputVisible;
305					},
306
307					isValidReviewContent: function() {
308						return '' !== this.reviewContent || ! this.$root.options.reviewContentInputVisible;
309					},
310
311					isValidAuthorName: function() {
312						return '' !== this.reviewAuthorName;
313					},
314
315					isValidAuthorEmail: function() {
316						return '' !== this.reviewAuthorMail && JetReviews.checkValidEmail( this.reviewAuthorMail );
317					},
318
319				},
320
321				methods: {
322					cancelSubmit: function() {
323						JetReviews.eventBus.$emit( 'closeNewReviewForm', { uniqId: this.$root.options.uniqId } );
324					},
325
326					submitReview: function() {
327
328						let self = this,
329						    forSendingData = {
330							    source: this.$root.sourceData.source,
331							    source_id: this.$root.sourceData.sourceId,
332							    title: this.reviewTitle,
333							    content: this.reviewContent,
334							    author_id: this.$root.userData.id,
335							    author_name: this.reviewAuthorName,
336							    author_mail: this.reviewAuthorMail,
337							    rating_data: this.fields
338						    },
339						    recaptchaConfig = window.jetReviewPublicConfig.recaptchaConfig;
340
341						// Recaptcha enable check
342						if ( recaptchaConfig.enable ) {
343
344							window.grecaptcha.ready( function() {
345								grecaptcha.execute(
346									recaptchaConfig.site_key,
347									{
348										action: 'submit_review'
349									}
350								).then( function( token ) {
351
352									JetReviews.captchaToken = token;
353
354									let modifyData = Object.assign( {}, forSendingData, {
355										captcha_token: token
356									} );
357
358									self.submitReviewHandle( modifyData );
359								} );
360							} );
361
362							return false;
363						}
364
365						this.submitReviewHandle( forSendingData );
366					},
367
368					submitReviewHandle: function( sendData = false ) {
369						let self = this;
370
371						if ( ! sendData ) {
372							console.warn( 'Empty new review data for sending' );
373
374							return false;
375						}
376
377						this.reviewSubmiting = true;
378						this.messageText = '';
379
380						wp.apiFetch( {
381							method: 'post',
382							path: window.jetReviewPublicConfig.submitReviewRoute,
383							data: sendData,
384						} ).then( function( response ) {
385							response = self.maybeModifyResponce( response );
386
387							let responseSuccess = response.success,
388							    responseData    = response.data,
389							    responseMessage = response.message;
390
391							self.reviewSubmiting = false;
392							self.messageText = responseMessage;
393
394							if ( self.$root.isUserGuest ) {
395								let guestReviewedItems = JetReviews.getLocalStorageData( self.$root.guestReviewedStorageName, [] );
396
397								if ( responseSuccess && ! guestReviewedItems.includes( self.$root.sourceData.sourceId ) ) {
398									self.$root.userData.name = self.reviewAuthorName;
399									self.$root.userData.mail = self.reviewAuthorMail;
400									JetReviews.setLocalStorageData( 'guestName', self.reviewAuthorName );
401									JetReviews.setLocalStorageData( 'guestMail', self.reviewAuthorMail );
402
403									guestReviewedItems.push( self.$root.sourceData.sourceId );
404									JetReviews.setLocalStorageData( self.$root.guestReviewedStorageName, guestReviewedItems );
405								}
406							}
407
408							if ( responseSuccess ) {
409								if ( 'review-created' === response.code ) {
410									JetReviews.eventBus.$emit( 'addReview', {
411										uniqId: self.$root.options.uniqId,
412										reviewData: responseData.item,
413									} );
414
415									self.$root.reviewsAverageRating = +responseData.rating;
416								}
417
418								self.$root.formVisible = false;
419								self.$root.userData.canReview.allowed = false;
420								self.$root.userData.canReview.message = responseMessage;
421							}
422
423						} );
424					},
425
426					maybeModifyResponce: function( responce = false ) {
427						let code = responce.code;
428
429						if ( 'need-approve' === code && '' !== this.$root.options.labels.moderatorCheckMessage ) {
430							responce.message = this.$root.options.labels.moderatorCheckMessage;
431						}
432
433						if ( 'already-created' === code && '' !== this.$root.options.labels.alreadyReviewedMessage ) {
434							responce.message = this.$root.options.labels.alreadyReviewedMessage;
435						}
436
437						return responce;
438					}
439
440				}
441			});
442
443			Vue.component( 'slider-input', {
444				template: '#jet-advanced-reviews-slider-input-template',
445
446				props: {
447					value: {
448						type: [ String, Number ],
449						default: ''
450					},
451					max: {
452						type: [ Number ],
453						default: 5
454					},
455					step: {
456						type: [ Number ],
457						default: 1
458					},
459					label: {
460						type: [ String, Boolean ],
461						default: false
462					},
463				},
464
465				data: function() {
466					return ( {
467						//currentValue: this.value,
468					} );
469				},
470
471				computed: {
472					valueLabel: function() {
473						return this.value;
474					}
475				},
476
477				methods: {
478					handleInput ( event ) {
479						let value = event.target.value;
480
481						this.$emit( 'input', value );
482						this.$emit( 'on-change', event );
483					},
484					handleChange ( event ) {
485						this.$emit( 'on-input-change', event );
486					}
487				},
488			});
489
490			Vue.component( 'stars-input', {
491				template: '#jet-advanced-reviews-stars-input-template',
492
493				props: {
494					value: {
495						type: [ String, Number ],
496						default: ''
497					},
498					max: {
499						type: [ Number ],
500						default: 5
501					},
502					step: {
503						type: [ Number ],
504						default: 1
505					},
506					label: {
507						type: [ String, Boolean ],
508						default: false
509					},
510				},
511
512				data: function() {
513					return ( {
514						currentRating: this.value,
515					} );
516				},
517
518				computed: {
519					valueLabel: function() {
520						return `${ this.value }/${ this.max }`;
521					},
522
523					rating: function() {
524						return ( this.currentRating / this.max ) * 100;
525					},
526
527					preparedRating: function() {
528
529						if ( 10 > this.rating ) {
530							return 10;
531						}
532
533						return this.rating;
534					},
535
536					emptyIcon: function() {
537						return this.$root.refsHtml.emptyStarIcon || '<i class="far fa-star"></i>';
538					},
539
540					emptyIcons: function() {
541						let icon = `<div class="jet-reviews-star">${ this.$root.refsHtml.emptyStarIcon }</div>` || '<div class="jet-reviews-star"><i class="far fa-star"></i></div>';
542
543						return icon.repeat( this.max );
544					},
545
546					filledIcons: function() {
547						let icon = `<div class="jet-reviews-star">${ this.$root.refsHtml.filledStarIcon }</div>` || `<div class="jet-reviews-star"><i class="fas fa-star"></i></div>`;
548						console.log(icon);
549						return icon.repeat( this.max );
550					},
551
552					ratingClass: function() {
553						let ratingClass = 'very-high-rating';
554
555						if ( this.rating >= 80 && this.rating <= 100 ) {
556							ratingClass = 'very-high-rating';
557						}
558
559						if ( this.rating >= 60 && this.rating <= 79 ) {
560							ratingClass = 'high-rating';
561						}
562
563						if ( this.rating >= 40 && this.rating <= 59 ) {
564							ratingClass = 'medium-rating';
565						}
566
567						if ( this.rating >= 22 && this.rating <= 39 ) {
568							ratingClass = 'low-rating';
569						}
570
571						if ( this.rating >= 0 && this.rating <= 21 ) {
572							ratingClass = 'very-low-rating';
573						}
574
575						return ratingClass;
576					},
577				},
578
579				methods: {
580					ratingClick( rating ) {
581						this.currentRating = rating;
582						this.$emit( 'input', rating );
583					},
584
585					ratingMouseOver( rating ) {
586						this.currentRating = rating;
587					},
588
589					ratingMouseOut() {
590						this.currentRating = this.value;
591					},
592				},
593			});
594
595			Vue.component( 'jet-advanced-reviews-item', {
596				template: '#jet-advanced-reviews-item-template',
597
598				props: {
599					itemData: Object
600				},
601
602				data: function() {
603					return ( {
604						commentFormVisible: false,
605						commentText: '',
606						commentAuthorName: '',
607						commentAuthorMail: '',
608						commentSubmiting: false,
609						approvalSubmiting: false,
610						parentComment: 0,
611						commentsVisible: false,
612						responseMessage: '',
613						detailsVisibleState: false
614					} );
615				},
616
617				mounted: function() {
618					if ( this.$root.isUserGuest ) {
619						this.commentAuthorName = JetReviews.getLocalStorageData( 'guestName', '' );
620						this.commentAuthorMail = JetReviews.getLocalStorageData( 'guestMail', '' );
621
622						let guestReviewRatedData = JetReviews.getLocalStorageData( this.$root.guestRatedStorageName, {} );
623
624						if ( guestReviewRatedData.hasOwnProperty( this.itemData.id ) ) {
625							this.$set( this.itemData, 'approval', guestReviewRatedData[ this.itemData.id ] );
626						}
627
628					}
629				},
630
631				computed: {
632
633					isDetailsFieldsAvaliable: function() {
634						return 1 < this.itemData.rating_data.length;
635					},
636
637					detailsVisible: function() {
638						return this.isDetailsFieldsAvaliable && this.detailsVisibleState;
639					},
640
641					averageRatingVisible: function() {
642						return 'average' === this.$root.options.reviewRatingType;
643					},
644
645					detailsRatingVisible: function() {
646						return 'details' === this.$root.options.reviewRatingType;
647					},
648
649					authorVerificationData: function() {
650						return 0 !== this.itemData.verifications.length ? this.itemData.verifications : false;
651					},
652
653					isCommentsEmpty: function() {
654						return 0 === this.itemData.comments.length;
655					},
656
657					isCommentsVisible: function() {
658						return !this.isCommentsEmpty && this.commentsVisible;
659					},
660
661					itemCommentsCount: function() {
662						let itemCommentsCount = false;
663
664						itemCommentsCount = this.getCommentsCount( this.itemData.comments );
665
666						return itemCommentsCount;
667					},
668
669					pinnedVisible: function() {
670						return this.itemData.pinned;
671					},
672
673					commentControlsVisible: function() {
674
675						if ( this.$root.isUserGuest ) {
676							return this.isCommentValid &&
677								this.isValidAuthorName &&
678								this.isValidAuthorEmail;
679						}
680
681						return this.isCommentValid;
682					},
683
684					averageRatingData: function() {
685						let ratingDatalength = this.itemData.rating_data.length,
686						    summaryValue = 0,
687						    avarageValue = 0,
688						    summaryMax = 0,
689						    avarageMax = 0;
690
691						summaryValue = this.itemData.rating_data.reduce( function( accumulator, currentValue ) {
692							return accumulator + +currentValue.field_value;
693						}, 0 );
694
695						summaryMax = this.itemData.rating_data.reduce( function( accumulator, currentValue ) {
696							return accumulator + +currentValue.field_max;
697						}, 0 );
698
699						avarageValue = Math.round( summaryValue / ratingDatalength );
700						avarageMax = Math.round( summaryMax / ratingDatalength );
701
702						return {
703							rating: Math.round( avarageValue * 100 / avarageMax, 1 ),
704							max: Math.round( avarageMax, 1 ),
705							value: Math.round( avarageValue, 1 )
706						};
707					},
708
709					addCommentIcon: function() {
710						return this.$root.refsHtml.newCommentButtonIcon || false;
711					},
712
713					showCommentsIcon: function() {
714						return this.$root.refsHtml.showCommentsButtonIcon || false;
715					},
716
717					pinnedIcon: function() {
718						return this.$root.refsHtml.pinnedIcon || '<i class="fas fa-thumbtack"></i>';
719					},
720
721					likeIcon: function() {
722						let emptyLike  = this.$root.refsHtml.reviewEmptyLikeIcon || '<i class="far fa-thumbs-up"></i>',
723						    filledLike = this.$root.refsHtml.reviewFilledLikeIcon || '<i class="fas fa-thumbs-up"></i>';
724
725						return ! this.itemData.approval.like ? emptyLike : filledLike;
726					},
727
728					dislikeIcon: function() {
729						let emptyDislike  = this.$root.refsHtml.reviewEmptyDislikeIcon || '<i class="far fa-thumbs-down"></i>',
730						    filledDislike = this.$root.refsHtml.reviewFilledDislikeIcon || '<i class="fas fa-thumbs-down"></i>';
731
732						return ! this.itemData.approval.dislike ? emptyDislike : filledDislike;
733					},
734
735					userCanComment: function() {
736						return this.$root.sourceData.commentsAllowed && this.$root.userData.canComment.allowed;
737					},
738
739					userCanRate: function() {
740						return this.$root.sourceData.approvalAllowed && this.$root.userData.canRate;
741					},
742
743					isValidAuthorName: function() {
744						return '' !== this.commentAuthorName;
745					},
746
747					isValidAuthorEmail: function() {
748						return JetReviews.checkValidEmail( this.commentAuthorMail );
749					},
750
751					isCommentValid: function() {
752						return '' !== this.commentText;
753					},
754
755				},
756
757				methods: {
758					showCommentForm: function() {
759						let self = this;
760
761						this.commentFormVisible = !this.commentFormVisible;
762
763						if ( this.commentFormVisible ) {
764							Vue.nextTick().then( function () {
765								let commentContent = self.$refs.commentContent,
766								    textarea       = commentContent.$refs.textarea;
767
768								textarea.focus();
769							} );
770						}
771					},
772
773					cancelNewComment: function() {
774						this.commentFormVisible = false;
775						this.responseMessage = '';
776					},
777
778					submitNewComment: function() {
779
780						let self = this,
781						    forSendingData = {
782							    source: this.$root.sourceData.source,
783							    source_id: this.$root.sourceData.sourceId,
784							    parent_id: this.parentComment,
785							    review_id: this.itemData.id,
786							    author_id: this.$root.userData.id,
787							    author_name: this.commentAuthorName,
788							    author_mail: this.commentAuthorMail,
789							    content: this.commentText,
790						    },
791						    recaptchaConfig = window.jetReviewPublicConfig.recaptchaConfig;
792
793						// Recaptcha enable check
794						if ( recaptchaConfig.enable ) {
795
796							window.grecaptcha.ready( function() {
797								grecaptcha.execute(
798									recaptchaConfig.site_key,
799									{
800										action: 'submit_review_comment'
801									}
802								).then( function( token ) {
803
804									JetReviews.captchaToken = token;
805
806									let modifyData = Object.assign( {}, forSendingData, {
807										captcha_token: token
808									} );
809
810									self.submitCommentHandler( modifyData );
811								} );
812							} );
813
814							return false;
815						}
816
817						this.submitCommentHandler( forSendingData );
818					},
819
820					submitCommentHandler: function( sendData = false ) {
821						let self = this;
822
823						if ( ! sendData ) {
824							console.warn( 'Empty new comment data for sending' );
825
826							return false;
827						}
828
829						this.commentSubmiting = true;
830
831						wp.apiFetch( {
832							method: 'post',
833							path: window.jetReviewPublicConfig.submitReviewCommentRoute,
834							data: sendData,
835						} ).then( function( response ) {
836
837							self.commentSubmiting = false;
838
839							self.$root.userData.name = self.commentAuthorName;
840							self.$root.userData.mail = self.commentAuthorMail;
841							JetReviews.setLocalStorageData( 'guestName', self.commentAuthorName );
842							JetReviews.setLocalStorageData( 'guestMail', self.commentAuthorMail );
843
844							if ( response.success ) {
845								self.commentFormVisible = false;
846								self.commentText = '';
847								self.itemData.comments.unshift( response.data );
848								self.commentsVisible = true;
849							} else {
850								self.responseMessage = response.message;
851								console.log( response.message );
852							}
853						} );
854					},
855
856					updateApprovalHandler: function( type ) {
857						let self    = this,
858						    altType = 'like' === type ? 'dislike' : 'like';
859
860						this.approvalSubmiting = true;
861
862						wp.apiFetch( {
863							method: 'post',
864							path: window.jetReviewPublicConfig.likeReviewRoute,
865							data: {
866								review_id: self.itemData.id,
867								type: type,
868								inc: ! self.itemData.approval[ type ],
869								current_state: self.itemData.approval,
870							},
871						} ).then( function( response ) {
872							self.approvalSubmiting = false;
873
874							if ( response.success ) {
875								self.$set( self.itemData, 'approval', response.data.approval );
876								self.$set( self.itemData, 'like', response.data.like );
877								self.$set( self.itemData, 'dislike', response.data.dislike );
878
879								if ( self.$root.isUserGuest ) {
880									self.updateGuestApprovalData( self.itemData.id, self.itemData.approval );
881								}
882
883							} else {
884								console.log( response.message );
885							}
886						} );
887					},
888
889					updateGuestApprovalData: function( $reviewId = false, rateData = false ) {
890						let guestReviewRateData = JetReviews.getLocalStorageData( this.$root.guestRatedStorageName, {} );
891
892						guestReviewRateData[ $reviewId ] = rateData;
893
894						JetReviews.setLocalStorageData( this.$root.guestRatedStorageName, guestReviewRateData );
895					},
896
897					toggleCommentsVisible: function() {
898						this.commentsVisible = !this.commentsVisible;
899					},
900
901					getCommentsCount: function( comments, initialValue = 0 ) {
902
903						let total = comments.reduce( ( accumulator, commentData ) => {
904							if ( commentData.hasOwnProperty( 'children' ) && 0 !== commentData.children.length ) {
905								let initialValue = accumulator + 1;
906								return this.getCommentsCount( commentData.children, initialValue );
907							} else {
908								return accumulator + 1;
909							}
910						}, initialValue );
911
912						return total;
913					}
914				}
915			});
916
917			Vue.component( 'jet-advanced-reviews-comment', {
918				template: '#jet-advanced-reviews-comment-template',
919
920				props: {
921					commentData: Object,
922					parentId: Number,
923					parentComments: Array,
924					depth: Number,
925				},
926
927				data: function() {
928					return ( {
929						commentsList: this.commentData.children || [],
930						replySubmiting: false,
931						replyFormVisible: false,
932						replyText: '',
933						replyAuthorName: '',
934						replyAuthorMail: '',
935						responseMessage: ''
936					} );
937				},
938
939				mounted: function() {
940					if ( this.$root.isUserGuest ) {
941						this.replyAuthorName = JetReviews.getLocalStorageData( 'guestName', '' );
942						this.replyAuthorMail = JetReviews.getLocalStorageData( 'guestMail', '' );
943					}
944				},
945
946				computed: {
947					commentClass: function() {
948						return '';
949					},
950
951					formControlsVisible: function() {
952						return this.$root.sourceData.commentsAllowed;
953					},
954
955					submitVisible: function() {
956
957						if ( this.$root.isUserGuest ) {
958							return this.isReplyTextValid &&
959								this.isValidAuthorName &&
960								this.isValidAuthorEmail;
961						}
962
963						return this.isReplyTextValid;
964					},
965
966					replyIcon: function() {
967						return this.$root.refsHtml.replyButtonIcon || false;
968					},
969
970					isValidAuthorName: function() {
971						return '' !== this.replyAuthorName;
972					},
973
974					isValidAuthorEmail: function() {
975						return JetReviews.checkValidEmail( this.replyAuthorMail );
976					},
977
978					isReplyTextValid: function() {
979						return '' !== this.replyText;
980					},
981
982					authorVerificationData: function() {
983
984						if ( ! this.commentData.verifications ) {
985							return false;
986						}
987
988						return 0 !== this.commentData.verifications.length ? this.commentData.verifications : false;
989					},
990				},
991
992				methods: {
993					showReplyForm: function() {
994						let self = this;
995
996						this.replyFormVisible = !this.replyFormVisible;
997
998						if ( this.replyFormVisible ) {
999							this.replyText = '<b>' + this.commentData.author.name + '</b>,&nbsp;';
1000
1001							Vue.nextTick().then( function () {
1002								let commentText = self.$refs.commentText,
1003								    textarea    = commentText.$refs.textarea;
1004
1005								JetReviews.placeCaretAtEnd( textarea );
1006							} );
1007						}
1008					},
1009
1010					cancelNewReply: function() {
1011						this.replyFormVisible = false;
1012						this.responseMessage = '';
1013					},
1014
1015					submitNewReply: function() {
1016
1017						let self = this,
1018						    forSendingData = {
1019							    source: this.$root.sourceData.source,
1020							    source_id: this.$root.sourceData.sourceId,
1021							    parent_id: 0 === this.depth ? this.commentData.id : this.parentId,
1022							    review_id: this.commentData.review_id,
1023							    author_id: this.$root.userData.id,
1024							    author_name: this.replyAuthorName,
1025							    author_mail: this.replyAuthorMail,
1026							    content: this.replyText,
1027						    },
1028						    recaptchaConfig = window.jetReviewPublicConfig.recaptchaConfig;
1029
1030						// Recaptcha enable check
1031						if ( recaptchaConfig.enable ) {
1032
1033							window.grecaptcha.ready( function() {
1034								grecaptcha.execute(
1035									recaptchaConfig.site_key,
1036									{
1037										action: 'submit_comment_reply'
1038									}
1039								).then( function( token ) {
1040
1041									JetReviews.captchaToken = token;
1042
1043									let modifyData = Object.assign( {}, forSendingData, {
1044										captcha_token: token
1045									} );
1046
1047									self.submitReplyHandler( modifyData );
1048								} );
1049							} );
1050
1051							return false;
1052						}
1053
1054						this.submitReplyHandler( forSendingData );
1055					},
1056
1057					submitReplyHandler: function( sendData = false ) {
1058						let self = this;
1059
1060						if ( ! sendData ) {
1061							console.warn( 'Empty review comment data for sending' );
1062
1063							return false;
1064						}
1065
1066						this.replySubmiting = true;
1067
1068						wp.apiFetch( {
1069							method: 'post',
1070							path: window.jetReviewPublicConfig.submitReviewCommentRoute,
1071							data: sendData,
1072						} ).then( function( response ) {
1073
1074							self.replySubmiting = false;
1075
1076							self.$root.userData.name = self.replyAuthorName;
1077							self.$root.userData.mail = self.replyAuthorMail;
1078							JetReviews.setLocalStorageData( 'guestName', self.replyAuthorName );
1079							JetReviews.setLocalStorageData( 'guestMail', self.replyAuthorMail );
1080
1081							if ( response.success ) {
1082								self.replyFormVisible = false;
1083								self.replyText = '';
1084
1085								if ( 0 === self.depth ) {
1086									self.commentData.children.unshift( response.data );
1087								} else {
1088									self.parentComments.push( response.data );
1089								}
1090							} else {
1091								self.responseMessage = response.message;
1092							}
1093						} );
1094					}
1095				}
1096			});
1097
1098			Vue.component( 'points-field', {
1099				template: '#jet-advanced-reviews-point-field-template',
1100
1101				props: {
1102					before: {
1103						type: [ Number, String, Boolean ],
1104						default: false
1105					},
1106					rating: Number,
1107					after: {
1108						type: [ Number, String, Boolean ],
1109						default: false
1110					},
1111				},
1112
1113				data: function() {
1114					return ( {} );
1115				},
1116
1117				computed: {
1118					isBeforeEmpty: function() {
1119						return false === this.before || '' === this.before;
1120					},
1121
1122					isAfterEmpty: function() {
1123						return false === this.after || '' === this.after;
1124					},
1125
1126					preparedRating: function() {
1127
1128						if ( 10 > this.rating ) {
1129							return 10;
1130						}
1131
1132						return this.rating;
1133					},
1134
1135					ratingClass: function() {
1136						let ratingClass = 'very-high-rating';
1137
1138						if ( this.rating >= 80 && this.rating <= 100 ) {
1139							ratingClass = 'very-high-rating';
1140						}
1141
1142						if ( this.rating >= 60 && this.rating <= 79 ) {
1143							ratingClass = 'high-rating';
1144						}
1145
1146						if ( this.rating >= 40 && this.rating <= 59 ) {
1147							ratingClass = 'medium-rating';
1148						}
1149
1150						if ( this.rating >= 22 && this.rating <= 39 ) {
1151							ratingClass = 'low-rating';
1152						}
1153
1154						if ( this.rating >= 0 && this.rating <= 21 ) {
1155							ratingClass = 'very-low-rating';
1156						}
1157
1158						return ratingClass;
1159					}
1160				}
1161			});
1162
1163			Vue.component( 'stars-field', {
1164				template: '#jet-advanced-reviews-star-field-template',
1165
1166				props: {
1167					before: {
1168						type: [ Number, String, Boolean ],
1169						default: false
1170					},
1171					rating: Number,
1172					after: {
1173						type: [ Number, String, Boolean ],
1174						default: false
1175					},
1176				},
1177
1178				data: function() {
1179					return ( {} );
1180				},
1181
1182				computed: {
1183					isBeforeEmpty: function() {
1184						return ! this.before || '' === this.before;
1185					},
1186
1187					isAfterEmpty: function() {
1188						return ! this.after || '' === this.after;
1189					},
1190
1191					preparedRating: function() {
1192
1193						if ( 10 > this.rating ) {
1194							return 10;
1195						}
1196
1197						return this.rating;
1198					},
1199
1200					emptyIcons: function() {
1201						let icon = `<div class="jet-reviews-star">${ this.$root.refsHtml.emptyStarIcon }</div>` || '<div class="jet-reviews-star"><i class="far fa-star"></i></div>';
1202
1203						return icon.repeat( 5 );
1204					},
1205
1206					filledIcons: function() {
1207						let icon = `<div class="jet-reviews-star">${ this.$root.refsHtml.filledStarIcon }</div>` || '<div class="jet-reviews-star"><i class="fas fa-star"></i></div>';
1208
1209						return icon.repeat( 5 );
1210					},
1211
1212					ratingClass: function() {
1213						let ratingClass = 'very-high-rating';
1214
1215						if ( this.rating >= 80 && this.rating <= 100 ) {
1216							ratingClass = 'very-high-rating';
1217						}
1218
1219						if ( this.rating >= 60 && this.rating <= 79 ) {
1220							ratingClass = 'high-rating';
1221						}
1222
1223						if ( this.rating >= 40 && this.rating <= 59 ) {
1224							ratingClass = 'medium-rating';
1225						}
1226
1227						if ( this.rating >= 22 && this.rating <= 39 ) {
1228							ratingClass = 'low-rating';
1229						}
1230
1231						if ( this.rating >= 0 && this.rating <= 21 ) {
1232							ratingClass = 'very-low-rating';
1233						}
1234
1235						return ratingClass;
1236					}
1237				},
1238			});
1239
1240			Vue.component( 'html-textarea', {
1241				template:'<div :class="classes" ref="textarea" contenteditable="true" tabindex="0" :data-placeholder="placeholder" :data-not-valid-label="notValidLabel" @input="updateHTML" @focus="focusHandler" @blur="blurHandler"></div>',
1242
1243				props: {
1244					value: String,
1245					isValid: {
1246						type: Boolean,
1247						default: true,
1248					},
1249					placeholder: {
1250						type: String,
1251						default: 'Input',
1252					},
1253					notValidLabel: {
1254						type: String,
1255						default: 'This field is required or not valid',
1256					},
1257				},
1258
1259				data: function() {
1260					return ( {
1261						isFocus: false,
1262						isEmpty: true,
1263					} );
1264				},
1265
1266				computed: {
1267					classes: function() {
1268						let classes = [
1269							'jet-reviews-content-editable',
1270							!this.isValid ? 'jet-reviews-content-editable--not-valid' : false,
1271							this.isFocus ? 'jet-reviews-content-editable--focus' : false,
1272							this.isPlaceholder ? 'jet-reviews-content-editable--placeholder' : false,
1273						];
1274
1275						return classes;
1276					},
1277
1278					isPlaceholder: function() {
1279
1280						if ( this.isFocus || ! this.isEmpty ) {
1281							return false;
1282						}
1283
1284						return true;
1285					}
1286				},
1287
1288				mounted: function () {
1289					this.$el.innerHTML = this.value;
1290				},
1291
1292				methods: {
1293					updateHTML: function( e ) {
1294						this.$emit( 'input', e.target.innerHTML );
1295
1296						if ( 0 === $( this.$refs.textarea ).text().trim().length ) {
1297							this.isEmpty = true;
1298						} else {
1299							this.isEmpty = false;
1300						}
1301					},
1302
1303					focusHandler: function( e ) {
1304						this.$emit( 'focus', e.target );
1305						this.isFocus = true;
1306					},
1307
1308					blurHandler: function( e ) {
1309						this.$emit( 'blur', e.target );
1310						this.isFocus = false;
1311					}
1312				}
1313			});
1314		},
1315
1316		createJetReviewAdvancedInstance: function( instanceId, options ) {
1317
1318			if ( JetReviews.initedInstance.includes( instanceId ) ) {
1319				return;
1320			}
1321
1322			JetReviews.initedInstance.push( instanceId );
1323
1324			let JetReviewAdvancedInstance = new Vue( {
1325				el: '#' + instanceId,
1326
1327				data: {
1328					uniqId: instanceId,
1329					options: options,
1330					reviewsLoaded: false,
1331					getReviewsProcessing: false,
1332					reviewsList: [],
1333					reviewsPage: 1,
1334					reviewsTotal: 0,
1335					reviewsAverageRating: 0,
1336					userData: options.userData,
1337					sourceData: options.sourceData,
1338					reviewTypeData: window.jetReviewPublicConfig.reviewTypeData,
1339					formVisible: false,
1340					isMounted: false,
1341					refsHtml: {},
1342				},
1343
1344				mounted: function() {
1345					let self     = this,
1346					    refsHtml = {};
1347
1348					this.isMounted = true;
1349
1350					for ( var ref in this.$refs ) {
1351						Object.assign( refsHtml, { [ ref ]: this.$refs[ ref ].innerHTML } );
1352					}
1353
1354					this.refsHtml = refsHtml;
1355
1356					if ( this.isUserGuest ) {
1357						this.$set( this.userData, 'id', this.guestId );
1358						this.$set( this.userData, 'name', this.guestName );
1359						this.$set( this.userData, 'mail', this.guestMail );
1360
1361						let guestReviewedItems     = JetReviews.getLocalStorageData( this.guestReviewedStorageName, [] );
1362
1363						if ( guestReviewedItems.includes( this.sourceData.sourceId ) ) {
1364							this.$set( this.userData.canReview, 'allowed', false );
1365							this.$set( this.userData.canReview, 'message', this.options.labels.alreadyReviewedMessage );
1366						}
1367					}
1368
1369					if ( this.options.reviewsListData ) {
1370						this.reviewsList = this.options.reviewsListData.list;
1371						this.reviewsTotal = +this.options.reviewsListData.total;
1372						this.reviewsAverageRating = +this.options.reviewsListData.rating;
1373						this.reviewsLoaded = true;
1374					} else {
1375						wp.apiFetch( {
1376							method: 'post',
1377							path: window.jetReviewPublicConfig.getPublicReviewsRoute,
1378							data: {
1379								source: self.sourceData.source,
1380								source_id: self.sourceData.sourceId,
1381								page: self.reviewsPage - 1,
1382								page_size: self.options.pageSize
1383							},
1384						} ).then( function( response ) {
1385
1386							self.reviewsLoaded = true;
1387
1388							if ( response.success && response.data ) {
1389								self.reviewsList = response.data.list;
1390								self.reviewsTotal = +response.data.total;
1391								self.reviewsAverageRating = +response.data.rating;
1392							} else {
1393								console.log( 'Error' );
1394							}
1395						} );
1396					}
1397
1398					JetReviews.eventBus.$on( 'addReview', function ( payLoad ) {
1399
1400						if ( self.options.uniqId !== payLoad.uniqId ) {
1401							return;
1402						}
1403
1404						self.formVisible = false;
1405
1406						let reviewData = payLoad.reviewData;
1407
1408						self.reviewsList.unshift( reviewData );
1409
1410						self.reviewsTotal += 1;
1411					} );
1412
1413					JetReviews.eventBus.$on( 'closeNewReviewForm', function ( payLoad ) {
1414
1415						if ( self.options.uniqId !== payLoad.uniqId ) {
1416							return;
1417						}
1418
1419						self.formVisible = false;
1420					} );
1421
1422				},
1423
1424				computed: {
1425					instanceClass: function() {
1426						let classes = [
1427							'jet-reviews-advanced__instance',
1428						];
1429
1430						if ( this.isMounted ) {
1431							classes.push( 'is-mounted' );
1432						}
1433
1434						return classes;
1435					},
1436
1437					reviewsLength: function() {
1438						return this.reviewsList.length;
1439					},
1440
1441					reviewsListEmpty: function() {
1442						return 0 === this.reviewsList.length ? true : false;
1443					},
1444
1445					preparedFields: function() {
1446
1447						let rawFields = this.reviewTypeData.fields,
1448						    preparedFields = [];
1449
1450						for ( let fieldData of rawFields ) {
1451							preparedFields.push( {
1452								field_label: fieldData.label,
1453								field_value: +fieldData.max,
1454								field_step: +fieldData.step,
1455								field_max: +fieldData.max,
1456							} );
1457						}
1458
1459						return preparedFields;
1460					},
1461
1462					averageRating: function() {
1463						let totalRating = 0;
1464
1465						if ( this.reviewsListEmpty ) {
1466							return 0;
1467						}
1468
1469						totalRating = this.reviewsList.reduce( function( sum, reviewItem ) {
1470							return +reviewItem.rating + sum;
1471						}, 0 );
1472
1473						return Math.round( totalRating / this.reviewsList.length, 1 );
1474					},
1475
1476					averageValue: function() {
1477						let summaryValue = 0;
1478
1479						if ( this.reviewsListEmpty ) {
1480							return 0;
1481						}
1482
1483						for ( let reviewItem of this.reviewsList ) {
1484							let ratingData = reviewItem.rating_data,
1485							    itemSummary = 0;
1486
1487							for ( let ratingItem of ratingData ) {
1488								itemSummary += +ratingItem.field_value
1489							}
1490
1491							summaryValue += Math.round( itemSummary / ratingData.length, 1 )
1492						}
1493
1494						return Math.round( summaryValue / this.reviewsList.length, 1 );
1495					},
1496
1497					averageMax: function() {
1498						let totalMax = 0,
1499						    fields   = this.reviewTypeData.fields;
1500
1501						totalMax = fields.reduce( function( sum, field ) {
1502							return +field.max + sum;
1503						}, 0 );
1504
1505						return Math.round( totalMax / fields.length, 1 );
1506					},
1507
1508					addReviewIcon: function() {
1509						return this.refsHtml.newReviewButtonIcon || false;
1510					},
1511
1512					isUserGuest: function() {
1513						return this.userData.roles.includes( 'guest' );
1514					},
1515
1516					guestId: function() {
1517						let guestId = JetReviews.getLocalStorageData( 'guestId', false );
1518
1519						if ( ! guestId ) {
1520							let guestId = `guest_${ JetReviews.getUniqId() }`;
1521
1522							JetReviews.setLocalStorageData( 'guestId', guestId );
1523
1524							return guestId;
1525						}
1526
1527						return guestId;
1528					},
1529
1530					guestName: function() {
1531						let guestName = JetReviews.getLocalStorageData( 'guestName', false );
1532
1533						if ( ! guestName ) {
1534							JetReviews.setLocalStorageData( 'guestName', '' );
1535
1536							return '';
1537						}
1538
1539						return guestName;
1540					},
1541
1542					guestMail: function() {
1543						let guestMail = JetReviews.getLocalStorageData( 'guestMail', false );
1544
1545						if ( ! guestMail ) {
1546							JetReviews.setLocalStorageData( 'guestMail', '' );
1547
1548							return '';
1549						}
1550
1551						return guestMail;
1552					},
1553
1554					guestReviewedStorageName: function() {
1555						return `reviewed${ JetReviews.capitalizeString( this.sourceData.source ) }Items`;
1556					},
1557
1558					guestRatedStorageName: function() {
1559						return `rated${ JetReviews.capitalizeString( this.sourceData.source ) }Items`;
1560					},
1561
1562					guestNameFieldVisible: function() {
1563						return this.isUserGuest && '' === this.userData.name;
1564					},
1565
1566					guestMailFieldVisible: function() {
1567						return this.isUserGuest && '' === this.userData.mail;
1568					},
1569
1570					paginationVisible: function() {
1571						return this.reviewsTotal > this.options.pageSize;
1572					},
1573
1574				},
1575
1576				methods: {
1577					formVisibleToggle: function() {
1578						this.formVisible = !this.formVisible;
1579					},
1580
1581					getLabelBySlug: function( slug = false ) {
1582
1583						if ( ! slug ) {
1584							return false;
1585						}
1586
1587						if ( ! window.jetReviewPublicConfig.labels.hasOwnProperty( slug ) ) {
1588							return false;
1589						}
1590
1591						return window.jetReviewPublicConfig.labels[ slug ];
1592					},
1593
1594					changePageHandle: function( page ) {
1595						this.reviewsPage = page;
1596						this.getReviews();
1597					},
1598
1599					getReviews: function() {
1600						let self = this;
1601
1602						self.getReviewsProcessing = true;
1603
1604						wp.apiFetch( {
1605							method: 'post',
1606							path: window.jetReviewPublicConfig.getPublicReviewsRoute,
1607							data: {
1608								source: self.sourceData.source,
1609								source_id: self.sourceData.sourceId,
1610								page: self.reviewsPage - 1,
1611								page_size: self.options.pageSize,
1612							},
1613						} ).then( function( response ) {
1614							self.getReviewsProcessing = false;
1615
1616							self.scrollToInstance();
1617
1618							if ( response.success && response.data ) {
1619								self.reviewsList = response.data.list;
1620								self.reviewsTotal = +response.data.total;
1621								self.reviewsAverageRating = +response.data.rating;
1622							} else {
1623								console.log( 'Error' );
1624							}
1625						} );
1626					},
1627
1628					scrollToInstance: function() {
1629						let $instance = $( `#${ this.uniqId }` ),
1630						    offsetTop = $instance.offset().top - 50;
1631
1632						window.scrollTo( {
1633							top: offsetTop,
1634							behavior: 'smooth',
1635						} );
1636					}
1637				}
1638
1639			} );
1640		},
1641
1642		getLocalStorageData: function( _key = false, _default = false ) {
1643			try {
1644				let jetReviewsData = JSON.parse( window.localStorage.getItem( 'jetReviewsData' ) );
1645
1646				if ( _key ) {
1647
1648					if ( jetReviewsData.hasOwnProperty( _key ) ) {
1649						return jetReviewsData[ _key ];
1650					} else {
1651						return _default;
1652					}
1653				}
1654
1655				return jetReviewsData;
1656			} catch ( e ) {
1657				return _default;
1658			}
1659		},
1660
1661		setLocalStorageData: function( key, data ) {
1662			let jetReviewsData = this.getLocalStorageData() || {};
1663
1664			jetReviewsData[ key ] = data;
1665
1666			window.localStorage.setItem( 'jetReviewsData', JSON.stringify( jetReviewsData ) );
1667		},
1668
1669		getUniqId: function() {
1670			return Math.random().toString( 36 ).substr( 2, 9 );
1671		},
1672
1673		capitalizeString: function( string = '' ) {
1674
1675			if ( typeof string !== 'string' ) {
1676				return ''
1677			}
1678
1679			return string.charAt( 0 ).toUpperCase() + string.slice( 1 );
1680		},
1681
1682		placeCaretAtEnd: function( el ) {
1683			el.focus();
1684
1685			if ( 'undefined' !== typeof window.getSelection && 'undefined' !== typeof document.createRange ) {
1686				let range = document.createRange();
1687
1688				range.selectNodeContents( el );
1689				range.collapse( false );
1690
1691				let selection = window.getSelection();
1692
1693				selection.removeAllRanges();
1694				selection.addRange( range );
1695			} else if ( 'undefined' !== typeof document.body.createTextRange ) {
1696				let textRange = document.body.createTextRange();
1697
1698				textRange.moveToElementText( el );
1699				textRange.collapse( false );
1700				textRange.select();
1701			}
1702		},
1703
1704		checkValidEmail: function ( email ) {
1705			var reg = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
1706
1707			return reg.test( email );
1708		},
1709	};
1710
1711	window.JetReviews = JetReviews;
1712
1713	JetReviews.init();
1714
1715}( jQuery, window.jetReviewPublicConfig ) );
1716
1717// Elementor Public Scripts
1718( function( $, elementorFrontend, publicConfig ) {
1719	'use strict';
1720
1721	let JetReviewsElementor = {
1722		init: function() {
1723
1724			var widgets = {
1725				'jet-reviews.default' : JetReviewsElementor.widgetJetReviewsSimple,
1726				'jet-reviews-advanced.default' : JetReviewsElementor.widgetJetReviewsAdvanced,
1727			};
1728
1729			$.each( widgets, function( widget, callback ) {
1730				elementorFrontend.hooks.addAction( 'frontend/element_ready/' + widget, callback );
1731			} );
1732		},
1733
1734		widgetJetReviewsSimple: function( $scope ) {
1735			var $target       = $scope.find( '.jet-review' ),
1736			    settings      = $target.data( 'settings' ),
1737			    $form         = $( '.jet-review__form', $target ),
1738			    $submitButton = $( '.jet-review__form-submit', $target ),
1739			    $removeButton = $( '.jet-review__item-remove', $target ),
1740			    $message      = $( '.jet-review__form-message', $target ),
1741			    $rangeControl = $( '.jet-review__form-field.type-range input', $target ),
1742			    ajaxRequest   = null;
1743
1744			$rangeControl.on( 'input', function( event ) {
1745				var $this         = $( this ),
1746				    $parent       = $this.closest( '.jet-review__form-field' ),
1747				    $currentValue = $( '.current-value', $parent ),
1748				    value         = $this.val();
1749
1750				$currentValue.html( value );
1751			} );
1752
1753			$submitButton.on( 'click.widgetJetReviews', function() {
1754				addReviewHandle();
1755
1756				return false;
1757			} );
1758
1759			$removeButton.on( 'click.widgetJetReviews', function() {
1760				var $this = $( this );
1761
1762				removeReviewHandle( $this );
1763
1764				return false;
1765			} );
1766
1767			function addReviewHandle() {
1768				var now            = new Date(),
1769				    reviewTime     = now.getTime(),
1770				    reviewDate     = new Date( reviewTime ).toLocaleString(),
1771				    sendData       = {
1772					    'post_id': settings['post_id'],
1773					    'review_time': reviewTime,
1774					    'review_date': reviewDate
1775				    },
1776				    serializeArray = $form.serializeObject();
1777
1778				sendData = jQuery.extend( sendData, serializeArray );
1779
1780				ajaxRequest = jQuery.ajax( {
1781					type: 'POST',
1782					url: window.jetReviewPublicConfig.ajax_url,
1783					data: {
1784						'action': 'jet_reviews_add_meta_review',
1785						'data': sendData
1786					},
1787					beforeSend: function( jqXHR, ajaxSettings ) {
1788						if ( null !== ajaxRequest ) {
1789							ajaxRequest.abort();
1790						}
1791
1792						$submitButton.addClass( 'load-state' );
1793					},
1794					error: function( jqXHR, ajaxSettings ) {
1795
1796					},
1797					success: function( data, textStatus, jqXHR ) {
1798
1799						var responseType = data['type'],
1800						    message      = data.message || '';
1801
1802						if ( 'error' === responseType ) {
1803							$submitButton.removeClass( 'load-state' );
1804							$message.addClass( 'visible-state' );
1805
1806							$( 'span', $message ).html( message );
1807						}
1808
1809						if ( 'success' === responseType ) {
1810							location.reload();
1811						}
1812					}
1813				} );
1814			};
1815
1816			function removeReviewHandle( $removeButton ) {
1817				var $reviewItem  = $removeButton.closest( '.jet-review__item' ),
1818				    reviewUserId = $reviewItem.data( 'user-id' ),
1819				    sendData     = {
1820					    'post_id': settings['post_id'],
1821					    'user_id': reviewUserId
1822				    };
1823
1824				ajaxRequest = jQuery.ajax( {
1825					type: 'POST',
1826					url: window.jetReviewPublicConfig.ajax_url,
1827					data: {
1828						'action': 'jet_reviews_remove_review',
1829						'data': sendData
1830					},
1831					beforeSend: function( jqXHR, ajaxSettings ) {
1832						if ( null !== ajaxRequest ) {
1833							ajaxRequest.abort();
1834						}
1835
1836						$removeButton.addClass( 'load-state' );
1837					},
1838					error: function( jqXHR, ajaxSettings ) {
1839
1840					},
1841					success: function( data, textStatus, jqXHR ) {
1842						var successType   = data.type,
1843						    message       = data.message || '';
1844
1845						if ( 'error' == successType ) {
1846
1847						}
1848
1849						if ( 'success' == successType ) {
1850							location.reload();
1851						}
1852					}
1853				} );
1854			};
1855		},
1856
1857		widgetJetReviewsAdvanced: function( $scope ) {
1858			let $target    = $scope.find( '.jet-reviews-advanced' ),
1859			    instanceId = $target.attr( 'id' ),
1860			    uniqid     = $target.data( 'uniqid' ) || false,
1861			    options    = window['jetReviewsWidget' + uniqid] || {};
1862
1863			if ( ! $target[0] || ! uniqid ) {
1864				return;
1865			}
1866
1867			window.JetReviews.createJetReviewAdvancedInstance( instanceId, options );
1868		},
1869	}
1870
1871	$( window ).on( 'elementor/frontend/init', JetReviewsElementor.init );
1872
1873	$.fn.serializeObject = function(){
1874
1875		var self = this,
1876		    json = {},
1877		    push_counters = {},
1878		    patterns = {
1879			    "validate": /^[a-zA-Z][a-zA-Z0-9_-]*(?:\[(?:\d*|[a-zA-Z0-9_-]+)\])*$/,
1880			    "key":      /[a-zA-Z0-9_-]+|(?=\[\])/g,
1881			    "push":     /^$/,
1882			    "fixed":    /^\d+$/,
1883			    "named":    /^[a-zA-Z0-9_-]+$/
1884		    };
1885
1886		this.build = function(base, key, value){
1887			base[key] = value;
1888			return base;
1889		};
1890
1891		this.push_counter = function(key){
1892			if(push_counters[key] === undefined){
1893				push_counters[key] = 0;
1894			}
1895			return push_counters[key]++;
1896		};
1897
1898		$.each($(this).serializeArray(), function(){
1899			// skip invalid keys
1900			if(!patterns.validate.test(this.name)){
1901				return;
1902			}
1903
1904			var k,
1905			    keys = this.name.match(patterns.key),
1906			    merge = this.value,
1907			    reverse_key = this.name;
1908
1909			while((k = keys.pop()) !== undefined){
1910
1911				// adjust reverse_key
1912				reverse_key = reverse_key.replace(new RegExp("\\[" + k + "\\]$"), '');
1913
1914				// push
1915				if(k.match(patterns.push)){
1916					merge = self.build([], self.push_counter(reverse_key), merge);
1917				}
1918
1919				// fixed
1920				else if(k.match(patterns.fixed)){
1921					merge = self.build([], k, merge);
1922				}
1923
1924				// named
1925				else if(k.match(patterns.named)){
1926					merge = self.build({}, k, merge);
1927				}
1928			}
1929
1930			json = $.extend(true, json, merge);
1931		});
1932
1933		return json;
1934	};
1935
1936}( jQuery, window.elementorFrontend, window.jetReviewPublicConfig ) );

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.