( function( $, elementorFrontend, publicConfig ) { 'use strict'; var JetReviews = { eventBus: new Vue(), initedInstance: [], captchaToken: false, init: function() { var widgets = { 'jet-reviews.default' : JetReviews.widgetJetReviewsSimple, 'jet-reviews-advanced.default' : JetReviews.widgetJetReviewsAdvanced, }; $.each( widgets, function( widget, callback ) { elementorFrontend.hooks.addAction( 'frontend/element_ready/' + widget, callback ); }); JetReviews.defineVueComponents(); }, widgetJetReviewsSimple: function( $scope ) { var $target = $scope.find( '.jet-review' ), settings = $target.data( 'settings' ), $form = $( '.jet-review__form', $target ), $submitButton = $( '.jet-review__form-submit', $target ), $removeButton = $( '.jet-review__item-remove', $target ), $message = $( '.jet-review__form-message', $target ), $rangeControl = $( '.jet-review__form-field.type-range input', $target ), ajaxRequest = null; $rangeControl.on( 'input', function( event ) { var $this = $( this ), $parent = $this.closest( '.jet-review__form-field' ), $currentValue = $( '.current-value', $parent ), value = $this.val(); $currentValue.html( value ); } ); $submitButton.on( 'click.widgetJetReviews', function() { addReviewHandle(); return false; } ); $removeButton.on( 'click.widgetJetReviews', function() { var $this = $( this ); removeReviewHandle( $this ); return false; } ); function addReviewHandle() { var now = new Date(), reviewTime = now.getTime(), reviewDate = new Date( reviewTime ).toLocaleString(), sendData = { 'post_id': settings['post_id'], 'review_time': reviewTime, 'review_date': reviewDate }, serializeArray = $form.serializeObject(); sendData = jQuery.extend( sendData, serializeArray ); ajaxRequest = jQuery.ajax( { type: 'POST', url: window.jetReviewPublicConfig.ajax_url, data: { 'action': 'jet_reviews_add_meta_review', 'data': sendData }, beforeSend: function( jqXHR, ajaxSettings ) { if ( null !== ajaxRequest ) { ajaxRequest.abort(); } $submitButton.addClass( 'load-state' ); }, error: function( jqXHR, ajaxSettings ) { }, success: function( data, textStatus, jqXHR ) { var responseType = data['type'], message = data.message || ''; if ( 'error' === responseType ) { $submitButton.removeClass( 'load-state' ); $message.addClass( 'visible-state' ); $( 'span', $message ).html( message ); } if ( 'success' === responseType ) { location.reload(); } } } ); }; function removeReviewHandle( $removeButton ) { var $reviewItem = $removeButton.closest( '.jet-review__item' ), reviewUserId = $reviewItem.data( 'user-id' ), sendData = { 'post_id': settings['post_id'], 'user_id': reviewUserId }; ajaxRequest = jQuery.ajax( { type: 'POST', url: window.jetReviewPublicConfig.ajax_url, data: { 'action': 'jet_reviews_remove_review', 'data': sendData }, beforeSend: function( jqXHR, ajaxSettings ) { if ( null !== ajaxRequest ) { ajaxRequest.abort(); } $removeButton.addClass( 'load-state' ); }, error: function( jqXHR, ajaxSettings ) { }, success: function( data, textStatus, jqXHR ) { var successType = data.type, message = data.message || ''; if ( 'error' == successType ) { } if ( 'success' == successType ) { location.reload(); } } } ); }; }, widgetJetReviewsAdvanced: function( $scope ) { let $target = $scope.find( '.jet-reviews-advanced' ), instanceId = $target.attr( 'id' ), uniqid = $target.data( 'uniqid' ) || false, options = window['jetReviewsWidget' + uniqid] || {}; if ( ! $target[0] || ! uniqid ) { return; } JetReviews.createJetReviewAdvancedInstance( instanceId, options ); }, defineVueComponents: function() { Vue.component( 'jet-reviews-widget-pagination', { template: '#jet-reviews-widget-pagination-template', props: { current: { type: Number, default: 1 }, total: { type: Number, default: 0 }, pageSize: { type: Number, default: 10 }, prevIcon: { type: String, default: '' }, nextIcon: { type: String, default: '' }, customCss: { type: String, default: '' }, }, data() { return { baseClass: 'jet-reviews-widget-pagination', currentPage: this.current, currentPageSize: this.pageSize }; }, watch: { total ( val ) { let maxPage = Math.ceil( val / this.currentPageSize ); if ( maxPage < this.currentPage ) { this.currentPage = ( maxPage === 0 ? 1 : maxPage ); } }, current ( val ) { this.currentPage = val; }, pageSize ( val ) { this.currentPageSize = val; } }, computed: { classesList() { let classesList = [ this.baseClass, ]; if ( this.customCss ) { classesList.push( this.customCss ); } return classesList; }, prevClasses () { return [ `${this.baseClass}__item`, `${this.baseClass}__item--prev`, { [`${this.baseClass}__item--disabled`]: this.currentPage === 1 || false } ]; }, nextClasses () { return [ `${this.baseClass}__item`, `${this.baseClass}__item--next`, { [`${this.baseClass}__item--disabled`]: this.currentPage === this.allPages || false } ]; }, firstPageClasses () { return [ `${this.baseClass}__item`, { [`${this.baseClass}__item--active`]: this.currentPage === 1 } ]; }, lastPageClasses () { return [ `${this.baseClass}__item`, { [`${this.baseClass}__item--active`]: this.currentPage === this.allPages } ]; }, allPages () { const allPage = Math.ceil( this.total / this.currentPageSize ); return ( allPage === 0 ) ? 1 : allPage; }, }, methods: { changePage ( page ) { if ( this.currentPage !== page ) { this.currentPage = page; this.$emit( 'update:current', page ); this.$emit( 'on-change', page ); } }, prev () { const current = this.currentPage; if ( current <= 1 ) { return false; } this.changePage( current - 1 ); }, next () { const current = this.currentPage; if ( current >= this.allPages ) { return false; } this.changePage(current + 1); }, fastPrev () { const page = this.currentPage - 5; if ( page > 0 ) { this.changePage( page ); } else { this.changePage( 1 ); } }, fastNext () { const page = this.currentPage + 5; if ( page > this.allPages ) { this.changePage( this.allPages ); } else { this.changePage( page ); } }, }, } ); Vue.component( 'jet-advanced-reviews-form', { template: '#jet-advanced-reviews-form-template', props: { reviewFields: Array }, data: function() { return ( { reviewSubmiting: false, reviewTitle: '', reviewContent: '', reviewAuthorName: '', reviewAuthorMail: '', messageText: '', fields: this.reviewFields } ); }, mounted: function() { let self = this; Vue.nextTick().then( function () { let reviewContent = self.$refs.reviewContent, textarea = reviewContent.$refs.textarea; textarea.focus(); } ); if ( this.$root.isUserGuest ) { this.reviewAuthorName = JetReviews.getLocalStorageData( 'guestName', '' ); this.reviewAuthorMail = JetReviews.getLocalStorageData( 'guestMail', '' ); } }, computed: { formControlsVisible: function() { if ( this.$root.isUserGuest ) { return this.isValidReviewContent && this.isValidReviewTitle && this.isValidAuthorName && this.isValidAuthorEmail; } return this.isValidReviewContent && this.isValidReviewTitle; }, formMessageVisible: function() { return '' !== this.messageText; }, isValidReviewContent: function() { return '' !== this.reviewContent; }, isValidReviewTitle: function() { return '' !== this.reviewTitle; }, isValidAuthorName: function() { return '' !== this.reviewAuthorName; }, isValidAuthorEmail: function() { return '' !== this.reviewAuthorMail && JetReviews.checkValidEmail( this.reviewAuthorMail ); }, }, methods: { cancelSubmit: function() { JetReviews.eventBus.$emit( 'closeNewReviewForm', { uniqId: this.$root.options.uniqId } ); }, submitReview: function() { let self = this, forSendingData = { source: this.$root.sourceData.source, source_id: this.$root.sourceData.sourceId, title: this.reviewTitle, content: this.reviewContent, author_id: this.$root.userData.id, author_name: this.reviewAuthorName, author_mail: this.reviewAuthorMail, rating_data: this.fields }, recaptchaConfig = publicConfig.recaptchaConfig; // Recaptcha enable check if ( recaptchaConfig.enable ) { window.grecaptcha.ready( function() { grecaptcha.execute( recaptchaConfig.site_key, { action: 'submit_review' } ).then( function( token ) { JetReviews.captchaToken = token; let modifyData = Object.assign( {}, forSendingData, { captcha_token: token } ); self.submitReviewHandle( modifyData ); } ); } ); return false; } this.submitReviewHandle( forSendingData ); }, submitReviewHandle: function( sendData = false ) { let self = this; if ( ! sendData ) { console.warn( 'Empty new review data for sending' ); return false; } this.reviewSubmiting = true; this.messageText = ''; wp.apiFetch( { method: 'post', path: publicConfig.submitReviewRoute, data: sendData, } ).then( function( response ) { response = self.maybeModifyResponce( response ); let responseSuccess = response.success, responseData = response.data, responseMessage = response.message; self.reviewSubmiting = false; self.messageText = responseMessage; if ( self.$root.isUserGuest ) { let guestReviewedItems = JetReviews.getLocalStorageData( self.$root.guestReviewedStorageName, [] ); self.$root.userData.name = self.reviewAuthorName; self.$root.userData.mail = self.reviewAuthorMail; JetReviews.setLocalStorageData( 'guestName', self.reviewAuthorName ); JetReviews.setLocalStorageData( 'guestMail', self.reviewAuthorMail ); if ( responseSuccess && ! guestReviewedItems.includes( self.$root.sourceData.sourceId ) ) { guestReviewedItems.push( self.$root.sourceData.sourceId ); JetReviews.setLocalStorageData( self.$root.guestReviewedStorageName, guestReviewedItems ); } } if ( responseSuccess ) { if ( 'review-created' === response.code ) { JetReviews.eventBus.$emit( 'addReview', { uniqId: self.$root.options.uniqId, reviewData: responseData.item, } ); self.$root.reviewsAverageRating = +responseData.rating; } self.$root.formVisible = false; self.$root.userData.canReview.allowed = false; self.$root.userData.canReview.message = responseMessage; } } ); }, maybeModifyResponce: function( responce = false ) { let code = responce.code; if ( 'need-approve' === code && '' !== this.$root.options.labels.moderatorCheckMessage ) { responce.message = this.$root.options.labels.moderatorCheckMessage; } if ( 'already-created' === code && '' !== this.$root.options.labels.alreadyReviewedMessage ) { responce.message = this.$root.options.labels.alreadyReviewedMessage; } return responce; } } }); Vue.component( 'slider-input', { template: '#jet-advanced-reviews-slider-input-template', props: { value: { type: [ String, Number ], default: '' }, max: { type: [ Number ], default: 5 }, step: { type: [ Number ], default: 1 }, label: { type: [ String, Boolean ], default: false }, }, data: function() { return ( { //currentValue: this.value, } ); }, computed: { valueLabel: function() { return this.value; } }, methods: { handleInput ( event ) { let value = event.target.value; this.$emit( 'input', value ); this.$emit( 'on-change', event ); }, handleChange ( event ) { this.$emit( 'on-input-change', event ); } }, }); Vue.component( 'stars-input', { template: '#jet-advanced-reviews-stars-input-template', props: { value: { type: [ String, Number ], default: '' }, max: { type: [ Number ], default: 5 }, step: { type: [ Number ], default: 1 }, label: { type: [ String, Boolean ], default: false }, }, data: function() { return ( { currentRating: this.value, } ); }, computed: { valueLabel: function() { return `${ this.value }/${ this.max }`; }, rating: function() { return ( this.currentRating / this.max ) * 100; }, preparedRating: function() { if ( 10 > this.rating ) { return 10; } return this.rating; }, emptyIcon: function() { return this.$root.refsHtml.emptyStarIcon || ''; }, emptyIcons: function() { let icon = `
${ this.$root.refsHtml.emptyStarIcon }
` || '
'; return icon.repeat( this.max ); }, filledIcons: function() { let icon = `
${ this.$root.refsHtml.filledStarIcon }
` || '
'; return icon.repeat( this.max ); }, ratingClass: function() { let ratingClass = 'very-high-rating'; if ( this.rating >= 80 && this.rating <= 100 ) { ratingClass = 'very-high-rating'; } if ( this.rating >= 60 && this.rating <= 79 ) { ratingClass = 'high-rating'; } if ( this.rating >= 40 && this.rating <= 59 ) { ratingClass = 'medium-rating'; } if ( this.rating >= 22 && this.rating <= 39 ) { ratingClass = 'low-rating'; } if ( this.rating >= 0 && this.rating <= 21 ) { ratingClass = 'very-low-rating'; } return ratingClass; } }, methods: { ratingClick( rating ) { this.currentRating = rating; this.$emit( 'input', rating ); }, ratingMouseOver( rating ) { this.currentRating = rating; }, ratingMouseOut() { this.currentRating = this.value; }, }, }); Vue.component( 'jet-advanced-reviews-item', { template: '#jet-advanced-reviews-item-template', props: { itemData: Object }, data: function() { return ( { commentFormVisible: false, commentText: '', commentAuthorName: '', commentAuthorMail: '', commentSubmiting: false, approvalSubmiting: false, parentComment: 0, commentsVisible: false, responseMessage: '', detailsVisibleState: false } ); }, mounted: function() { if ( this.$root.isUserGuest ) { this.commentAuthorName = JetReviews.getLocalStorageData( 'guestName', '' ); this.commentAuthorMail = JetReviews.getLocalStorageData( 'guestMail', '' ); let guestReviewRatedData = JetReviews.getLocalStorageData( this.$root.guestRatedStorageName, {} ); if ( guestReviewRatedData.hasOwnProperty( this.itemData.id ) ) { this.$set( this.itemData, 'approval', guestReviewRatedData[ this.itemData.id ] ); } } }, computed: { isDetailsFieldsAvaliable: function() { return 1 < this.itemData.rating_data.length; }, detailsVisible: function() { return this.isDetailsFieldsAvaliable && this.detailsVisibleState; }, averageRatingVisible: function() { return 'average' === this.$root.options.reviewRatingType; }, detailsRatingVisible: function() { return 'details' === this.$root.options.reviewRatingType; }, authorVerificationData: function() { return 0 !== this.itemData.verifications.length ? this.itemData.verifications : false; }, isCommentsEmpty: function() { return 0 === this.itemData.comments.length; }, isCommentsVisible: function() { return !this.isCommentsEmpty && this.commentsVisible; }, itemCommentsCount: function() { let itemCommentsCount = false; itemCommentsCount = this.getCommentsCount( this.itemData.comments ); return itemCommentsCount; }, pinnedVisible: function() { return this.itemData.pinned; }, commentControlsVisible: function() { if ( this.$root.isUserGuest ) { return this.isCommentValid && this.isValidAuthorName && this.isValidAuthorEmail; } return this.isCommentValid; }, averageRatingData: function() { let ratingDatalength = this.itemData.rating_data.length, summaryValue = 0, avarageValue = 0, summaryMax = 0, avarageMax = 0; summaryValue = this.itemData.rating_data.reduce( function( accumulator, currentValue ) { return accumulator + +currentValue.field_value; }, 0 ); summaryMax = this.itemData.rating_data.reduce( function( accumulator, currentValue ) { return accumulator + +currentValue.field_max; }, 0 ); avarageValue = Math.round( summaryValue / ratingDatalength ); avarageMax = Math.round( summaryMax / ratingDatalength ); return { rating: Math.round( avarageValue * 100 / avarageMax, 1 ), max: Math.round( avarageMax, 1 ), value: Math.round( avarageValue, 1 ) }; }, addCommentIcon: function() { return this.$root.refsHtml.newCommentButtonIcon || false; }, showCommentsIcon: function() { return this.$root.refsHtml.showCommentsButtonIcon || false; }, pinnedIcon: function() { return this.$root.refsHtml.pinnedIcon || ''; }, likeIcon: function() { let emptyLike = this.$root.refsHtml.reviewEmptyLikeIcon || '', filledLike = this.$root.refsHtml.reviewFilledLikeIcon || ''; return ! this.itemData.approval.like ? emptyLike : filledLike; }, dislikeIcon: function() { let emptyDislike = this.$root.refsHtml.reviewEmptyDislikeIcon || '', filledDislike = this.$root.refsHtml.reviewFilledDislikeIcon || ''; return ! this.itemData.approval.dislike ? emptyDislike : filledDislike; }, userCanComment: function() { return this.$root.sourceData.commentsAllowed && this.$root.userData.canComment.allowed; }, userCanRate: function() { return this.$root.sourceData.approvalAllowed && this.$root.userData.canRate; }, isValidAuthorName: function() { return '' !== this.commentAuthorName; }, isValidAuthorEmail: function() { return JetReviews.checkValidEmail( this.commentAuthorMail ); }, isCommentValid: function() { return '' !== this.commentText; }, }, methods: { showCommentForm: function() { let self = this; this.commentFormVisible = !this.commentFormVisible; if ( this.commentFormVisible ) { Vue.nextTick().then( function () { let commentContent = self.$refs.commentContent, textarea = commentContent.$refs.textarea; textarea.focus(); } ); } }, cancelNewComment: function() { this.commentFormVisible = false; this.responseMessage = ''; }, submitNewComment: function() { let self = this, forSendingData = { source: this.$root.sourceData.source, source_id: this.$root.sourceData.sourceId, parent_id: this.parentComment, review_id: this.itemData.id, author_id: this.$root.userData.id, author_name: this.commentAuthorName, author_mail: this.commentAuthorMail, content: this.commentText, }, recaptchaConfig = publicConfig.recaptchaConfig; // Recaptcha enable check if ( recaptchaConfig.enable ) { window.grecaptcha.ready( function() { grecaptcha.execute( recaptchaConfig.site_key, { action: 'submit_review_comment' } ).then( function( token ) { JetReviews.captchaToken = token; let modifyData = Object.assign( {}, forSendingData, { captcha_token: token } ); self.submitCommentHandler( modifyData ); } ); } ); return false; } this.submitCommentHandler( forSendingData ); }, submitCommentHandler: function( sendData = false ) { let self = this; if ( ! sendData ) { console.warn( 'Empty new comment data for sending' ); return false; } this.commentSubmiting = true; wp.apiFetch( { method: 'post', path: publicConfig.submitReviewCommentRoute, data: sendData, } ).then( function( response ) { self.commentSubmiting = false; self.$root.userData.name = self.commentAuthorName; self.$root.userData.mail = self.commentAuthorMail; JetReviews.setLocalStorageData( 'guestName', self.commentAuthorName ); JetReviews.setLocalStorageData( 'guestMail', self.commentAuthorMail ); if ( response.success ) { self.commentFormVisible = false; self.commentText = ''; self.itemData.comments.unshift( response.data ); self.commentsVisible = true; } else { self.responseMessage = response.message; console.log( response.message ); } } ); }, updateApprovalHandler: function( type ) { let self = this, altType = 'like' === type ? 'dislike' : 'like'; this.approvalSubmiting = true; wp.apiFetch( { method: 'post', path: publicConfig.likeReviewRoute, data: { review_id: self.itemData.id, type: type, inc: ! self.itemData.approval[ type ], current_state: self.itemData.approval, }, } ).then( function( response ) { self.approvalSubmiting = false; if ( response.success ) { self.$set( self.itemData, 'approval', response.data.approval ); self.$set( self.itemData, 'like', response.data.like ); self.$set( self.itemData, 'dislike', response.data.dislike ); if ( self.$root.isUserGuest ) { self.updateGuestApprovalData( self.itemData.id, self.itemData.approval ); } } else { console.log( response.message ); } } ); }, updateGuestApprovalData: function( $reviewId = false, rateData = false ) { let guestReviewRateData = JetReviews.getLocalStorageData( this.$root.guestRatedStorageName, {} ); guestReviewRateData[ $reviewId ] = rateData; JetReviews.setLocalStorageData( this.$root.guestRatedStorageName, guestReviewRateData ); }, toggleCommentsVisible: function() { this.commentsVisible = !this.commentsVisible; }, getCommentsCount: function( comments, initialValue = 0 ) { let total = comments.reduce( ( accumulator, commentData ) => { if ( commentData.hasOwnProperty( 'children' ) && 0 !== commentData.children.length ) { let initialValue = accumulator + 1; return this.getCommentsCount( commentData.children, initialValue ); } else { return accumulator + 1; } }, initialValue ); return total; } } }); Vue.component( 'jet-advanced-reviews-comment', { template: '#jet-advanced-reviews-comment-template', props: { commentData: Object, parentId: Number, parentComments: Array, depth: Number, }, data: function() { return ( { commentsList: this.commentData.children || [], replySubmiting: false, replyFormVisible: false, replyText: '', replyAuthorName: '', replyAuthorMail: '', responseMessage: '' } ); }, mounted: function() { if ( this.$root.isUserGuest ) { this.replyAuthorName = JetReviews.getLocalStorageData( 'guestName', '' ); this.replyAuthorMail = JetReviews.getLocalStorageData( 'guestMail', '' ); } }, computed: { commentClass: function() { return ''; }, formControlsVisible: function() { return this.$root.sourceData.commentsAllowed; }, submitVisible: function() { if ( this.$root.isUserGuest ) { return this.isReplyTextValid && this.isValidAuthorName && this.isValidAuthorEmail; } return this.isReplyTextValid; }, replyIcon: function() { return this.$root.refsHtml.replyButtonIcon || false; }, isValidAuthorName: function() { return '' !== this.replyAuthorName; }, isValidAuthorEmail: function() { return JetReviews.checkValidEmail( this.replyAuthorMail ); }, isReplyTextValid: function() { return '' !== this.replyText; }, authorVerificationData: function() { if ( ! this.commentData.verifications ) { return false; } return 0 !== this.commentData.verifications.length ? this.commentData.verifications : false; }, }, methods: { showReplyForm: function() { let self = this; this.replyFormVisible = !this.replyFormVisible; if ( this.replyFormVisible ) { this.replyText = '' + this.commentData.author.name + ', '; Vue.nextTick().then( function () { let commentText = self.$refs.commentText, textarea = commentText.$refs.textarea; JetReviews.placeCaretAtEnd( textarea ); } ); } }, cancelNewReply: function() { this.replyFormVisible = false; this.responseMessage = ''; }, submitNewReply: function() { let self = this, forSendingData = { source: this.$root.sourceData.source, source_id: this.$root.sourceData.sourceId, parent_id: 0 === this.depth ? this.commentData.id : this.parentId, review_id: this.commentData.review_id, author_id: this.$root.userData.id, author_name: this.replyAuthorName, author_mail: this.replyAuthorMail, content: this.replyText, }, recaptchaConfig = publicConfig.recaptchaConfig; // Recaptcha enable check if ( recaptchaConfig.enable ) { window.grecaptcha.ready( function() { grecaptcha.execute( recaptchaConfig.site_key, { action: 'submit_comment_reply' } ).then( function( token ) { JetReviews.captchaToken = token; let modifyData = Object.assign( {}, forSendingData, { captcha_token: token } ); self.submitReplyHandler( modifyData ); } ); } ); return false; } this.submitReplyHandler( forSendingData ); }, submitReplyHandler: function( sendData = false ) { let self = this; if ( ! sendData ) { console.warn( 'Empty review comment data for sending' ); return false; } this.replySubmiting = true; wp.apiFetch( { method: 'post', path: publicConfig.submitReviewCommentRoute, data: sendData, } ).then( function( response ) { self.replySubmiting = false; self.$root.userData.name = self.replyAuthorName; self.$root.userData.mail = self.replyAuthorMail; JetReviews.setLocalStorageData( 'guestName', self.replyAuthorName ); JetReviews.setLocalStorageData( 'guestMail', self.replyAuthorMail ); if ( response.success ) { self.replyFormVisible = false; self.replyText = ''; if ( 0 === self.depth ) { self.commentData.children.unshift( response.data ); } else { self.parentComments.push( response.data ); } } else { self.responseMessage = response.message; } } ); } } }); Vue.component( 'points-field', { template: '#jet-advanced-reviews-point-field-template', props: { before: { type: [ Number, String, Boolean ], default: false }, rating: Number, after: { type: [ Number, String, Boolean ], default: false }, }, data: function() { return ( {} ); }, computed: { isBeforeEmpty: function() { return false === this.before || '' === this.before; }, isAfterEmpty: function() { return false === this.after || '' === this.after; }, preparedRating: function() { if ( 10 > this.rating ) { return 10; } return this.rating; }, ratingClass: function() { let ratingClass = 'very-high-rating'; if ( this.rating >= 80 && this.rating <= 100 ) { ratingClass = 'very-high-rating'; } if ( this.rating >= 60 && this.rating <= 79 ) { ratingClass = 'high-rating'; } if ( this.rating >= 40 && this.rating <= 59 ) { ratingClass = 'medium-rating'; } if ( this.rating >= 22 && this.rating <= 39 ) { ratingClass = 'low-rating'; } if ( this.rating >= 0 && this.rating <= 21 ) { ratingClass = 'very-low-rating'; } return ratingClass; } } }); Vue.component( 'stars-field', { template: '#jet-advanced-reviews-star-field-template', props: { before: { type: [ Number, String, Boolean ], default: false }, rating: Number, after: { type: [ Number, String, Boolean ], default: false }, }, data: function() { return ( {} ); }, computed: { isBeforeEmpty: function() { return ! this.before || '' === this.before; }, isAfterEmpty: function() { return ! this.after || '' === this.after; }, preparedRating: function() { if ( 10 > this.rating ) { return 10; } return this.rating; }, emptyIcons: function() { let icon = `
${ this.$root.refsHtml.emptyStarIcon }
` || '
'; return icon.repeat( 5 ); }, filledIcons: function() { let icon = `
${ this.$root.refsHtml.filledStarIcon }
` || '
'; `` return icon.repeat( 5 ); }, ratingClass: function() { let ratingClass = 'very-high-rating'; if ( this.rating >= 80 && this.rating <= 100 ) { ratingClass = 'very-high-rating'; } if ( this.rating >= 60 && this.rating <= 79 ) { ratingClass = 'high-rating'; } if ( this.rating >= 40 && this.rating <= 59 ) { ratingClass = 'medium-rating'; } if ( this.rating >= 22 && this.rating <= 39 ) { ratingClass = 'low-rating'; } if ( this.rating >= 0 && this.rating <= 21 ) { ratingClass = 'very-low-rating'; } return ratingClass; } }, }); Vue.component( 'html-textarea', { template:'
', props: { value: String, isValid: { type: Boolean, default: true, }, placeholder: { type: String, default: 'Input', }, notValidLabel: { type: String, default: 'This field is required or not valid', }, }, data: function() { return ( { isFocus: false, isEmpty: true, } ); }, computed: { classes: function() { let classes = [ 'jet-reviews-content-editable', !this.isValid ? 'jet-reviews-content-editable--not-valid' : false, this.isFocus ? 'jet-reviews-content-editable--focus' : false, this.isPlaceholder ? 'jet-reviews-content-editable--placeholder' : false, ]; return classes; }, isPlaceholder: function() { if ( this.isFocus || ! this.isEmpty ) { return false; } return true; } }, mounted: function () { this.$el.innerHTML = this.value; }, methods: { updateHTML: function( e ) { this.$emit( 'input', e.target.innerHTML ); if ( 0 === $( this.$refs.textarea ).text().trim().length ) { this.isEmpty = true; } else { this.isEmpty = false; } }, focusHandler: function( e ) { this.$emit( 'focus', e.target ); this.isFocus = true; }, blurHandler: function( e ) { this.$emit( 'blur', e.target ); this.isFocus = false; } } }); }, createJetReviewAdvancedInstance: function( instanceId, options ) { if ( JetReviews.initedInstance.includes( instanceId ) ) { return; } JetReviews.initedInstance.push( instanceId ); let JetReviewAdvancedInstance = new Vue( { el: '#' + instanceId, data: { uniqId: instanceId, options: options, reviewsLoaded: false, getReviewsProcessing: false, reviewsList: [], reviewsPage: 1, reviewsTotal: 0, reviewsAverageRating: 0, userData: options.userData, sourceData: options.sourceData, reviewTypeData: publicConfig.reviewTypeData, formVisible: false, isMounted: false, refsHtml: {}, }, mounted: function() { let self = this, refsHtml = {}; this.isMounted = true; for ( var ref in this.$refs ) { Object.assign( refsHtml, { [ ref ]: this.$refs[ ref ].innerHTML } ); } this.refsHtml = refsHtml; if ( this.isUserGuest ) { this.$set( this.userData, 'id', this.guestId ); this.$set( this.userData, 'name', this.guestName ); this.$set( this.userData, 'mail', this.guestMail ); let guestReviewedItems = JetReviews.getLocalStorageData( this.guestReviewedStorageName, [] ); if ( guestReviewedItems.includes( this.sourceData.sourceId ) ) { this.$set( this.userData.canReview, 'allowed', false ); this.$set( this.userData.canReview, 'message', this.options.labels.alreadyReviewedMessage ); } } if ( this.options.reviewsListData ) { this.reviewsList = this.options.reviewsListData.list; this.reviewsTotal = +this.options.reviewsListData.total; this.reviewsAverageRating = +this.options.reviewsListData.rating; this.reviewsLoaded = true; } else { wp.apiFetch( { method: 'post', path: publicConfig.getPublicReviewsRoute, data: { source: self.sourceData.source, source_id: self.sourceData.sourceId, page: self.reviewsPage - 1, page_size: self.options.pageSize }, } ).then( function( response ) { self.reviewsLoaded = true; if ( response.success && response.data ) { self.reviewsList = response.data.list; self.reviewsTotal = +response.data.total; self.reviewsAverageRating = +response.data.rating; } else { console.log( 'Error' ); } } ); } JetReviews.eventBus.$on( 'addReview', function ( payLoad ) { if ( self.options.uniqId !== payLoad.uniqId ) { return; } self.formVisible = false; let reviewData = payLoad.reviewData; self.reviewsList.unshift( reviewData ); self.reviewsTotal += 1; } ); JetReviews.eventBus.$on( 'closeNewReviewForm', function ( payLoad ) { if ( self.options.uniqId !== payLoad.uniqId ) { return; } self.formVisible = false; } ); }, computed: { instanceClass: function() { let classes = [ 'jet-reviews-advanced__instance', ]; if ( this.isMounted ) { classes.push( 'is-mounted' ); } return classes; }, reviewsLength: function() { return this.reviewsList.length; }, reviewsListEmpty: function() { return 0 === this.reviewsList.length ? true : false; }, preparedFields: function() { let rawFields = this.reviewTypeData.fields, preparedFields = []; for ( let fieldData of rawFields ) { preparedFields.push( { field_label: fieldData.label, field_value: +fieldData.max, field_step: +fieldData.step, field_max: +fieldData.max, } ); } return preparedFields; }, averageRating: function() { let totalRating = 0; if ( this.reviewsListEmpty ) { return 0; } totalRating = this.reviewsList.reduce( function( sum, reviewItem ) { return +reviewItem.rating + sum; }, 0 ); return Math.round( totalRating / this.reviewsList.length, 1 ); }, averageValue: function() { let summaryValue = 0; if ( this.reviewsListEmpty ) { return 0; } for ( let reviewItem of this.reviewsList ) { let ratingData = reviewItem.rating_data, itemSummary = 0; for ( let ratingItem of ratingData ) { itemSummary += +ratingItem.field_value } summaryValue += Math.round( itemSummary / ratingData.length, 1 ) } return Math.round( summaryValue / this.reviewsList.length, 1 ); }, averageMax: function() { let totalMax = 0, fields = this.reviewTypeData.fields; totalMax = fields.reduce( function( sum, field ) { return +field.max + sum; }, 0 ); return Math.round( totalMax / fields.length, 1 ); }, addReviewIcon: function() { return this.refsHtml.newReviewButtonIcon || false; }, isUserGuest: function() { return this.userData.roles.includes( 'guest' ); }, guestId: function() { let guestId = JetReviews.getLocalStorageData( 'guestId', false ); if ( ! guestId ) { let guestId = `guest_${ JetReviews.getUniqId() }`; JetReviews.setLocalStorageData( 'guestId', guestId ); return guestId; } return guestId; }, guestName: function() { let guestName = JetReviews.getLocalStorageData( 'guestName', false ); if ( ! guestName ) { JetReviews.setLocalStorageData( 'guestName', '' ); return ''; } return guestName; }, guestMail: function() { let guestMail = JetReviews.getLocalStorageData( 'guestMail', false ); if ( ! guestMail ) { JetReviews.setLocalStorageData( 'guestMail', '' ); return ''; } return guestMail; }, guestReviewedStorageName: function() { return `reviewed${ JetReviews.capitalizeString( this.sourceData.source ) }Items`; }, guestRatedStorageName: function() { return `rated${ JetReviews.capitalizeString( this.sourceData.source ) }Items`; }, guestNameFieldVisible: function() { return this.isUserGuest && '' === this.userData.name; }, guestMailFieldVisible: function() { return this.isUserGuest && '' === this.userData.mail; }, paginationVisible: function() { return this.reviewsTotal > this.options.pageSize; }, }, methods: { formVisibleToggle: function() { this.formVisible = !this.formVisible; }, getLabelBySlug: function( slug = false ) { if ( ! slug ) { return false; } if ( ! publicConfig.labels.hasOwnProperty( slug ) ) { return false; } return publicConfig.labels[ slug ]; }, changePageHandle: function( page ) { this.reviewsPage = page; this.getReviews(); }, getReviews: function() { let self = this; self.getReviewsProcessing = true; wp.apiFetch( { method: 'post', path: publicConfig.getPublicReviewsRoute, data: { source: self.sourceData.source, source_id: self.sourceData.sourceId, page: self.reviewsPage - 1, page_size: self.options.pageSize, }, } ).then( function( response ) { self.getReviewsProcessing = false; self.scrollToInstance(); if ( response.success && response.data ) { self.reviewsList = response.data.list; self.reviewsTotal = +response.data.total; self.reviewsAverageRating = +response.data.rating; } else { console.log( 'Error' ); } } ); }, scrollToInstance: function() { let $instance = $( `#${ this.uniqId }` ), offsetTop = $instance.offset().top - 50; window.scrollTo( { top: offsetTop, behavior: 'smooth', } ); } } } ); }, getLocalStorageData: function( _key = false, _default = false ) { try { let jetReviewsData = JSON.parse( window.localStorage.getItem( 'jetReviewsData' ) ); if ( _key ) { if ( jetReviewsData.hasOwnProperty( _key ) ) { return jetReviewsData[ _key ]; } else { return _default; } } return jetReviewsData; } catch ( e ) { return _default; } }, setLocalStorageData: function( key, data ) { let jetReviewsData = this.getLocalStorageData() || {}; jetReviewsData[ key ] = data; window.localStorage.setItem( 'jetReviewsData', JSON.stringify( jetReviewsData ) ); }, getUniqId: function() { return Math.random().toString( 36 ).substr( 2, 9 ); }, capitalizeString: function( string = '' ) { if ( typeof string !== 'string' ) { return '' } return string.charAt( 0 ).toUpperCase() + string.slice( 1 ); }, placeCaretAtEnd: function( el ) { el.focus(); if ( 'undefined' !== typeof window.getSelection && 'undefined' !== typeof document.createRange ) { let range = document.createRange(); range.selectNodeContents( el ); range.collapse( false ); let selection = window.getSelection(); selection.removeAllRanges(); selection.addRange( range ); } else if ( 'undefined' !== typeof document.body.createTextRange ) { let textRange = document.body.createTextRange(); textRange.moveToElementText( el ); textRange.collapse( false ); textRange.select(); } }, checkValidEmail: function ( email ) { 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,}))$/; return reg.test( email ); }, }; $( window ).on( 'elementor/frontend/init', JetReviews.init ); $.fn.serializeObject = function(){ var self = this, json = {}, push_counters = {}, patterns = { "validate": /^[a-zA-Z][a-zA-Z0-9_-]*(?:\[(?:\d*|[a-zA-Z0-9_-]+)\])*$/, "key": /[a-zA-Z0-9_-]+|(?=\[\])/g, "push": /^$/, "fixed": /^\d+$/, "named": /^[a-zA-Z0-9_-]+$/ }; this.build = function(base, key, value){ base[key] = value; return base; }; this.push_counter = function(key){ if(push_counters[key] === undefined){ push_counters[key] = 0; } return push_counters[key]++; }; $.each($(this).serializeArray(), function(){ // skip invalid keys if(!patterns.validate.test(this.name)){ return; } var k, keys = this.name.match(patterns.key), merge = this.value, reverse_key = this.name; while((k = keys.pop()) !== undefined){ // adjust reverse_key reverse_key = reverse_key.replace(new RegExp("\\[" + k + "\\]$"), ''); // push if(k.match(patterns.push)){ merge = self.build([], self.push_counter(reverse_key), merge); } // fixed else if(k.match(patterns.fixed)){ merge = self.build([], k, merge); } // named else if(k.match(patterns.named)){ merge = self.build({}, k, merge); } } json = $.extend(true, json, merge); }); return json; }; }( jQuery, window.elementorFrontend, window.jetReviewPublicConfig ) );