/* global wccomCurrentProduct */ ( function( global ) { // Global var for throttling. var throttleWait = false; function trackIt( name, parameters ) { var wccom = global.wccom || {}; var tracks = wccom.fireTracksEvent || function() {}; // eslint-disable-next-line camelcase var product_id = JSON.parse( wccomCurrentProduct ).productId || ''; // eslint-disable-next-line camelcase parameters.product_id = product_id; tracks( name, parameters ); } function trackRatingClick( event ) { var starRating = event.currentTarget.getAttribute( 'for' ).slice( -1 ); trackIt( 'product_review_rating_click', { stars: starRating } ); } function trackRatingSubmit() { trackIt( 'product_review_rating_submit', {} ); } function viewingReviews() { var reviewsContainer = document.getElementById( 'reviews' ); // Check if we already tracked this view. if ( null === reviewsContainer || reviewsContainer.classList.contains( 'tracks-tracked' ) ) { return; } // A buffer to ensure the container is well into view. var reviewContainerBuffer = 150; // get window height var windowHeight = window.innerHeight; // get number of pixels that the document is scrolled var scrollY = window.scrollY || window.pageYOffset; // get current scroll position // (distance from the top of the page to the bottom of the current viewport) var scrollPosition = scrollY + windowHeight; // get element position (distance from the top of the page to the bottom of the element) var elementPosition = reviewsContainer.getBoundingClientRect().top + scrollY + reviewContainerBuffer; // is scroll position greater than element position? (is element in view?) if ( scrollPosition > elementPosition ) { reviewsContainer.classList.add( 'tracks-tracked' ); return true; } return false; } function maybeTrackReviewsView() { if ( viewingReviews() ) { trackIt( 'product_reviews_viewed', {} ); // Once we tracked the view we can remove the event listener. document.removeEventListener( 'scroll', throttledMaybeTrackReviewsView ); } } function trackSortReviews() { var e = document.querySelector( '.wccom-product-ratings__sort-container select' ); trackIt( 'product_reviews_sort_reviews', { sort: e.options[ e.selectedIndex ].text } ); } function trackReviewVoteUp( event ) { var targetElement = event.target || event.srcElement; var properties = {}; if ( 'undefined' !== typeof targetElement.dataset.commentId ) { // eslint-disable-next-line camelcase properties.comment_id = targetElement.dataset.commentId; } trackIt( 'product_review_vote_up', properties ); } function trackReviewVoteDown( event ) { var targetElement = event.target || event.srcElement; var properties = {}; if ( 'undefined' !== typeof targetElement.dataset.commentId ) { // eslint-disable-next-line camelcase properties.comment_id = targetElement.dataset.commentId; } trackIt( 'product_review_vote_down', properties ); } function trackReviewVoteClickListener( event ) { if ( event.target.classList.contains( 'vote-up' ) ) { trackReviewVoteUp( event ); } if ( event.target.classList.contains( 'vote-down' ) ) { trackReviewVoteDown( event ); } } /* * A throttle function to avoid calling scroll event 100's of times in a second, * lodash has a throttle, but is only available via react and not vanilla js. */ function throttle( callback, limit ) { // If we're not waiting if ( ! throttleWait ) { // Execute users function callback(); // Prevent future invocations throttleWait = true; // After a period of time window.setTimeout( function() { // And allow future invocations throttleWait = false; }, limit ); } } function throttledMaybeTrackReviewsView() { throttle( maybeTrackReviewsView, 1000 ); } function init() { Array.prototype.slice.call( document.querySelectorAll( 'label[for^="review_rating_"]' ), ).forEach( function( star ) { star.addEventListener( 'click', trackRatingClick ); } ); var submit = document .querySelector( '.form-contribution button[type="submit"]' ); if ( submit ) { submit.addEventListener( 'click', trackRatingSubmit ); } // Track onchange for the sorting dropdown. const ratingSortMethod = document.querySelector( '.wccom-product-ratings__sort-container .select', ); if ( ratingSortMethod ) { ratingSortMethod.addEventListener( 'change', trackSortReviews ); } // Since reviews are ajax loaded and there is no js event triggered // we use a general click listener on window and then check in the function the class. window.addEventListener( 'click', trackReviewVoteClickListener ); } document.addEventListener( 'DOMContentLoaded', init ); document.addEventListener( 'scroll', throttledMaybeTrackReviewsView ); }( this ) ); ; /* global MutationObserver */ ( function() { var observer; function starChange( event ) { var starRating = parseInt( event.currentTarget.getAttribute( 'for' ).slice( -1 ), 10 ); openForm( starRating ); } function getCurrentRating() { const ratingInput = document.querySelector( '#review_rating_field .input-checkbox:checked' ); if ( ratingInput ) { return ratingInput.value; } return 0; } function openSubmissionForm() { openForm( getCurrentRating() ); } /** * When the submit review form opens it fetches the existing review * and updates form data with the current review state. * * We want to force the selected rating value and to do this, * we listen to changes on #review_attachment_type_field * and update the rating with the selected value. * * We use #review_attachment_type_field because it get's updated after rating is updated. * For reference see: wc-product-reviews-pro-frontend.min.js * * @param {number} starRating Clicked rating value. */ function forceClickedRatingToBeActive( starRating ) { if ( observer ) { observer.disconnect(); } var ratingFieldset = document.getElementById( 'review_attachment_type_field' ); if ( ratingFieldset ) { var config = { attributes: true }; observer = new MutationObserver( function() { const starRatingLabel = document.querySelector( `#review_rating_${ starRating }:not(:checked) ~ label.checkbox[for="review_rating_${ starRating }"]` ); if ( starRatingLabel ) { starRatingLabel.click(); } } ); observer.observe( ratingFieldset, config ); } } function openForm( starRating ) { if ( starRating ) { forceClickedRatingToBeActive( starRating ); } document.getElementById( 'wccom-extension-review__more' ) .removeAttribute( 'hidden' ); document.getElementById( 'review_comment_field' ) .style.display = 'block'; } function cancelReview( event ) { event.preventDefault(); document.getElementById( 'wccom-extension-review__more' ) .setAttribute( 'hidden', '' ); } function init() { if ( ! document.getElementById( 'wccom-extension-review__more' ) ) { return; } Array.prototype.slice.call( document.querySelectorAll( 'label[for^="review_rating_"]' ) ).forEach( function( star ) { star.addEventListener( 'click', starChange ); } ); document.getElementById( 'wccom-extension-review__cancel' ) .addEventListener( 'click', cancelReview ); document .getElementById( 'review_comment_field' ) .classList .remove( 'validate-required' ); Array.prototype.slice.call( document.querySelectorAll( '#reviews .edit-comment' ) ).forEach( function( editButton ) { editButton.addEventListener( 'click', openSubmissionForm ); } ); } document.addEventListener( 'DOMContentLoaded', init ); }() ); ;