What our clients say…
IMBED
"use strict";
if (!Element.prototype.matches) {
    Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
}
(function () {
    let script = document.currentScript;
    let container;
    if (typeof script === 'undefined') {
        let scriptTags = document.getElementsByTagName('script');
        let scriptFound = false;
        for (let i = scriptTags.length - 1; i >= 0 && !scriptFound; i--) {
            if (scriptTags[i].src.indexOf('widgetAdv.min.js') >= 0) {
                script = scriptTags[i];
                scriptFound = true;
            }
        }
    }
    container = script.parentElement;
    let config = {
        layout: '',
        cssPrefix: 'revwid-',
        mobileBreakpoint: 1024,
        carouselSwipeBuffer: 75,
        readMoreLimit: 455,
        cssPath: getCssPath(),
    };
    let stylesheet;
    let baseUrl = container.dataset.url;
    let businessId = parseInt(container.dataset.bid);
    let businessIds = container.dataset.bid; // multi location widget
    let totalPages = 0;
    let socialLogos = {};
    let widget = {
        cssLoaded: false,
        unique: config.cssPrefix + Math.random().toString(36).substr(2, 9),
        additionalId: container.hasAttribute('data-aid') ? container.getAttribute('data-aid') : false,
        preview: container.hasAttribute('data-preview'),
        masonryTimeout: null,
        jsonLd: container.dataset.hasOwnProperty('jsonld') ? container.dataset.jsonld : 1
    };
    container.setAttribute('data-unique', widget.unique);
    function getCssPath() {
        return container.hasAttribute('data-css') ? container.getAttribute('data-css') : 'https://widget.reviewability.com/css/widgetAdv.min.css';
    }
    function initWidget(divContainer, json) {
        if (!widget.cssLoaded) {
            setTimeout(function () {
                initWidget(divContainer, json);
            }, 100);
            return;
        }
        if (json.content.search('data-widget-layout="dataOnly"') !== -1) {
            stylesheet.parentNode.removeChild(stylesheet);
        }
        divContainer.innerHTML += json.content;
        // Set the container for this widget to our container property
        widget.container = getContainerElement();
        // Store the layout type for this widget (retrieved via data value on the container).
        // Some functionality is unique to the layout type. Valid options: full, vertical, horizontal
        config.layout = widget.container.dataset.widgetLayout;
        if (config.layout === 'horizontal') {
            config.readMoreLimit = 200;
        }
        widget.reviewContainerWidth = 0;
        widget.touchStartX = 0;
        widget.touchStartY = 0;
        widget.touchEndX = 0;
        widget.touchEndY = 0;
        widget.slideToLast = false;
        widget.reviews = "";
        widget.ui = {
            reviewContainer: "",
            filterButton: "",
            filterSelects: "",
            boxes: "",
            painationArrowNext: "",
            painationArrowPrevious: "",
        };
        /**
         * Settings for the carousel. Only the 'horizontal' layout uses the carousel.
         */
        widget.carousel = {
            reviewsPerSlide: 3,
            currentIndex: 0,
            previousIndex: 0,
            ui: {
                arrowNext: "",
                arrowPrevious: "",
                scrollableArea: "",
            }
        };
        /**
         * Initialize the core widget by setting values and binding listeners
         */
        widget.init = function () {
            // Attach event listers to the widget's UI elements
            attachListeners();
            // Set the reviews
            widget.reviews = widget.container.querySelectorAll('.js-review');
            // In order for our flexbox masonry effect to properly wrap two columns on 'full' layout we need to give the container an
            // explicit height. This is called multiple times, so scoping it to the 'full' layout only occurs in the function.
            widget.setReviewContainerProperties();
            if (config.layout == 'horizontal') {
                widget.initCarousel();
                // Set the box height explicilty on 'horizontal' view so that all the boxes are the same height
                widget.setBoxHeight();
            }
        };
        /**
         * Initialize the carousel. This should only be called if the widget uses the carousel (currently only "horizontal" layout does)
         */
        widget.initCarousel = function () {
            widget.setReviewContainerWidthValue();
            setReviewsPerSlide();
            widget.carousel.ui.arrowNext = widget.container.querySelector('.js-carousel-next-arrow');
            widget.carousel.ui.arrowPrevious = widget.container.querySelector('.js-carousel-previous-arrow');
            widget.carousel.ui.scrollableArea = widget.container.querySelector('.js-scrollable-area');
            widget.carousel.ui.arrowNext.addEventListener('click', function (e) {
                widget.carousel.goToNextSlide();
            });
            widget.carousel.ui.arrowPrevious.addEventListener('click', function (e) {
                widget.carousel.goToPreviousSlide();
            });
            widget.carousel.ui.scrollableArea.addEventListener('touchstart', function (event) {
                widget.touchStartX = event.changedTouches[0].screenX;
                widget.touchStartY = event.changedTouches[0].screenY;
            }, false);
            widget.carousel.ui.scrollableArea.addEventListener('touchend', function (event) {
                widget.touchEndX = event.changedTouches[0].screenX;
                widget.touchEndY = event.changedTouches[0].screenY;
                handleSwipe();
            }, false);
        };
        /**
         * Get the containing element for this review widget. We'll assume the script tag is nested within the container.
         */
        function getContainerElement() {
            if (typeof container !== 'undefined') {
                return container.querySelector('.js-widget-container');
            } else {
                let scriptTags = document.getElementsByTagName('script');
                let containerTag = scriptTags[scriptTags.length - 1].parentNode;
                return containerTag.querySelector('.js-widget-container');
            }
        }
        /**
         * Attach listeners to widget DOM elements and window events
         */
        function attachListeners() {
            // Bind main UI elements to the elements within this review widget's context
            widget.ui.reviewContainer = widget.container.querySelector('.js-review-container');
            widget.ui.boxes = widget.container.querySelectorAll('.js-box'); // only used if we are forcing review boxes to be same height. Per update it's not needed at this time.
            widget.ui.filterContainer = widget.container.querySelector('.js-filter-container');
            widget.ui.filterButton = widget.container.querySelector('.js-filter-button');
            widget.ui.painationArrowNext = widget.container.querySelector('.js-next-arrow');
            widget.ui.painationArrowPrevious = widget.container.querySelector('.js-previous-arrow');
            // Adjust widget element widths & heights as needed when the window is resized
            window.addEventListener('resize', function (event) {
                if (config.layout === 'full') {
                    widget.setReviewContainerProperties();
                }
                if (config.layout === 'horizontal') {
                    widget.setBoxHeight();
                    widget.setReviewContainerWidthValue();
                    setReviewsPerSlide();
                }
            });
            document.addEventListener('click', function (event) {
                if (isShowingFilterMenu() && !widget.ui.filterContainer.contains(event.target)) {
                    widget.ui.filterContainer.classList.remove(config.cssPrefix + 'show-invisibles');
                    widget.ui.filterButton.classList.remove(config.cssPrefix + 'is-active');
                }
            });
            // This is a bit of a hack. By listening to touch events we can ensure the "Filter" link closes on mobile when a user clicks away from it
            widget.container.addEventListener('touchstart', function (event) {
            }, false);
            widget.ui.filterButton.addEventListener('click', function (event) {
                widget.ui.filterContainer.classList.toggle(config.cssPrefix + 'show-invisibles');
                widget.ui.filterButton.classList.toggle(config.cssPrefix + 'is-active');
            });
        }
        /**
         * This is used for carousel only - we need to know the width of a slide so that we can transition as a user navigates the carousel
         */
        widget.setReviewContainerWidthValue = function () {
            widget.reviewContainerWidth = widget.ui.reviewContainer.clientWidth;
        };
        /**
         * This is used on 'full' layouts only. We need to set an explicit height for the container so that our flexbox will wrap
         */
        widget.setReviewContainerProperties = function () {
            // Only set the container height on non-mobile views.
            // For mobile we will just list everything as one column and can have an auto height
            if (config.layout === 'full') {
                doMasonry();
                if (widget.masonryTimeout) {
                    window.clearTimeout(widget.masonryTimeout);
                }
                widget.masonryTimeout = setTimeout(doMasonry, 50);
            }
            // Add an 'is-small-container' class to the widget if the viewport isn't mobile, but it is within a smaller container
            if (isSmallContainer() && (config.layout == 'full' || config.layout == 'horizontal')) {
                widget.container.classList.add(config.cssPrefix + 'is-small-container');
            } else {
                widget.container.classList.remove(config.cssPrefix + 'is-small-container');
            }
        };
        /**
         * Not currently used. This would ensure each review box is the same height
         */
        widget.setBoxHeight = function () {
            /*
            if (config.layout == 'horizontal') {
                setBoxHeightValues(getMaxBoxHeightValue());
            }
            */
            return false;
        };
        /**
         * Widget Carousel: Go to a specific slide
         */
        widget.carousel.goToIndex = function (index) {
            if (index == widget.carousel.previousIndex) {
                return;
            }
            widget.carousel.previousIndex = index;
            var offset = -(index * (widget.reviewContainerWidth - (isMobile() ? 32 : 0)));
            widget.ui.reviewContainer.style.setProperty('transform', 'translateX(' + offset + 'px)', 'important');
        };
        /**
         * Widget Carousel: Return whether the user is viewing the last slide
         */
        widget.carousel.isOnLastSlide = function () {
            return (widget.carousel.currentIndex + 1) >= Math.ceil(widget.reviews.length / widget.carousel.reviewsPerSlide);
        };
        /**
         * Widget Carousel: Return whether the user is viewing the first slide
         */
        widget.carousel.isOnFirstSlide = function () {
            return widget.carousel.currentIndex === 0;
        };
        widget.getPageNumber = function () {
            return parseInt(widget.container.querySelector('.revwid-pagination-link.revwid-is-active').dataset.page);
        };
        widget.isOnFirstPage = function () {
            return widget.getPageNumber() === 1;
        };
        widget.isOnLastPage = function () {
            return widget.getPageNumber() === totalPages;
        };
        /**
         * Widget Carousel: Advance the user to the next slide if able
         */
        widget.carousel.goToNextSlide = function () {
            widget.slideToLast = false;
            if (!widget.carousel.isOnLastSlide()) {
                widget.carousel.currentIndex++;
                widget.carousel.goToIndex(widget.carousel.currentIndex);
            } else {
                widget.container.querySelectorAll(".revwid-pagination-list .revwid-is-right-arrow")[0].click();
            }
            setCarouselDisabledStatus();
        };
        /**
         * Widget Carousel: Move the user to the previous slide if able
         */
        widget.carousel.goToPreviousSlide = function () {
            if (!widget.carousel.isOnFirstSlide()) {
                widget.slideToLast = false;
                widget.carousel.currentIndex--;
                widget.carousel.goToIndex(widget.carousel.currentIndex);
            } else {
                widget.slideToLast = true;
                widget.container.querySelectorAll(".revwid-pagination-list .revwid-is-left-arrow")[0].click();
            }
            setCarouselDisabledStatus();
        };
        /**
         * Widget Carousel: Disable / Enable carousel previous & next arrows links as necessary
         */
        function setCarouselDisabledStatus() {
            if (widget.carousel.isOnLastSlide() && widget.isOnLastPage()) {
                widget.carousel.ui.arrowNext.classList.add(config.cssPrefix + 'is-disabled');
            } else {
                widget.carousel.ui.arrowNext.classList.remove(config.cssPrefix + 'is-disabled');
            }
            if (widget.carousel.isOnFirstSlide() && widget.isOnFirstPage()) {
                widget.carousel.ui.arrowPrevious.classList.add(config.cssPrefix + 'is-disabled');
            } else {
                widget.carousel.ui.arrowPrevious.classList.remove(config.cssPrefix + 'is-disabled');
            }
        }
        /**
         * Widget Carousel: Allow swiping left / right to traverse the carousel on mobile views
         */
        function handleSwipe() {
            if (
                (Math.abs(widget.touchEndY - widget.touchStartY) < 20 || widget.touchStartY == 0)
                && Math.abs(widget.touchEndX - widget.touchStartX) > 10
            ) {
                if (widget.touchEndX + config.carouselSwipeBuffer < widget.touchStartX) {
                    widget.carousel.goToNextSlide();
                }
                if (widget.touchEndX - config.carouselSwipeBuffer > widget.touchStartX) {
                    widget.carousel.goToPreviousSlide();
                }
            }
        }
        function setReviewsPerSlide() {
            widget.carousel.reviewsPerSlide = isMobile() ? 1 : 3;
        }
        function isMobile() {
            return window.innerWidth < config.mobileBreakpoint;
        }
        function isSmallContainer() {
            return !isMobile() && widget.container.clientWidth < config.mobileBreakpoint;
        }
        function isShowingFilterMenu() {
            return widget.ui.filterContainer.classList.contains(config.cssPrefix + 'show-invisibles');
        }
        function doMasonry() {
            let reviewsCont = widget.container.querySelector('.js-review-container');
            // Set the container's height on non-mobile
            if (!isMobile()) {
                // set height to big number because if container is smaller than review then review clientHeight will be
                // equal to container height, not real value
                reviewsCont.style.height = 1000;
                let els1 = widget.container.querySelectorAll('.js-is-order-1');
                let els2 = widget.container.querySelectorAll('.js-is-order-2');
                let column1Height = 0, column2Height = 0;
                if (els1.length > 0) {
                    if (els1.length === 1) {
                        column1Height = els1[0].clientHeight;
                    } else {
                        forEach(els1, function (a) {
                            column1Height += a.clientHeight;
                        });
                    }
                } else {
                    column1Height = widget.container.querySelector('.revwid-reviews .revwid-has-text-centered').clientHeight;
                }
                if (els2.length > 0) {
                    if (els2.length === 1) {
                        column2Height = els2[0].clientHeight;
                    } else {
                        forEach(els2, function (a) {
                            column2Height += a.clientHeight;
                        });
                    }
                }
                reviewsCont.style.height = ((column1Height > column2Height ? column1Height : column2Height) + 10) + 'px';
            } else {
                reviewsCont.style.height = 'auto';
            }
            widget.masonryTimeout = null;
        }
        renderReviews(json.reviews.reviews);
        renderPagination(json.reviews.pages, 1);
        widget.init();
    }
    function ajax(data) {
        let $ajax = new XMLHttpRequest();
        let url = data.url;
        let onSuccess = typeof data.success === 'function' ? data.success : function (t) {
        };
        let onError = typeof data.error === 'function' ? data.error : function (t) {
        };
        let type = typeof data.type === 'string' ? data.type : "GET";
        $ajax.onreadystatechange = function () {
            if (this.readyState === 4 && this.status === 200) {
                onSuccess(this.responseText);
            } else if (this.readyState === 4 && this.status >= 300) {
                onError(this.responseText);
            }
        };
        $ajax.open(type, url, true);
        $ajax.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
        $ajax.send();
    }
    function getRndInteger(min, max) {
        return Math.floor(Math.random() * (max - min)) + min;
    }
    function encode(string) {
        try {
            string = encodeURI(string.trim());
        } catch (e) {
            string = escape(string.trim());
        }
        return string;
    }
    function removeEmojis(str) {
        return str.replace(/[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c[\ude32-\ude3a]|[\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff]?/g, '');
    }
    function getShareableUrls(review) {
        let cleanContent = removeEmojis(review.review);
        let desc = (cleanContent.length >= 240) ? cleanContent.slice(0, 240) + '...' : cleanContent;
        let url = baseUrl + '/share/feedback/' + review.id + '/' + getRndInteger(100000, 999999);
        let caption = '';
        if (review.type === 'facebookRecommend') {
            url += '/2';
        } else if (review.type !== 'gfs') {
            url += '/1';
        } else {
            url += '/0';
        }
        for (let $i = 1; $i <= review.rating; $i++) {
            caption += '★';
        }
        caption += ' ' + review.author;
        url = encode(url);
        desc = encode(desc);
        caption = encode(caption);
        return {
            facebook: 'https://www.facebook.com/sharer.php?display=popup&caption=' + caption + '&u=' + url,
            twitter: 'https://twitter.com/share?url=' + url + '&text=' + desc + '&hashtags=Review',
            linkedin: 'https://www.linkedin.com/shareArticle?mini=true&title=' + caption + '&summary='
                + desc + '&source=' + baseUrl + '&url=' + url,
            buffer: 'https://buffer.com/add?text=' + desc + '&url=' + url,
        }
    }
    function renderReview(order, review) {
        let template = container.querySelector('.revwid-review-template').innerHTML;
        let charLimit = config.readMoreLimit;
        let responsesHtml = '';
        let responseClass = config.layout === 'horizontal' ? 'revwid-review-full-text' : '';
        let text = container.querySelector(".revwid-text");
        forEach(review.responses, function (r) {
            responsesHtml += '
' + '' + r.responder + ' - ' + r.date + ''; }); let socialLogo = review.type in socialLogos ? socialLogos[review.type] : false; let starsHtml = '', googleAttributes = ''; if (review.type === 'facebookRecommend') { template = template.replace(/' + r.content + '
.*<\/div>/, "");
            socialLogo = 'facebook' in socialLogos ? socialLogos['facebook'] : false;
            starsHtml = '
'
            : (review.type === 'gfs' ? '' : ' ');
        let limit = 4;
        let limitHalf = parseInt(limit / 2);
        if (total <= 7) {
            for (let $i = 1; $i <= total; $i++) {
                available.push($i);
            }
        } else {
            if (current < limit) {
                for (let $i = 1; $i <= limit; $i++) {
                    available.push($i);
                }
                available.push('...');
                available.push(total);
            } else if (current > total - limit) {
                available.push(1);
                available.push('...');
                for (let $i = total - limit; $i <= total; $i++) {
                    available.push($i);
                }
            } else {
                available.push(1);
                available.push('...');
                for (let $i = current - limitHalf; $i <= current + limitHalf; $i++) {
                    available.push($i);
                }
                available.push('...');
                available.push(total);
            }
        }
        forEach(available, function (e) {
            if (e === '...') {
                lis.push('... ');
            } else {
                lis.push('' + e + ' ');
            }
        });
        lis.push(' ');
        holder.innerHTML = lis.join('');
    }
    function getNoResultsHtml() {
        let text = container.querySelector(".revwid-text");
        let html = "";
        return html;
    }
    function renderReviews(data) {
        let $order = 1;
        let pieces = [];
        forEach(data, function (r) {
            $order++;
            pieces.push(renderReview(($order % 2) + 1, r));
        });
        let reviewsCont = container.querySelector('.revwid-reviews');
        reviewsCont.innerHTML = pieces.length === 0 ? getNoResultsHtml() : pieces.join("");
        forEach(reviewsCont.querySelectorAll('.remove-element'), function (e) {
            e.parentNode.removeChild(e);
        });
        if (widget.container) {
            widget.reviews = widget.container.querySelectorAll('.js-review');
        }
        if (config.layout === 'horizontal') {
            if (widget.slideToLast) {
                widget.slideToLast = false;
                widget.carousel.currentIndex = (widget.reviews.length / widget.carousel.reviewsPerSlide) - 1;
            } else {
                widget.carousel.currentIndex = 0;
            }
            widget.carousel.goToIndex(widget.carousel.currentIndex);
        }
        // Review source logos - after an image asset is loaded let's recalculate the review container height to ensure our grid displays properly
        let logos = reviewsCont.querySelectorAll('img');
        forEach(Array.prototype.slice.call(logos), function (element) {
            if (config.layout === 'full') {
                element.addEventListener('load', function () {
                    widget.setReviewContainerProperties();
                });
            }
            if (config.layout === 'horizontal') {
                equalizeReviewHeaderHeights();
            }
            if (element.complete && config.layout === 'full') {
                widget.setReviewContainerProperties();
            }
        });
    }
    function equalizeReviewHeaderHeights() {
        if (widget.carousel.reviewsPerSlide > 1) {
            const chunks = [];
            const boxesArray = Array.prototype.slice.call(widget.ui.boxes);
            while (boxesArray.length) {
                chunks.push(boxesArray.splice(0, widget.carousel.reviewsPerSlide));
            }
            for (let i = 0; i < chunks.length; i++) {
                const chunk = chunks[i];
                const headers = [];
                let maxHeight = -1;
                for (let j = 0; j < chunk.length; j++) {
                    const header = chunk[j].querySelector('.' + config.cssPrefix + 'review-header');
                    maxHeight = Math.max(maxHeight, header.clientHeight);
                    headers.push(header);
                }
                for (let j = 0; j < headers.length; j++) {
                    headers[j].style.height = maxHeight;
                }
            }
        }
    }
    function appendStylesheet() {
        stylesheet = document.createElement('link');
        stylesheet.setAttribute('rel', 'stylesheet');
        stylesheet.setAttribute('type', 'text/css');
        stylesheet.onload = function () {
            widget.cssLoaded = true;
        };
        stylesheet.setAttribute('href', config.cssPath);
        document.getElementsByTagName('head')[0].appendChild(stylesheet);
    }
    // IE 11 fix for forEach
    function forEach(elements, callable) {
        for (let i = 0; i < elements.length; i++) {
            callable(elements[i]);
        }
    }
    function live(eventType, elementQuerySelector, cb) {
        document.addEventListener(eventType, function (event) {
            let $selector = '[data-unique="' + widget.unique + '"] ' + elementQuerySelector;
            let qs = document.querySelectorAll($selector);
            if (qs) {
                let el = event.target, index = -1;
                while (el && ((index = Array.prototype.indexOf.call(qs, el)) === -1)) {
                    el = el.parentElement;
                }
                if (index > -1) {
                    cb.call(el, event);
                }
            }
        });
    }
    function apllyMainParametersToUrl(parameterBag) {
        if (widget.additionalId) {
            parameterBag.push('aid=' + widget.additionalId);
        }
        if (widget.preview) {
            parameterBag.push('preview=' + widget.preview);
        }
        return parameterBag;
    }
    function getMainUrl() {
        let widgetMainUrlParts = apllyMainParametersToUrl([]);
        return baseUrl
            + '/widget/b-'
            + businessIds
            + '?' + widgetMainUrlParts.join('&');
    }
    var getNextSibling = function (elem, selector) {
        // Get the next sibling element
        var sibling = elem.nextElementSibling;
        var attempt = 0;
        // If there's no selector, return the first sibling
        if (!selector) {
            return sibling;
        }
        // If the sibling matches our selector, use it
        // If not, jump to the next sibling and continue the loop
        while (sibling && attempt < 10) {
            if (sibling.matches(selector)) {
                return sibling;
            }
            sibling = sibling.nextElementSibling;
            attempt++;
        }
    };
    function loadAjaxPage(page, getPages) {
        let orderParts = widget.container.querySelector('[name=revwid-selected-order]').value.split('-'),
            socials = widget.container.querySelector('[name=revwid-selected-social]');
        socials = socials ? socials.value : null;
        let urlParts = [];
        urlParts.push('order=' + orderParts[0]);
        urlParts.push('dir=' + orderParts[1]);
        if (socials !== 'none' && socials !== null && socials !== '') {
            urlParts.push('socials=' + socials);
        }
        if (getPages) {
            urlParts.push('getPages=' + 1);
        }
        urlParts = apllyMainParametersToUrl(urlParts);
        ajax({
            url: baseUrl + '/widget/reviews/b-' + businessIds + '/p-' + page + '?' + urlParts.join('&'),
            success: function (data) {
                let json = JSON.parse(data);
                if (getPages) {
                    totalPages = json.reviews.pages;
                }
                renderReviews(json.reviews.reviews);
                renderPagination(totalPages, page);
                widget.setReviewContainerProperties();
            }
        });
    }
    appendStylesheet();
    live('click', '.revwid-share-buttons a', function (e) {
        e.preventDefault();
        if (this.classList.contains('js-share-icon-close')) {
            return;
        }
        let intWidth = '600',
            intHeight = '400';
        let dualScreenLeft = window.screenLeft ? window.screenLeft : screen.left;
        let dualScreenTop = window.screenTop ? window.screenTop : screen.top;
        let width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
        let height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;
        let left = ((width / 2) - (intWidth / 2)) + dualScreenLeft;
        let top = ((height / 2) - (intHeight / 2)) + dualScreenTop;
        let strTitle = ((typeof this.getAttribute('title') !== 'undefined') ? this.getAttribute('title') : 'Social Share'),
            strParam = 'width=' + intWidth + ',height=' + intHeight + ',resizable=yes, top=' + top + ', left=' + left;
        window.open(this.getAttribute('href'), strTitle, strParam).focus();
    });
    live('click', '.revwid-pagination-link[data-page]', function (e) {
        if (this.classList.contains('revwid-is-active')) {
            return;
        }
        if (config.layout !== 'horizontal') {
            document.querySelector('div[data-unique="' + widget.unique + '"]').scrollIntoView(true);
        }
        loadAjaxPage(this.dataset.page, false);
    });
    live('change', '[name="revwid-selected-social"], [name="revwid-selected-order"]', function (e) {
        loadAjaxPage(1, true);
    });
    live('click', '.revwid-pagination .revwid-pagination-arrow', function (e) {
        let page = parseInt(widget.container.querySelector('.revwid-pagination-link.revwid-is-active').dataset.page);
        if (this.classList.contains('revwid-is-disabled')) {
            return;
        }
        if (this.classList.contains('revwid-is-left-arrow')) {
            page--;
        }
        if (this.classList.contains('revwid-is-right-arrow')) {
            page++;
        }
        if (config.layout !== 'horizontal') {
            document.querySelector('div[data-unique="' + widget.unique + '"]').scrollIntoView(true);
        }
        loadAjaxPage(page, false);
    });
    live('click', '[data-share-tools-for]', function (e) {
        this.classList.toggle(config.cssPrefix + 'is-active');
        e.preventDefault();
    });
    live('click', '.js-read-more', function (e) {
        let id = this.getAttribute('data-review-id');
        let selector = '.revwid-review[data-review-id="' + id + '"]';
        widget.container.querySelector(selector).classList.toggle(config.cssPrefix + 'is-expanded');
        widget.setReviewContainerProperties();
        e.preventDefault();
    });
    function createJsonLdScriptTag(json) {
        let script = document.createElement("script");
        script.className = "json-ld-content";
        script.type = "application/ld+json";
        script.innerText = json.jsonLd;
        container.parentNode.appendChild(script);
    }
    ajax({
        url: getMainUrl(),
        success: function (data) {
            let jsonLd = getNextSibling(container, '.json-ld-content');
            let json = JSON.parse(data);
            if (json.baseUrl) {
                baseUrl = json.baseUrl;
            }
            if (json.legacy) {
                // legacy widget layouts mode:
                container.setAttribute('id', 'e2wget5widget');
                let script = document.createElement("script");
                script.id = 'e2wWidgetScript';
                script.async = true;
                script.type = "text/javascript";
                script.src = 'https://widget.reviewability.com/js/widgetAjax.min.js';
                script.setAttribute('data-src', baseUrl + '/reviews-mobile.js/' + businessIds + '.0');
                script.setAttribute('data-jsonld', widget.jsonLd);
                if (widget.preview) {
                    script.setAttribute('data-preview', 1);
                }
                if (widget.additionalId > 0) {
                    script.setAttribute('data-additionalId', widget.additionalId);
                }
                container.innerHTML = "";
                container.appendChild(script);
            } else {
                socialLogos = json.socials;
                try {
                    if (widget.jsonLd == 1 && jsonLd.matches('.json-ld-content')) {
                        jsonLd.innerHTML = json.jsonLd;
                    }
                } catch (e) {
                    createJsonLdScriptTag(json);
                }
                initWidget(container, json);
                totalPages = json.reviews.pages;
            }
            try {
                if (widget.jsonLd == 0 && jsonLd.matches('.json-ld-content')) {
                    jsonLd.parentNode.removeChild(jsonLd);
                }
            } catch (e) {
                // json ld element not found
            }
        }
    });
})();
'
                + ''
                + (review.rating > 0 ? text.getAttribute("data-translation-yes") : text.getAttribute("data-translation-no"))
                + ' ' + text.getAttribute("data-translation-recommends") + '
'
        } else {
            for (let $i = 1; $i <= review.rating; $i++) {
                starsHtml += ' ';
            }
            if (Math.round(review.rating) !== review.rating) {
                starsHtml += ' ';
            }
            for (let $i = review.rating + 1; $i <= 5; $i++) {
                starsHtml += ' ';
            }
        }
        if (!!review.attributes && !!review.attributesPositive) {
            googleAttributes = '' + (review.attributesPositive === "1" ? text.getAttribute("data-translation-positive") : text.getAttribute("data-translation-critical")) + ': ' + review.attributes.split(',').map(function(i){ let trans = text.getAttribute("data-translation-"+i.toLowerCase()); return !!trans ? trans : i.charAt(0).toUpperCase() + i.slice(1);; }).join(', ') + '
'; } let socialHtml = socialLogo ? '' + review.type + '
');
        let shareUrl = getShareableUrls(review);
        let params = {
            order: order,
            id: review.id,
            stars: starsHtml,
            rating: review.rating,
            social_logo: socialHtml,
            author: review.author,
            date: review.reviewReceived,
            review: review.review,
            responses: responsesHtml,
            remove_read_mode: "remove-element",
            share_fb: shareUrl.facebook,
            share_tt: shareUrl.twitter,
            share_lk: shareUrl.linkedin,
            share_bf: shareUrl.buffer,
            google_attributes: googleAttributes
        };
        let isLongReviewText = params.review.length > charLimit;
        if (isLongReviewText || (config.layout === 'horizontal' && review.responses.length > 0)) {
            params.review_full = params.review;
            params.remove_read_mode = "";
            if (isLongReviewText) {
                params.review = params.review.substr(0, charLimit - 50) + '...';
            }
        }
        for (let key in params) {
            if (params.hasOwnProperty(key)) {
                template = template.split('{*' + key + '*}').join(params[key]);
            }
        }
        return template;
    }
    function renderPagination(total, current) {
        current = parseInt(current);
        total = parseInt(total);
        let holder = container.querySelector('.revwid-pagination-list');
        let lis = [], available = [];
        lis.push('";
        html += text.getAttribute("data-translation-message-no-testimonials") + "
"; html += "" + text.getAttribute("data-translation-message-no-firstReview") + "
"; html += "" + text.getAttribute("data-translation-message-no-firstReview") + "