( 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 ) );