Advertisement
kayart

Untitled

Jul 2nd, 2025
195
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 12.79 KB | None | 0 0
  1. <style>
  2.     /*Custom override styles*/
  3. #lipscore-service-review-list {
  4.     padding: 0 5rem 20px;
  5.     overflow: hidden;
  6.     position: relative;
  7.     -webkit-overflow-scrolling: touch;
  8.   }
  9.  
  10.   #lipscore-service-review-list .lipscore-review-list-box-container {
  11.     display: flex;
  12.     position: relative;
  13.     will-change: transform;
  14.     width: max-content;
  15.     cursor: grab;
  16.     user-select: none;
  17.     transition: transform 0.1s ease-out;
  18.   }
  19.  
  20.   #lipscore-service-review-list .lipscore-review-list-box-container:active {
  21.     cursor: grabbing;
  22.   }
  23.  
  24.   #lipscore-service-review-list .lipscore-review-box {
  25.     flex: 0 0 400px;
  26.     height: auto;
  27.     margin: 0 10px;
  28.     padding: 20px;
  29.     background-color: #f2f2f2;
  30.     border-radius: 8px;
  31.     display: flex;
  32.     flex-direction: column;
  33.     transition: transform 0.3s ease, box-shadow 0.3s ease;
  34.     box-shadow: -4px 4px 10px rgba(0, 0, 0, 0.1);
  35.     backface-visibility: hidden;
  36.     will-change: transform;
  37.   }
  38.  
  39.   /* Pause animation on hover */
  40.   #lipscore-service-review-list:hover .lipscore-review-list-box-container {
  41.     animation-play-state: paused;
  42.   }
  43.  
  44.   #lipscore-service-review-list:active {
  45.     cursor: grabbing;
  46.   }
  47.  
  48.   #lipscore-service-review-list::-webkit-scrollbar {
  49.     display: none;
  50.   }
  51.  
  52.   #lipscore-service-review-list .lipscore-review-info-wrapper {
  53.     display: flex;
  54.     flex-direction: column;
  55.   }
  56.  
  57.   #lipscore-service-review-list .lipscore-review-creation-info {
  58.     display: flex;
  59.     flex-direction: column;
  60.     align-items: flex-start;
  61.   }
  62.  
  63.   #lipscore-service-review-list .lipscore-review-author {
  64.     font-size: 14px;
  65.     color: #555;
  66.     font-weight: normal;
  67.     margin-right: 5px;
  68.   }
  69.  
  70.   #lipscore-service-review-list .lipscore-review-date {
  71.     font-size: 16px;
  72.     font-weight: bold;
  73.     color: #555;
  74.     margin-top: 15px;
  75.   }
  76.  
  77.   #lipscore-service-review-list .lipscore-review-rating-stars-wrapper {
  78.     margin-top: 10px;
  79.   }
  80.  
  81.   #lipscore-service-review-list .lipscore-rating-star {
  82.     width: 16px;
  83.     height: 16px;
  84.     margin-right: 2px;
  85.   }
  86.  
  87.   #lipscore-service-review-list .lipscore-review-content {
  88.     margin-top: 15px;
  89.   }
  90.  
  91.   #lipscore-service-review-list .lipscore-review-text {
  92.     font-size: 16px;
  93.     line-height: 1.4;
  94.     color: #000;
  95.     font-weight: normal;
  96.   }
  97.  
  98.   #lipscore-service-review-list .lipscore-show-review-original-text-btn {
  99.     font-size: 12px;
  100.     color: #555;
  101.     font-weight: 300;
  102.     margin-top: 15px;
  103.     background: none;
  104.     border: none;
  105.     padding: 0;
  106.     cursor: pointer;
  107.     text-align: left;
  108.   }
  109.  
  110.   .lipscore-service-review-badge-small-short.lipscore-no-border,
  111.   .lipscore-service-review-badge-small-long.lipscore-no-border {
  112.     padding: 0 3rem;
  113.   }
  114.  
  115.   .lipscore-real-reviews-badge-container {
  116.       text-align: end;
  117.       margin: 5px 0 15px 0;
  118.   }
  119.  
  120.   .lipscore-real-reviews-badge-right {
  121.       display: inline-block;
  122.   }
  123.  
  124.   #lipscore-service-review-list .lipscore-text-muted.lipscore-review-info-delim,
  125.   #lipscore-service-review-list .lipscore-visually-hidden,
  126.   #lipscore-service-review-list
  127.     .lipscore-review-content-wrapper
  128.     > *:not(.lipscore-review-text),
  129.   #lipscore-service-review-list .lipscore-review-footer,
  130.   #lipscore-service-review-list .lipscore-review-media,
  131.   #lipscore-service-review-list .lipscore-review-reply,
  132.   #lipscore-service-review-list .lipscore-review-footer-wrapper,
  133.   #lipscore-service-review-list .lipscore-review-vote-wrapper,
  134.   #lipscore-service-review-list .lipscore-review-flag-wrapper,
  135.   #lipscore-service-review-list .lipscore-review-imported-wrapper,
  136.   #lipscore-service-review-list .lipscore-widget-lang,
  137.   #lipscore-service-review-list .lipscore-paginator {
  138.     display: none !important;
  139.   }
  140.  
  141.   @media (max-width: 768px) {
  142.     #lipscore-service-review-list {
  143.       padding: 0 15px 20px;
  144.       height: auto;
  145.       overflow-x: hidden;
  146.     }
  147.  
  148.     #lipscore-service-review-list .lipscore-review-list-box-container {
  149.       display: flex;
  150.       flex-wrap: nowrap;
  151.       transition: transform 0.3s ease;
  152.       width: 100%;
  153.     }
  154.  
  155.     #lipscore-service-review-list .lipscore-review-box {
  156.       flex: 0 0 calc(100% - 40px);
  157.       width: calc(100% - 40px);
  158.       margin: 0 20px;
  159.       padding: 15px;
  160.     }
  161.      
  162.       .lipscore-service-review-badge-small-short.lipscore-no-border, .lipscore-service-review-badge-small-long.lipscore-no-border {
  163.       padding: 0;
  164.           width: 100%;
  165.           text-align:center;
  166.   }
  167.      
  168.       .lipscore-real-reviews-badge-container {
  169.           text-align: center;
  170.       }
  171.   }
  172. </style>
  173.  
  174. <div id="lipscore-service-review-list"></div>
  175.  
  176. <script>
  177. class InfiniteSlider {
  178.   constructor(containerSelector, options = {}) {
  179.     this.container = document.querySelector(containerSelector);
  180.     if (!this.container) {
  181.       console.error('Container element not found.');
  182.       return;
  183.     }
  184.  
  185.     this.reviews = this.container.innerHTML;
  186.     this.isMobile = this.checkIfMobile();
  187.     this.options = Object.assign(
  188.       {
  189.         speed: 50, // Pixels per second for auto-scroll
  190.         slideSelector: '.lipscore-review-box',
  191.         autoScroll: !this.isMobile, // Set initial autoScroll based on mobile status
  192.       },
  193.       options
  194.     );
  195.     this.totalWidth = 0;
  196.     this.slideWidth = 0;
  197.     this.currentPosition = 0;
  198.     this.isDragging = false;
  199.     this.isHovering = false;
  200.     this.isContainerVisible = true;
  201.     this.isPageVisible = true;
  202.     this.animationFrameId = null;
  203.     this.lastTimestamp = 0;
  204.  
  205.     this.init();
  206.   }
  207.  
  208.   // Update this method to only update isMobile and return the value
  209.   updateMobileStatus() {
  210.     this.isMobile = this.checkIfMobile();
  211.     return this.isMobile;
  212.   }
  213.  
  214.   // Add this method to check if the device is mobile
  215.   checkIfMobile() {
  216.     return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
  217.       navigator.userAgent
  218.     );
  219.   }
  220.  
  221.   // Initialize slider
  222.   init() {
  223.     this.updateContent();
  224.     this.initObservers();
  225.     this.bindEvents();
  226.     this.startAnimation();
  227.   }
  228.  
  229.   // Update content for infinite scroll
  230.   updateContent() {
  231.     this.container.innerHTML = this.reviews + this.reviews;
  232.  
  233.     // Cache total width and slide width
  234.     this.totalWidth = this.container.scrollWidth;
  235.     const slide = this.container.querySelector(this.options.slideSelector);
  236.     if (slide) {
  237.       const slideStyles = window.getComputedStyle(slide);
  238.       this.slideWidth =
  239.         slide.offsetWidth +
  240.         parseFloat(slideStyles.marginLeft) +
  241.         parseFloat(slideStyles.marginRight);
  242.     }
  243.   }
  244.  
  245.   // Update position for infinite scrolling
  246.   updatePosition() {
  247.     if (this.currentPosition >= this.totalWidth / 2) {
  248.       this.currentPosition -= this.totalWidth / 2;
  249.     } else if (this.currentPosition < 0) {
  250.      this.currentPosition += this.totalWidth / 2;
  251.    }
  252.    this.container.style.transform = `translateX(${-this.currentPosition}px)`;
  253.  }
  254.  
  255.  // Animation step function
  256.  step(timestamp) {
  257.    const progress = timestamp - this.lastTimestamp;
  258.    this.lastTimestamp = timestamp;
  259.  
  260.    // Only auto-scroll if it's not a mobile device and other conditions are met
  261.    if (
  262.      !this.isMobile &&
  263.      !this.isDragging &&
  264.      !this.isHovering &&
  265.      this.isContainerVisible &&
  266.      this.isPageVisible &&
  267.      this.options.autoScroll
  268.    ) {
  269.      this.currentPosition += (progress * this.options.speed) / 1000;
  270.      this.updatePosition();
  271.    }
  272.    this.animationFrameId = requestAnimationFrame(this.step.bind(this));
  273.  }
  274.  // Start the animation loop
  275.  startAnimation() {
  276.    this.lastTimestamp = performance.now();
  277.    this.animationFrameId = requestAnimationFrame(this.step.bind(this));
  278.  }
  279.  // Handle dragging
  280.  startDragging(e) {
  281.    e.preventDefault();
  282.    this.isDragging = true;
  283.    this.startX = e.type.includes('mouse') ? e.pageX : e.touches[0].pageX;
  284.    this.scrollLeft = this.currentPosition;
  285.    this.container.style.cursor = 'grabbing';
  286.    this.container.style.transition = 'none';
  287.  }
  288.  stopDragging() {
  289.    if (!this.isDragging) return;
  290.    this.isDragging = false;
  291.    this.container.style.cursor = 'grab';
  292.    this.container.style.transition = 'transform 0.3s ease-out';
  293.    const slideIndex = Math.round(this.currentPosition / this.slideWidth);
  294.    this.currentPosition = slideIndex * this.slideWidth;
  295.    this.updatePosition();
  296.  }
  297.  drag(e) {
  298.    if (!this.isDragging) return;
  299.    e.preventDefault();
  300.    const x = e.type.includes('mouse') ? e.pageX : e.touches[0].pageX;
  301.    const sensitivity = this.isMobile ? 2 : 1;
  302.    const walk = (x - this.startX) * sensitivity;
  303.    this.currentPosition = this.scrollLeft - walk;
  304.    this.updatePosition();
  305.  }
  306.  // Handle resize event with debounce
  307.  resizeHandler() {
  308.    clearTimeout(this.resizeTimeout);
  309.    this.resizeTimeout = setTimeout(() => {
  310.       const wasMobile = this.isMobile;
  311.       const isMobileNow = this.updateMobileStatus();
  312.       if (wasMobile !== isMobileNow) {
  313.         this.options.autoScroll = !isMobileNow;
  314.       }
  315.       this.updateContent();
  316.       this.updatePosition();
  317.     }, 250);
  318.   }
  319.  
  320.   // Initialize observers for visibility and DOM mutations
  321.   initObservers() {
  322.     // Intersection Observer for container visibility
  323.     const observerOptions = {
  324.       root: null,
  325.       threshold: 0,
  326.     };
  327.     this.intersectionObserver = new IntersectionObserver((entries) => {
  328.       entries.forEach((entry) => {
  329.         if (entry.target === this.container) {
  330.           this.isContainerVisible = entry.isIntersecting;
  331.         }
  332.       });
  333.     }, observerOptions);
  334.     this.intersectionObserver.observe(this.container);
  335.  
  336.     // Page visibility API
  337.     document.addEventListener('visibilitychange', () => {
  338.       this.isPageVisible = !document.hidden;
  339.     });
  340.   }
  341.  
  342.   // Bind all necessary events
  343.   bindEvents() {
  344.     // Drag events
  345.     this.container.addEventListener('mousedown', this.startDragging.bind(this));
  346.     this.container.addEventListener(
  347.       'touchstart',
  348.       this.startDragging.bind(this),
  349.       {
  350.         passive: false,
  351.       }
  352.     );
  353.     document.addEventListener('mousemove', this.drag.bind(this));
  354.     document.addEventListener('touchmove', this.drag.bind(this), {
  355.       passive: false,
  356.     });
  357.     document.addEventListener('mouseup', this.stopDragging.bind(this));
  358.     document.addEventListener('touchend', this.stopDragging.bind(this));
  359.  
  360.     // Hover events
  361.     this.container.addEventListener(
  362.       'mouseenter',
  363.       () => (this.isHovering = true)
  364.     );
  365.     this.container.addEventListener(
  366.       'mouseleave',
  367.       () => (this.isHovering = false)
  368.     );
  369.  
  370.     // Window resize
  371.     window.addEventListener('resize', this.resizeHandler.bind(this));
  372.   }
  373.  
  374.   // Cleanup event listeners and observers
  375.   cleanup() {
  376.     cancelAnimationFrame(this.animationFrameId);
  377.  
  378.     this.container.removeEventListener(
  379.       'mousedown',
  380.       this.startDragging.bind(this)
  381.     );
  382.     this.container.removeEventListener(
  383.       'touchstart',
  384.       this.startDragging.bind(this),
  385.       {
  386.         passive: false,
  387.       }
  388.     );
  389.     document.removeEventListener('mousemove', this.drag.bind(this));
  390.     document.removeEventListener('touchmove', this.drag.bind(this), {
  391.       passive: false,
  392.     });
  393.     document.removeEventListener('mouseup', this.stopDragging.bind(this));
  394.     document.removeEventListener('touchend', this.stopDragging.bind(this));
  395.  
  396.     window.removeEventListener('resize', this.resizeHandler.bind(this));
  397.  
  398.     document.removeEventListener(
  399.       'visibilitychange',
  400.       this.visibilityChangeHandler
  401.     );
  402.  
  403.     this.intersectionObserver.unobserve(this.container);
  404.   }
  405. }
  406.  
  407. document.addEventListener('DOMContentLoaded', function () {
  408.   let currentContainer = null;
  409.   let slider = null; // Declare the slider variable at the correct scope
  410.  
  411.   // Initialize slider function
  412.   function initializeSlider(container) {
  413.     if (slider) {
  414.       // Clean up the previous slider if it exists
  415.       slider.cleanup();
  416.     }
  417.     slider = new InfiniteSlider(container, {
  418.       speed: 50, // Custom speed
  419.     });
  420.   }
  421.  
  422.   // MutationObserver to detect changes in the DOM
  423.   const observer = new MutationObserver((mutations) => {
  424.     const newContainer = document.querySelector(
  425.       '#lipscore-service-review-list .lipscore-review-list-box-container'
  426.     );
  427.     if (newContainer && newContainer !== currentContainer) {
  428.      if (currentContainer) {
  429.        if (slider) slider.cleanup(); // Clean up the previous slider before re-initializing
  430.       }
  431.       currentContainer = newContainer;
  432.       initializeSlider('#lipscore-service-review-list .lipscore-review-list-box-container'); // Initialize the slider
  433.     }
  434.   });
  435.  
  436.   // Start observing the document body for changes
  437.   observer.observe(document.body, {
  438.     childList: true,
  439.     subtree: true,
  440.   });
  441. });
  442. </script>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement