1/** FOXIZ MAIN SCRIPT */ 2 3/** Ensure RB_VIEWPORT_OBSERVER is available */ 4if (typeof RB_VIEWPORT_OBSERVER === 'undefined') { 5 var RB_VIEWPORT_OBSERVER = { 6 observe: function () { 7 return null; 8 }, 9 unobserve: function () {}, 10 destroy: function () {}, 11 refreshAll: function () {}, 12 has: function () { 13 return false; 14 }, 15 getActiveIds: function () { 16 return []; 17 }, 18 destroyAll: function () {}, 19 }; 20} 21 22var FOXIZ_MAIN_SCRIPT = (function (Module, $) { 23 'use strict'; 24 25 Module.initParams = function () { 26 this.yesStorage = this.isStorageAvailable(); 27 this.themeSettings = typeof foxizParams !== 'undefined' ? foxizParams : {}; 28 this.galleriesData = typeof foxizGalleriesData !== 'undefined' ? foxizGalleriesData : {}; 29 this.ajaxURL = typeof foxizCoreParams !== 'undefined' ? foxizCoreParams.ajaxurl || '' : ''; 30 this.ajaxData = {}; 31 this.siteAccessFlag = false; 32 this._document = $(document); 33 this._body = $('body'); 34 this._window = $(window); 35 this.html = $('html, body'); 36 this.outerHTML = $('html'); 37 this.iOS = /(iPad|iPhone|iPod)/g.test(navigator.userAgent); 38 this.sticky = {}; 39 this.eSticky = {}; 40 this.YTPlayers = {}; 41 this.articleData = []; 42 this.readIndicatorPercent = 0; 43 this.isProgress = false; 44 this.readIndicator = $('#reading-progress'); 45 this.popupNewsletterEl = $('#rb-popup-newsletter'); 46 47 this.personalizeUID = 48 typeof FOXIZ_CORE_SCRIPT !== 'undefined' && FOXIZ_CORE_SCRIPT.personalizeUID !== undefined 49 ? FOXIZ_CORE_SCRIPT.personalizeUID 50 : 'u0'; 51 52 // Unified scroll manager 53 this._scrollHandlers = {}; 54 this._scrollTicking = false; 55 this._scrollListenerActive = false; 56 }; 57 58 /** 59 * Unified Scroll Manager - single listener for all scroll handlers 60 */ 61 Module._onScroll = function () { 62 const self = this; 63 if (!self._scrollTicking) { 64 self._scrollTicking = true; 65 requestAnimationFrame(function () { 66 const handlers = self._scrollHandlers; 67 for (const id in handlers) { 68 if (handlers[id]) handlers[id](); 69 } 70 self._scrollTicking = false; 71 }); 72 } 73 }; 74 75 Module.addScrollHandler = function (id, handler) { 76 this._scrollHandlers[id] = handler; 77 if (!this._scrollListenerActive) { 78 this._scrollListenerActive = true; 79 window.addEventListener('scroll', this._onScroll.bind(this), { passive: true }); 80 } 81 }; 82 83 Module.removeScrollHandler = function (id) { 84 delete this._scrollHandlers[id]; 85 }; 86 87 Module.init = function () { 88 this.initParams(); 89 this.syncLayoutLike(); 90 this.topSpacing(); 91 this.siteAccessDetector(); 92 this.headerDropdown(); 93 this.mobileCollapse(); 94 this.initSubMenuPos(); 95 this.privacyTrigger(); 96 this.popupNewsletter(); 97 this.documentClick(); 98 this.backTop(); 99 this.readIndicatorInit(); 100 this.fontResizer(); 101 this.breakingNews(); 102 this.sequentialGalleryDisplay(); 103 this.sliders(); 104 this.carousels(); 105 this.liveSearch(); 106 this.personalizeBlocks(); 107 this.personalizeCategories(); 108 this.likeToggle(); 109 this.singleInfiniteLoadNext(); 110 this.loginPopup(); 111 this.popupTemplate(); 112 this.loadYoutubeIframe(); 113 this.browserResize(); 114 this.footerSlideUp(); 115 this.cartNotification(); 116 this.newsNotification(); 117 this.tocToggle(); 118 this.delayLoad(); 119 this.showPostComment(); 120 this.replyReview(); 121 this.paginationNextPrev(); 122 this.paginationLoadMore(); 123 this.paginationInfinite(); 124 this.productQuantity(); 125 this.readingCollect(); 126 this.liveBlog(); 127 this.neededReloadFuncs(); 128 }; 129 130 Module.neededReloadFuncs = function () { 131 this.hoverTipsy(); 132 this.scrollToComment(); 133 this.usersRating(); 134 this.singleGallery(); 135 this.floatingVideo(); 136 this.videoPreview(); 137 this.floatingVideoRemove(); 138 this.scrollTableContent(); 139 this.singleScrollRefresh(); 140 this.playerAutoPlay(); 141 this.hoverEffects(); 142 this.highlightShares(); 143 this.galleryLightbox(); 144 this.singleFeaturedLightbox(); 145 this.accordion(); 146 this.resIframeClassic(); 147 this.taxBasedAccordion(); 148 this.scrollBarSlider(); 149 }; 150 151 Module.reInitAll = function () { 152 this._window.trigger('load'); 153 this.syncLayoutLike(); 154 if (typeof FOXIZ_PERSONALIZE !== 'undefined') { 155 FOXIZ_PERSONALIZE.syncPersonalizeLayout(); 156 } 157 if (typeof RB_REACTION !== 'undefined') { 158 RB_REACTION.syncReactLayout(); 159 } 160 this.neededReloadFuncs(); 161 RB_VIEWPORT_OBSERVER.refreshAll(); 162 }; 163 164 /** sync layout & reload features */ 165 Module.reloadBlockFunc = function () { 166 this._window.trigger('load'); 167 168 if (typeof FOXIZ_PERSONALIZE !== 'undefined') { 169 FOXIZ_PERSONALIZE.syncLayoutBookmarks(); 170 } 171 this.syncLayoutLike(); 172 this.videoPreview(); 173 this.hoverTipsy(); 174 RB_VIEWPORT_OBSERVER.refreshAll(); 175 }; 176 177 Module.initElementor = function () { 178 if ('undefined' !== typeof initDarkMode && !FOXIZ_MAIN_SCRIPT.editorDarkModeInit) { 179 FOXIZ_MAIN_SCRIPT.editorDarkModeInit = true; 180 initDarkMode(); 181 } 182 FOXIZ_MAIN_SCRIPT.breakingNews(); 183 FOXIZ_MAIN_SCRIPT.carousels(); 184 FOXIZ_MAIN_SCRIPT.sliders(); 185 }; 186 187 Module.isRTL = function () { 188 return this._body.hasClass('rtl'); 189 }; 190 191 Module.animationFrame = function (callback) { 192 const func = 193 window.requestAnimationFrame || 194 window.mozRequestAnimationFrame || 195 window.webkitRequestAnimationFrame || 196 this.animationFrameFallback; 197 func.call(window, callback); 198 }; 199 200 Module.animationFrameFallback = function (callback) { 201 window.setTimeout(callback, 1000 / 60); 202 }; 203 204 /** 205 * 206 * @returns {boolean} 207 */ 208 Module.isStorageAvailable = function () { 209 let storage; 210 try { 211 storage = window['localStorage']; 212 storage.setItem('__rbStorageSet', 'x'); 213 storage.removeItem('__rbStorageSet'); 214 return true; 215 } catch (e) { 216 return false;
217 } 218 }; 219 220 /** 221 * set localStorage 222 * @param key 223 * @param data 224 */ 225 Module.setStorage = function (key, data) { 226 this.yesStorage && localStorage.setItem(key, typeof data === 'string' ? data : JSON.stringify(data)); 227 }; 228 229 /** 230 * get localStorage 231 * @param key 232 * @param defaultValue 233 * @returns {any} 234 */ 235 Module.getStorage = function (key, defaultValue) { 236 if (!this.yesStorage) return null; 237 const data = localStorage.getItem(key); 238 if (data === null) return defaultValue; 239 try { 240 return JSON.parse(data); 241 } catch (e) { 242 return data; 243 } 244 }; 245 246 /** 247 * delelte localStorage 248 * @param key 249 */ 250 Module.deleteStorage = function (key) { 251 this.yesStorage && localStorage.removeItem(key); 252 }; 253 254 /** 255 * 256 * @param id 257 * @param value 258 * @param ttl 259 * @constructor 260 */ 261 Module.SetTTLStorage = function (id, value, ttl) { 262 const data = { 263 value: value, 264 ttl: Date.now() + ttl * 3600000, 265 }; 266 267 this.setStorage(id, data); 268 }; 269 270 /** 271 * 272 * @param id 273 * @returns {null|*} 274 */ 275 Module.getTTLStorage = function (id) { 276 const data = this.getStorage(id); 277 if (data && Date.now() <= data.ttl) { 278 return data.value; 279 } 280 this.deleteStorage(id); 281 return null; 282 }; 283 284 /** on load */ 285 Module.delayLoad = function () { 286 const self = this; 287 setTimeout(function () { 288 self.stickyNavBar(); 289 self.stickyHeaderBuilder(); 290 }, 100); 291 }; 292 293 /** resize */ 294 Module.browserResize = function () { 295 const self = this; 296 297 self._window.on('resize', function () { 298 self.topSpacing(); 299 self.calcSubMenuPos(); 300 }); 301 }; 302 303 /* ================================ HEADERS ================================ */ 304 Module.hoverTipsy = function () { 305 if (!$.fn.rbTipsy) { 306 return false; 307 } 308 309 this._body.find('[data-copy]').rbTipsy({ 310 title: 'data-copy', 311 fade: true, 312 opacity: 1, 313 trigger: 'hover', 314 gravity: 's', 315 }); 316 317 if (window.innerWidth > 1024) { 318 this._body.find('#site-header [data-title]').rbTipsy({ 319 title: 'data-title', 320 fade: true, 321 opacity: 1, 322 trigger: 'hover', 323 gravity: 'n', 324 }); 325 326 this._body.find('.site-wrap [data-title]').rbTipsy({ 327 title: 'data-title', 328 fade: true, 329 opacity: 1, 330 trigger: 'hover', 331 gravity: 's', 332 }); 333 } 334 }; 335 336 /** font resizer */ 337 Module.fontResizer = function () { 338 const self = this; 339 let size = self.yesStorage ? sessionStorage.getItem('rubyResizerStep') : 1; 340 341 self._body.on('click', '.font-resizer-trigger', function (e) { 342 e.preventDefault(); 343 e.stopPropagation(); 344 size++; 345 if (3 < size) { 346 size = 1; 347 self._body.removeClass('medium-entry-size big-entry-size'); 348 } else { 349 if (2 == size) { 350 self._body.addClass('medium-entry-size').removeClass('big-entry-size'); 351 } else { 352 self._body.addClass('big-entry-size').removeClass('medium-entry-size'); 353 } 354 } 355 356 self.yesStorage && sessionStorage.setItem('rubyResizerStep', size); 357 }); 358 }; 359 360 /** hover */ 361 Module.hoverEffects = function () { 362 const selectors = $('.effect-fadeout'); 363 364 if (selectors.length === 0) { 365 return; 366 } 367 selectors 368 .off('mouseenter mouseleave') 369 .on('mouseenter', function (e) { 370 e.stopPropagation(); 371 const target = $(this); 372 if (!target.hasClass('activated')) { 373 target.addClass('activated'); 374 } 375 }) 376 .on('mouseleave', function () { 377 $(this).removeClass('activated'); 378 }); 379 }; 380 381 Module.videoPreview = function () {
382 let playPromise; 383 384 $('.preview-trigger') 385 .on('mouseenter', function () { 386 const target = $(this); 387 const wrap = target.find('.preview-video'); 388 if (!wrap.hasClass('video-added')) { 389 const video = 390 '<video preload="auto" muted loop><source src="' + 391 wrap.data('source') + 392 '" type="' + 393 wrap.data('type') + 394 '"></video>'; 395 wrap.append(video).addClass('video-added'); 396 } 397 target.addClass('show-preview'); 398 wrap.css('z-index', 3); 399 const el = target.find('video')[0]; 400 if (el) { 401 playPromise = el.play(); 402 } 403 }) 404 .on('mouseleave', function () { 405 const target = $(this); 406 target.find('.preview-video').css('z-index', 1); 407 const el = target.find('video')[0]; 408 if (el && playPromise !== undefined) { 409 playPromise 410 .then((_) => { 411 el.pause(); 412 }) 413 .catch(); 414 } 415 }); 416 }; 417 418 Module.playerAutoPlay = function () { 419 const self = this; 420 const items = $('.is-autoplay'); 421 const nonResIframe = $('.entry-content > iframe'); 422 423 if (items != null && items.length > 0) { 424 items.each(function (index) { 425 const el = $(this); 426 if (!el.hasClass('is-loaded')) { 427 RB_VIEWPORT_OBSERVER.observe('iframe_' + index, { 428 element: el, 429 offset: '70%', 430 once: true, 431 handler: function () { 432 const iframe = el.find('iframe'); 433 self.initAutoPlay(iframe); 434 el.addClass('is-loaded'); 435 }, 436 }); 437 } 438 }); 439 } 440 441 if (nonResIframe != null && nonResIframe.length > 0) { 442 nonResIframe.each(function () { 443 const el = $(this); 444 if (!el.hasClass('is-loaded')) { 445 const iURL = el.attr('src'); 446 if ( 447 iURL.indexOf('youtube.com') > 0 || 448 iURL.indexOf('youtu.be') > 0 || 449 iURL.indexOf('vimeo.com') > 0 450 ) { 451 el.wrap('<div class="rb-ires is-loaded"></div>'); 452 } 453 } 454 }); 455 } 456 }; 457 458 Module.initAutoPlay = function (item) { 459 if (item.length > 0 && undefined !== item[0]) { 460 const src = item[0].src; 461 if (src.indexOf('?') > -1) { 462 item[0].src += '&autoplay=1'; 463 } else { 464 item[0].src += '?autoplay=1'; 465 } 466 } 467 }; 468 469 Module.tocToggle = function () { 470 this._document.on('click', '.toc-toggle', function (e) { 471 e.preventDefault(); 472 e.stopPropagation(); 473 474 const target = $(this); 475 const content = target.parents('.ruby-table-contents').find('.toc-content'); 476 content.toggle(200); 477 target.toggleClass('activate'); 478 }); 479 }; 480 481 /** Header JS functions */ 482 Module.headerDropdown = function () { 483 const self = this; 484 $('.more-trigger').on('click', function (e) { 485 e.preventDefault(); 486 e.stopPropagation(); 487 488 /** re calc menu */ 489 self.calcSubMenuPos(); 490 491 const target = $(this); 492 const holder = target.parents('.header-wrap').find('.more-section-outer'); 493 494 if (!holder.hasClass('dropdown-activated')) { 495 self._body.find('.dropdown-activated').removeClass('dropdown-activated'); 496 holder.addClass('dropdown-activated'); 497 } else { 498 holder.removeClass('dropdown-activated'); 499 } 500 if (target.hasClass('search-btn')) { 501 setTimeout(function () { 502 holder.find('input[type="text"]').focus(); 503 }, 150); 504 } 505 506 return false;
507 }); 508 509 /** search trigger */ 510 $('.search-trigger').on('click', function (e) { 511 e.preventDefault(); 512 e.stopPropagation(); 513 const holder = $(this).parent('.header-dropdown-outer'); 514 if (!holder.hasClass('dropdown-activated')) { 515 self._body.find('.dropdown-activated').removeClass('dropdown-activated'); 516 holder.addClass('dropdown-activated'); 517 setTimeout(function () { 518 holder.find('input[type="text"]').focus(); 519 }, 150); 520 } else { 521 holder.removeClass('dropdown-activated'); 522 } 523 return false; 524 }); 525 526 /** header dropdown */ 527 $('.dropdown-trigger').on('click', function (e) { 528 e.preventDefault(); 529 e.stopPropagation(); 530 const holder = $(this).parent('.header-dropdown-outer'); 531 if (!holder.hasClass('dropdown-activated')) { 532 self._body.find('.dropdown-activated').removeClass('dropdown-activated'); 533 holder.addClass('dropdown-activated'); 534 } else { 535 holder.removeClass('dropdown-activated'); 536 } 537 }); 538 }; 539 540 Module.topSpacing = function () { 541 const self = this; 542 if (self._body.hasClass('top-spacing')) { 543 const height = $('.top-site-ad').outerHeight(); 544 $('.site-outer').css('margin-top', height); 545 } 546 }; 547 548 /** outside click */ 549 Module.documentClick = function () { 550 const self = this; 551 const wrapper = $('.more-section-outer, .header-dropdown-outer, .mobile-collapse, .mfp-wrap'); 552 const inlineSearchForm = $('.is-form-layout'); 553 554 document.addEventListener('click', function (e) { 555 if (!wrapper.is(e.target) && wrapper.has(e.target).length === 0) { 556 wrapper.removeClass('dropdown-activated'); 557 self.outerHTML.removeClass('collapse-activated'); 558 } 559 560 if (!inlineSearchForm.is(e.target) && inlineSearchForm.has(e.target).length === 0) { 561 inlineSearchForm.find('.live-search-response').fadeOut(500); 562 } 563 }); 564 }; 565 566 /** calc mega menu position */ 567 Module.initSubMenuPos = function () { 568 const self = this; 569 let trigger = false; 570 571 /** add delay to ensure image loaded */ 572 setTimeout(function () { 573 self.calcSubMenuPos(); 574 }, 1000); 575 576 /** re calc when hovering */ 577 $('.menu-has-child-mega').on('mouseenter', function () { 578 if (!trigger) { 579 self.calcSubMenuPos(); 580 } 581 trigger = true; 582 }); 583 }; 584 585 Module.calcSubMenuPos = function () { 586 if (window.outerWidth < 1025) { 587 return false; 588 } 589 590 const self = this; 591 const megaParents = $('.menu-has-child-mega'); 592 const headerWrapper = $('#site-header'); 593 594 /** for mega wide */ 595 if (megaParents.length > 0) { 596 megaParents.each(function () { 597 const item = $(this); 598 item.find('.mega-dropdown').css({ 599 width: self._body.width(), 600 left: -item.offset().left, 601 }); 602 item.addClass('mega-menu-loaded'); 603 }); 604 } 605 606 /** sub-menu left right direction */ 607 if (headerWrapper.length > 0) { 608 let headerLeftOffset = headerWrapper.offset().left; 609 let headerWidth = headerWrapper.width(); 610 let headerRightOffset = headerLeftOffset + headerWidth; 611 612 const flexDropdown = $('.flex-dropdown'); 613 614 /** sub menu direction */ 615 const subElements = $('ul.sub-menu'); 616 if (subElements.length > 0) { 617 subElements.each(function () { 618 const item = $(this); 619 let itemLeftOffset = item.offset().left; 620 let itemRightOffset = itemLeftOffset + item.width() + 100; 621 if (itemRightOffset > headerRightOffset) { 622 item.addClass('left-direction'); 623 } 624 }); 625 } 626 627 /** calc dropdown flex width */ 628 if (flexDropdown.length > 0) { 629 flexDropdown.each(function () { 630 const item = $(this); 631 const parentItem = item.parent(); 632 if (parentItem.hasClass('is-child-wide') || item.hasClass('mega-has-left')) { 633 return; 634 } 635 const itemWidth = item.width(); 636 const itemHalfWidth = itemWidth / 2; 637 const parentItemOffset = parentItem.offset().left; 638 const parentHalfWidth = parentItem.width() / 2; 639 const parentItemCenterOffset = parentItemOffset + parentHalfWidth; 640 const rightSpacing = headerRightOffset - parentItemCenterOffset; 641 const leftSpacing = parentItemCenterOffset - headerLeftOffset; 642 643 if (itemWidth >= headerWidth) { 644 item.css({ 645 width: headerWidth - 2, 646 left: -parentItemOffset, 647 }); 648 } else if (itemHalfWidth > rightSpacing) { 649 item.css({ 650 right: -rightSpacing + parentHalfWidth + 1, 651 left: 'auto', 652 }); 653 } else if (itemHalfWidth > leftSpacing) { 654 item.css({ 655 left: -leftSpacing + parentHalfWidth + 1, 656 right: 'auto', 657 }); 658 } else { 659 item.css({ 660 right: 'auto', 661 left: -itemHalfWidth + parentHalfWidth, 662 }); 663 } 664 }); 665 } 666 } 667 }; 668 669 /** 670 * 671 * @returns {boolean} 672 */ 673 Module.stickyNavBar = function () { 674 const self = this; 675 676 /** turn off sticky on editor mode */ 677 if (self._body.hasClass('elementor-editor-active')) { 678 return false;
679 } 680 681 self.sticky.section = $('#sticky-holder'); 682 self.sticky.outer = $('#navbar-outer'); 683 684 if ( 685 (!self._body.hasClass('is-mstick') && !self._body.hasClass('yes-tstick')) || 686 self.sticky.outer.length < 1 || 687 self.sticky.section.length < 1 688 ) { 689 return false; 690 } 691 692 self.sticky.smartSticky = !!self._body.hasClass('is-smart-sticky'); 693 self.sticky.isSticky = false; 694 self.sticky.lastScroll = 0; 695 696 if (self._body.hasClass('yes-tstick')) { 697 self.sticky.isTitleSticky = true; 698 } else { 699 self.sticky.isTitleSticky = 0; 700 } 701 702 self.sticky.additionalOffset = 200; 703 if (window.innerWidth > 1024) { 704 if (self.sticky.isTitleSticky) { 705 self.sticky.additionalOffset = 450; 706 } else { 707 self.sticky.additionalOffset = 0; 708 } 709 } 710 711 if (self._body.hasClass('admin-bar')) { 712 self.sticky.adminBarSpacing = 32; 713 } else { 714 self.sticky.adminBarSpacing = 0; 715 } 716 717 self.sticky.topOffset = self.sticky.section.offset().top; 718 self.sticky.stickySectionHeight = self.sticky.section.outerHeight(); 719 720 self.sticky.outer.css('min-height', self.sticky.outer.outerHeight()); 721 self.sticky.activatePos = 722 self.sticky.topOffset + 1 + self.sticky.stickySectionHeight + self.sticky.additionalOffset; 723 self.sticky.deactivePos = self.sticky.topOffset - self.sticky.adminBarSpacing + self.sticky.additionalOffset; 724 725 // Use unified scroll manager 726 if (self.sticky.smartSticky) { 727 self.addScrollHandler('stickyNav', self.initSmartStickyNavBar.bind(self)); 728 } else { 729 self.addScrollHandler('stickyNav', self.initStickyNavBar.bind(self)); 730 } 731 732 self._window.on('unstickMenu', function () { 733 self.sticky.outer.css('min-height', self.sticky.outer.outerHeight()); 734 self.sticky.stickySectionHeight = self.sticky.section.outerHeight(); 735 self.sticky.topOffset = self.sticky.section.offset().top; 736 self.sticky.activatePos = 737 self.sticky.topOffset + 1 + self.sticky.stickySectionHeight + self.sticky.additionalOffset; 738 self.sticky.deactivePos = 739 self.sticky.topOffset - self.sticky.adminBarSpacing + self.sticky.additionalOffset; 740 }); 741 }; 742 743 Module.initStickyNavBar = function () { 744 const self = this; 745 const scroll = self._window.scrollTop(); 746 747 if (!self.sticky.isSticky && scroll > self.sticky.activatePos) { 748 self.sticky.isSticky = true; 749 self._body.addClass('stick-animated sticky-on'); 750 self.sticky.stickAnimatedTimeout = setTimeout(function () { 751 self._body.removeClass('stick-animated'); 752 }, 200); 753 } else if (self.sticky.isSticky && scroll <= self.sticky.deactivePos) { 754 self.sticky.isSticky = false; 755 self._body.removeClass('sticky-on stick-animated'); 756 self._window.trigger('unstickMenu'); 757 } 758 }; 759 760 Module.initSmartStickyNavBar = function () { 761 const self = this; 762 const scroll = self._window.scrollTop(); 763 764 if (!self.sticky.isSticky && scroll > self.sticky.activatePos && scroll < self.sticky.lastScroll) { 765 self.sticky.isSticky = true; 766 self._body.addClass('stick-animated sticky-on'); 767 self.sticky.stickAnimatedTimeout = setTimeout(function () { 768 self._body.removeClass('stick-animated'); 769 }, 200); 770 } else if (self.sticky.isSticky && (scroll <= self.sticky.deactivePos || scroll > self.sticky.lastScroll)) { 771 self.sticky.isSticky = false; 772 self._body.removeClass('sticky-on stick-animated'); 773 if (scroll <= self.sticky.deactivePos) { 774 self._window.trigger('unstickESection'); 775 } 776 } 777 self.sticky.lastScroll = scroll; 778 }; 779 780 /** header sticky template */ 781 Module.stickyHeaderBuilder = function () { 782 const self = this; 783 784 /** turn off sticky on editor mode */ 785 if (self._body.hasClass('elementor-editor-active')) { 786 return false;
787 } 788 789 let stickySection = $('.header-template .e-section-sticky').first(); 790 const hasTitleSticky = $('body.single-post #s-title-sticky').first(); 791 792 if (stickySection.length < 1) { 793 return false; 794 } 795 796 if (hasTitleSticky.length > 0) { 797 self._body.addClass('yes-tstick'); 798 self.eSticky.isTitleSticky = true; 799 } else { 800 self.eSticky.isTitleSticky = 0; 801 } 802 803 self.eSticky.additionalOffset = 200; 804 if (window.innerWidth > 1024) { 805 if (self.eSticky.isTitleSticky) { 806 self.eSticky.additionalOffset = 450; 807 } else { 808 self.eSticky.additionalOffset = 0; 809 } 810 } 811 812 self.eSticky.smartSticky = !!stickySection.hasClass('is-smart-sticky'); 813 814 /** mobile sticky for header template */ 815 if (window.innerWidth <= 1024) { 816 stickySection.removeClass('e-section-sticky'); 817 stickySection = $('#header-template-holder').addClass('e-section-sticky'); 818 } 819 820 self.eSticky.section = stickySection; 821 self.eSticky.outer = stickySection.parent(); 822 823 self.eSticky.adminBarSpacing = 0; 824 self.eSticky.isSticky = false; 825 self.eSticky.lastScroll = 0; 826 self.eSticky.stickySectionHeight = stickySection.outerHeight(); 827 self.eSticky.topOffset = stickySection.offset().top; 828 829 /** set min height */ 830 if (self._body.hasClass('admin-bar')) { 831 self.eSticky.adminBarSpacing = 32; 832 } 833 self.eSticky.outer.css('min-height', self.eSticky.outer.outerHeight()); 834 self.eSticky.activatePos = 835 self.eSticky.topOffset + 1 + self.eSticky.stickySectionHeight + self.eSticky.additionalOffset; 836 self.eSticky.deactivePos = 837 self.eSticky.topOffset - self.eSticky.adminBarSpacing + self.eSticky.additionalOffset; 838 839 // Use unified scroll manager 840 if (self.eSticky.smartSticky) { 841 self.addScrollHandler('stickyESection', self.initSmartStickyESection.bind(self)); 842 } else { 843 self.addScrollHandler('stickyESection', self.initStickyESection.bind(self)); 844 } 845 846 /** re-calc height values */ 847 self._window.on('unstickESection', function () { 848 self.eSticky.outer.css('min-height', self.eSticky.outer.outerHeight()); 849 self.eSticky.stickySectionHeight = self.eSticky.section.outerHeight(); 850 self.eSticky.topOffset = self.eSticky.section.offset().top; 851 self.eSticky.activatePos = 852 self.eSticky.topOffset + 1 + self.eSticky.stickySectionHeight + self.eSticky.additionalOffset; 853 self.eSticky.deactivePos = 854 self.eSticky.topOffset - self.eSticky.adminBarSpacing + self.eSticky.additionalOffset; 855 }); 856 }; 857 858 Module.initStickyESection = function () { 859 const self = this; 860 const scroll = self._window.scrollTop(); 861 if (!self.eSticky.isSticky && scroll > self.eSticky.activatePos) { 862 self.eSticky.isSticky = true; 863 self._body.addClass('stick-animated sticky-on'); 864 self.eSticky.stickAnimatedTimeout = setTimeout(function () { 865 self._body.removeClass('stick-animated'); 866 }, 200); 867 } else if (self.eSticky.isSticky && scroll <= self.eSticky.deactivePos) { 868 self.eSticky.isSticky = false; 869 self._body.removeClass('sticky-on stick-animated'); 870 self._window.trigger('unstickESection'); 871 } 872 }; 873 874 Module.initSmartStickyESection = function () { 875 const self = this; 876 const scroll = self._window.scrollTop(); 877 878 if (!self.eSticky.isSticky && scroll > self.eSticky.activatePos && scroll < self.eSticky.lastScroll) { 879 self.eSticky.isSticky = true; 880 self._body.addClass('stick-animated sticky-on'); 881 self.eSticky.stickAnimatedTimeout = setTimeout(function () { 882 self._body.removeClass('stick-animated'); 883 }, 200); 884 } else if (self.eSticky.isSticky && (scroll <= self.eSticky.deactivePos || scroll > self.eSticky.lastScroll)) { 885 self.eSticky.isSticky = false;
886 self._body.removeClass('sticky-on stick-animated'); 887 if (scroll <= self.eSticky.deactivePos) { 888 self._window.trigger('unstickESection'); 889 } 890 } 891 892 self.eSticky.lastScroll = scroll; 893 }; 894 895 /** mobileCollapse */ 896 Module.mobileCollapse = function () { 897 const self = this; 898 const $mobileMenuTrigger = $('.mobile-menu-trigger'); 899 const $outerHTML = self.outerHTML; 900 const $mobileSearchForm = $outerHTML.find('.mobile-search-form input[type="text"]'); 901 902 $mobileMenuTrigger.on('click', function (e) { 903 e.preventDefault(); 904 e.stopPropagation(); 905 const target = $(this); 906 907 if (target.hasClass('mobile-search-icon')) { 908 setTimeout(function () { 909 $mobileSearchForm.focus(); 910 }, 100); 911 } 912 913 const isCollapseActivated = $outerHTML.hasClass('collapse-activated'); 914 $outerHTML.toggleClass('collapse-activated', !isCollapseActivated); 915 }); 916 }; 917 918 /** 919 * privacy trigger 920 */ 921 Module.privacyTrigger = function () { 922 const self = this; 923 $('#privacy-trigger').on('click', function (e) { 924 e.preventDefault(); 925 e.stopPropagation(); 926 self.setStorage('RubyPrivacyAllowed', '1'); 927 $('#rb-privacy').slideUp(200, function () { 928 $(this).remove(); 929 }); 930 return false; 931 }); 932 }; 933 934 /** back top */ 935 Module.backTop = function () { 936 if (this._body.hasClass('is-backtop')) { 937 $().UItoTop({ 938 text: '<i class="rbi rbi-darrow-top"></i>', 939 }); 940 } 941 }; 942 943 /** login popup */ 944 Module.loginPopup = function () { 945 const self = this; 946 const form = $('#rb-user-popup-form'); 947 if (form.length < 1) { 948 return false; 949 } 950 this._document.on('click', '.login-toggle', (e) => { 951 e.preventDefault(); 952 e.stopPropagation(); 953 $.magnificPopup.open({ 954 type: 'inline', 955 preloader: false, 956 removalDelay: 400, 957 showCloseBtn: true, 958 closeBtnInside: true, 959 closeOnBgClick: false, 960 items: { 961 src: form, 962 type: 'inline', 963 }, 964 mainClass: 'rb-popup-center', 965 closeMarkup: '<span class="close-popup-btn mfp-close"><span class="close-icon"></span></span>', 966 fixedBgPos: true, 967 fixedContentPos: true, 968 callbacks: { open: () => self.reloadCaptchaPopups() }, 969 }); 970 }); 971 }; 972 973 /** popup template blocks */ 974 Module.popupTemplate = function () { 975 const templateCache = {}; 976 this._document.on('click', '.popup-trigger-btn', (e) => { 977 e.preventDefault(); 978 e.stopPropagation(); 979 980 const target = $(e.target); 981 const templateID = target.data('trigger') || ''; 982 const position = target.data('position') || ''; 983 984 if (!templateCache[templateID]) { 985 const template = $(`#tmpl-${templateID}`); 986 if (template.length === 0) { 987 return; 988 } 989 templateCache[templateID] = template.html(); 990 } 991 $.magnificPopup.open({ 992 type: 'inline', 993 preloader: false, 994 removalDelay: 400, 995 showCloseBtn: true, 996 closeBtnInside: true, 997 closeOnBgClick: true, 998 allowHTMLInTemplate: true, 999 items: { 1000 src: templateCache[templateID], 1001 type: 'inline', 1002 }, 1003 mainClass: `is-template-popup popup-${templateID} ${position}`, 1004 closeMarkup: '<span class="close-popup-btn mfp-close"><span class="close-icon"></span></span>', 1005 fixedBgPos: true, 1006 fixedContentPos: true, 1007 callbacks: { open: () => self.reloadCaptchaPopups() }, 1008 }); 1009 }); 1010 }; 1011 1012 /** newsletter */ 1013 Module.popupNewsletter = function () { 1014 const self = this; 1015 if (self.popupNewsletterEl.length > 0) { 1016 const display = self.popupNewsletterEl.data('display'); 1017 self.newsletterExpired = self.popupNewsletterEl.data('expired'); 1018 self.newsletterDisplayOffset = self.popupNewsletterEl.data('offset');
1019 const delay = self.popupNewsletterEl.data('delay'); 1020 const oldExpired = self.getStorage('RubyNewsletterExpired'); 1021 1022 if (self.newsletterExpired === 0) { 1023 self.deleteStorage('RubyNewsletter'); 1024 } 1025 1026 if (!oldExpired || self.newsletterExpired !== oldExpired) { 1027 self.setStorage('RubyNewsletterExpired', self.newsletterExpired); 1028 self.deleteStorage('RubyNewsletter'); 1029 } 1030 1031 if (!self.getTTLStorage('RubyNewsletter')) { 1032 if (!display || 'scroll' === display) { 1033 self.addScrollHandler('newsletter', self.scrollPopupNewsletter.bind(self)); 1034 } else { 1035 setTimeout(function () { 1036 self.popupNewsletterInit(); 1037 }, delay); 1038 } 1039 } 1040 } 1041 }; 1042 1043 Module.scrollPopupNewsletter = function () { 1044 const self = this; 1045 if (!self.newsletterPopupFlag && self._window.scrollTop() > self.newsletterDisplayOffset) { 1046 self.newsletterPopupFlag = true; 1047 self.removeScrollHandler('newsletter'); 1048 self.popupNewsletterInit(); 1049 } 1050 }; 1051 1052 Module.popupNewsletterInit = function () { 1053 const self = this; 1054 if (self.siteAccessFlag) { 1055 return; 1056 } 1057 1058 if (!self.popupNewsletterEl.hasClass('is-pos-fixed')) { 1059 $.magnificPopup.open({ 1060 type: 'inline', 1061 preloader: false, 1062 closeBtnInside: true, 1063 removalDelay: 400, 1064 showCloseBtn: true, 1065 closeOnBgClick: false, 1066 disableOn: 1024, 1067 items: { 1068 src: '#rb-popup-newsletter', 1069 type: 'inline', 1070 }, 1071 mainClass: 'rb-popup-center', 1072 fixedBgPos: true, 1073 fixedContentPos: true, 1074 closeMarkup: '<span class="close-popup-btn mfp-close"><span class="close-icon"></span></span>', 1075 callbacks: { 1076 open: () => self.reloadCaptchaPopups(), 1077 close: function () { 1078 if (self.siteAccessFlag) { 1079 return; 1080 } 1081 self.SetTTLStorage('RubyNewsletter', 1, self.newsletterExpired * 24); 1082 }, 1083 }, 1084 }); 1085 } else { 1086 self.popupNewsletterEl.removeClass('is-hidden'); 1087 setTimeout(() => { 1088 self.popupNewsletterEl.addClass('yes-show'); 1089 }, 10); 1090 const closeBtn = self.popupNewsletterEl.find('.close-popup-btn'); 1091 closeBtn.on('click', function () { 1092 self.SetTTLStorage('RubyNewsletter', 1, self.newsletterExpired * 24); 1093 self.popupNewsletterEl.removeClass('yes-show'); 1094 setTimeout(() => { 1095 self.popupNewsletterEl.addClass('is-hidden'); 1096 }, 400); 1097 }); 1098 } 1099 }; 1100 1101 /** footer slide up */ 1102 Module.footerSlideUp = function () { 1103 const target = $('#footer-slideup'); 1104 if (target.length > 0) { 1105 const self = this; 1106 self.footerSlideUpExpired = target.data('expired'); 1107 const delay = target.data('delay'); 1108 const oldExpired = self.getStorage('footerSlideUpExpired'); 1109 if (!oldExpired || self.footerSlideUpExpired != oldExpired) { 1110 self.setStorage('footerSlideUpExpired', self.footerSlideUpExpired); 1111 self.deleteStorage('footerSlideUp'); 1112 } 1113 if (!self.getTTLStorage('footerSlideUp')) { 1114 setTimeout(function () { 1115 self.footerSlideUpInit(); 1116 }, delay); 1117 } 1118 /** show hide toggle */ 1119 setTimeout(function () { 1120 self.footerSlideUpToggle(); 1121 }, delay); 1122 } 1123 }; 1124 1125 Module.footerSlideUpToggle = function () { 1126 const self = this; 1127 $('.slideup-toggle') 1128 .off('click') 1129 .on('click', function (e) { 1130 e.preventDefault(); 1131 e.stopPropagation(); 1132 self.footerSlideUpInit(); 1133 return false;
1134 }); 1135 }; 1136 1137 Module.footerSlideUpInit = function () { 1138 if (this._body.hasClass('yes-f-slideup')) { 1139 this._body.removeClass('yes-f-slideup'); 1140 this.SetTTLStorage('footerSlideUp', 1, this.footerSlideUpExpired * 24); 1141 } else { 1142 this._body.addClass('yes-f-slideup'); 1143 this.deleteStorage('footerSlideUp'); 1144 } 1145 }; 1146 1147 /** youtube iframe */ 1148 Module.loadYoutubeIframe = function () { 1149 const self = this; 1150 const blockPlaylist = $('.yt-playlist'); 1151 if (blockPlaylist.length > 0) { 1152 const tag = document.createElement('script'); 1153 tag.src = '//www.youtube.com/iframe_api'; 1154 const firstScriptTag = document.getElementsByTagName('script')[0]; 1155 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); 1156 } 1157 1158 window.onYouTubeIframeAPIReady = function () { 1159 $('.yt-playlist').each(function () { 1160 const target = $(this); 1161 const iframe = target.find('.yt-player'); 1162 const videoID = target.data('id'); 1163 const blockID = target.data('block'); 1164 self.YTPlayers[blockID] = new YT.Player(iframe.get(0), { 1165 height: '540', 1166 width: '960', 1167 videoId: videoID, 1168 events: { 1169 onReady: self.videoPlayToggle, 1170 onStateChange: self.videoPlayToggle, 1171 }, 1172 }); 1173 }); 1174 1175 $('.plist-item').on('click', function (e) { 1176 e.preventDefault(); 1177 e.stopPropagation(); 1178 1179 const target = $(this); 1180 const wrapper = target.closest('.yt-playlist'); 1181 const currentBlockID = wrapper.data('block'); 1182 const videoID = target.data('id'); 1183 const title = target.find('.plist-item-title').text(); 1184 const meta = target.data('index'); 1185 1186 Object.keys(self.YTPlayers).forEach(function (id) { 1187 self.YTPlayers[id].pauseVideo(); 1188 }); 1189 self.YTPlayers[currentBlockID].loadVideoById({ 1190 videoId: videoID, 1191 }); 1192 1193 wrapper.find('.yt-trigger').addClass('is-playing'); 1194 wrapper.find('.play-title').hide().text(title).fadeIn(200); 1195 wrapper.find('.video-index').text(meta); 1196 }); 1197 }; 1198 }; 1199 1200 Module.videoPlayToggle = function () { 1201 const players = FOXIZ_MAIN_SCRIPT.YTPlayers; 1202 1203 $('.yt-trigger').on('click', function (e) { 1204 e.preventDefault(); 1205 e.stopPropagation(); 1206 1207 const target = $(this); 1208 const currentBlockID = target.closest('.yt-playlist').data('block'); 1209 const currentState = players[currentBlockID].getPlayerState(); 1210 const isPlaying = [1, 3].includes(currentState); 1211 if (!isPlaying) { 1212 players[currentBlockID].playVideo(); 1213 target.addClass('is-playing'); 1214 } else { 1215 players[currentBlockID].pauseVideo(); 1216 target.removeClass('is-playing'); 1217 } 1218 }); 1219 }; 1220 1221 /** Comment scripts */ 1222 Module.showPostComment = function () { 1223 const self = this; 1224 1225 this._document.on('click', '.smeta-sec .meta-comment', function (e) { 1226 e.stopPropagation(); 1227 const commentBtn = $('.show-post-comment'); 1228 if (commentBtn.length > 0) { 1229 self.html.animate({ scrollTop: commentBtn.offset().top }, 300); 1230 commentBtn.trigger('click'); 1231 } 1232 }); 1233 1234 this._document.on('click', '.show-post-comment', function (e) { 1235 e.preventDefault(); 1236 e.stopPropagation(); 1237 const target = $(this); 1238 const wrap = target.parent(); 1239 1240 target.fadeOut(200, function () { 1241 target.remove(); 1242 wrap.find('.is-invisible').removeClass('is-invisible'); 1243 wrap.next('.comment-holder').removeClass('is-hidden'); 1244 }); 1245 }); 1246 }; 1247 1248 /** table scroll */ 1249 Module.scrollTableContent = function () { 1250 const self = this; 1251 const behavior = self._body.hasClass('toc-smooth') ? 'smooth' : 'instant'; 1252 1253 self._document.on('click', '.anchor-link', function (e) { 1254 e.stopPropagation(); 1255 1256 const targetClass = $(this).data('index'); 1257 if (!targetClass) return; 1258 1259 let $scrollElement = $(`.${targetClass}`); 1260 1261 // if target not found, search inside its parent .s-ct 1262 if (!$scrollElement.length) { 1263 const $parentContainer = $(this).closest('.s-ct'); 1264 if ($parentContainer.length) { 1265 $scrollElement = $parentContainer.find('.restrict-box, .continue-reading-btn').first(); 1266 } 1267 } 1268 1269 if (!$scrollElement.length) return; 1270 1271 setTimeout(() => { 1272 window.scrollTo({ 1273 top: $scrollElement.offset().top, 1274 behavior: behavior, 1275 }); 1276 }, 10); 1277 }); 1278 }; 1279 1280 /** scroll to comment */ 1281 Module.scrollToComment = function () { 1282 const self = this; 1283 const hash = window.location.hash; 1284 if (hash === '#respond' || hash.startsWith('#comment')) { 1285 const commentBtn = $('.show-post-comment').first(); 1286 if (commentBtn.length === 0) { 1287 return; 1288 } 1289 self.html.animate({ scrollTop: commentBtn.offset().top - 200 }, 400); 1290 commentBtn.trigger('click'); 1291 } 1292 }; 1293 1294 Module.replyReview = function () { 1295 this._document.on('click', '.comment-reply-link', function () { 1296 const target = $(this); 1297 const wrapper = target.parents('.rb-reviews-area'); 1298 const cancelLink = $('#cancel-comment-reply-link'); 1299 if (wrapper.length > 0) { 1300 wrapper.find('.rb-form-rating').addClass('is-hidden'); 1301 cancelLink.on('click', function () { 1302 wrapper.find('.rb-form-rating').removeClass('is-hidden'); 1303 }); 1304 } 1305 }); 1306 }; 1307 1308 /** user rating */ 1309 Module.usersRating = function () { 1310 const self = this; 1311 const reviewsForm = self._body.find('.rb-reviews-form'); 1312 if (reviewsForm.length > 0) { 1313 reviewsForm.each(function () { 1314 const reviewForm = $(this); 1315 if (!reviewForm.hasClass('is-loaded')) { 1316 reviewForm.addClass('is-loaded'); 1317 const ratingForm = reviewForm.find('.rb-form-rating'); 1318 const selection = reviewForm.find('.rb-rating-selection'); 1319 const text = reviewForm.find('.rating-alert').html();
1320 let ratingValue = null; 1321 1322 selection.val(''); 1323 selection.hide(); 1324 selection.before( 1325 '<div class="rb-review-stars">\ 1326 <span>\ 1327 <a class="star" data-rating="1" href="#"><i class="rbi rbi-star-o"></i></a>\ 1328 <a class="star" data-rating="2" href="#"><i class="rbi rbi-star-o"></i></a>\ 1329 <a class="star" data-rating="3" href="#"><i class="rbi rbi-star-o"></i></a>\ 1330 <a class="star" data-rating="4" href="#"><i class="rbi rbi-star-o"></i></a>\ 1331 <a class="star" data-rating="5" href="#"><i class="rbi rbi-star-o"></i></a>\ 1332 </span>\ 1333 </div>' 1334 ); 1335 1336 ratingForm.on('click', 'a.star', function (e) { 1337 e.preventDefault(); 1338 e.stopPropagation(); 1339 const star = $(this); 1340 ratingValue = star.data('rating'); 1341 star.siblings('a').removeClass('active'); 1342 star.addClass('active'); 1343 ratingForm.addClass('selected'); 1344 }); 1345 1346 reviewForm.on('click', '#respond #submit', function () { 1347 selection.val(ratingValue); 1348 if (!selection.val()) { 1349 window.alert(text); 1350 return false; 1351 } 1352 }); 1353 } 1354 }); 1355 } 1356 }; 1357 1358 /** 1359 * 1360 * @returns {boolean} 1361 */ 1362 Module.readIndicatorInit = function () { 1363 const self = this; 1364 if (!self._body.hasClass('single') || self.readIndicator.length < 1) { 1365 return false; 1366 } 1367 1368 let content = $('.entry-content').first(); 1369 if (!content.length) return false; 1370 1371 self.indicatorTop = content.offset().top; 1372 self.indicatorHeight = content.outerHeight(true) - self._window.height(); 1373 /** delay for load images */ 1374 setTimeout(function () { 1375 self.indicatorTop = content.offset().top; 1376 self.indicatorHeight = content.outerHeight(true) - self._window.height(); 1377 }, 1000); 1378 1379 self.addScrollHandler('readIndicator', self.readIndicatorCalc.bind(self)); 1380 }; 1381 1382 Module.readIndicatorCalc = function () { 1383 const self = this; 1384 const scroll = self._window.scrollTop(); 1385 self.readIndicatorPercent = Math.min(((scroll - self.indicatorTop) / self.indicatorHeight) * 100, 100); 1386 if (self.readIndicatorPercent <= 100) { 1387 self.readIndicator.css('width', self.readIndicatorPercent + '%'); 1388 } 1389 }; 1390 1391 /** breaking news */ 1392 Module.breakingNews = function () { 1393 const self = this; 1394 const breakingNews = $('.breaking-news-slider'); 1395 1396 if (breakingNews.length < 1) { 1397 return false; 1398 } 1399 1400 breakingNews.each(function () { 1401 const el = $(this); 1402 let params = { 1403 slidesPerView: 1, 1404 loop: true, 1405 }; 1406 if (el.data('play')) { 1407 params.autoplay = { 1408 delay: el.data('speed') || self.themeSettings.sliderSpeed, 1409 stopOnLastSlide: false, 1410 disableOnInteraction: self.isElementorEditor ? true : window.outerWidth < 1025, 1411 pauseOnMouseEnter: true, 1412 }; 1413 } 1414 params.navigation = { 1415 nextEl: el.find('.breaking-news-next')[0], 1416 prevEl: el.find('.breaking-news-prev')[0], 1417 }; 1418 new RBSwiper(this, params); 1419 }); 1420 }; 1421 1422 /** overlay slider */ 1423 Module.sliders = function () { 1424 const self = this; 1425 const sliders = $('.post-slider'); 1426 if (sliders.length < 1) { 1427 return false;
1428 } 1429 1430 sliders.each(function () { 1431 const slider = $(this); 1432 let params = { 1433 grabCursor: true, 1434 allowTouchMove: true, 1435 effect: self.themeSettings.sliderEffect, 1436 loop: true, 1437 }; 1438 if (slider.data('play')) { 1439 params.autoplay = { 1440 delay: slider.data('speed') || self.themeSettings.sliderSpeed, 1441 stopOnLastSlide: true, 1442 disableOnInteraction: self.isElementorEditor ? true : window.outerWidth < 1025, 1443 pauseOnMouseEnter: true, 1444 }; 1445 } 1446 1447 params.pagination = { 1448 el: slider.find('.slider-pagination')[0], 1449 clickable: true, 1450 }; 1451 1452 params.navigation = { 1453 nextEl: slider.find('.slider-next')[0], 1454 prevEl: slider.find('.slider-prev')[0], 1455 }; 1456 new RBSwiper(this, params); 1457 }); 1458 }; 1459 1460 /** carousel blocks */ 1461 Module.carousels = function () { 1462 const self = this; 1463 const carousels = $('.post-carousel'); 1464 if (carousels.length < 1) { 1465 return false; 1466 } 1467 carousels.each(function () { 1468 const carousel = $(this); 1469 let params = { 1470 grabCursor: true, 1471 allowTouchMove: true, 1472 freeMode: false, 1473 loop: true, 1474 }; 1475 params.slidesPerView = carousel.data('mcol'); 1476 params.spaceBetween = carousel.data('mgap'); 1477 params.centeredSlides = carousel.data('centered'); 1478 1479 params.navigation = { 1480 nextEl: carousel.find('.slider-next')[0], 1481 prevEl: carousel.find('.slider-prev')[0], 1482 }; 1483 if (carousel.find('.slider-pagination')[0]) { 1484 params.pagination = { 1485 el: carousel.find('.slider-pagination')[0], 1486 type: 'bullets', 1487 clickable: true, 1488 }; 1489 } 1490 1491 if (carousel.data('play')) { 1492 params.autoplay = { 1493 delay: carousel.data('speed') || self.themeSettings.sliderSpeed, 1494 stopOnLastSlide: false, 1495 disableOnInteraction: self.isElementorEditor ? true : window.outerWidth < 1025, 1496 pauseOnMouseEnter: true, 1497 }; 1498 } 1499 1500 if (carousel.data('fmode')) { 1501 params.freeMode = true; 1502 } 1503 params.breakpoints = { 1504 768: { 1505 slidesPerView: carousel.data('tcol'), 1506 spaceBetween: carousel.data('tgap'), 1507 }, 1508 1025: { 1509 slidesPerView: carousel.data('col'), 1510 spaceBetween: carousel.data('gap'), 1511 }, 1512 1500: { 1513 slidesPerView: carousel.data('wcol'), 1514 spaceBetween: carousel.data('gap'), 1515 }, 1516 }; 1517 params.on = { 1518 afterInit: function (swiper) { 1519 const wrap = $(swiper.$wrapperEl); 1520 $(swiper.$wrapperEl).find('.p-box').css('height', wrap.height()); 1521 }, 1522 resize: function (swiper) { 1523 const wrap = $(swiper.$wrapperEl); 1524 $(swiper.$wrapperEl).find('.p-box').css('height', wrap.height()); 1525 }, 1526 }; 1527 1528 new RBSwiper(this, params); 1529 }); 1530 }; 1531 1532 /* ================================ SINGLE GALLERY ================================ */ 1533 Module.singleGallery = function () { 1534 const self = this; 1535 const gallerySections = self._body.find('.featured-gallery-wrap'); 1536 if (gallerySections.length === 0) { 1537 return; 1538 } 1539 1540 gallerySections.each(function () { 1541 const section = $(this); 1542 if (!section.hasClass('is-loaded')) { 1543 const index = section.data('gallery'); 1544 const sliderEl = section.find('.gallery-slider').attr('id'); 1545 const sliderNavEl = section.find('.gallery-slider-nav').attr('id'); 1546 const carouselEl = section.find('.gallery-carousel').attr('id'); 1547 const coverflowEL = section.find('.gallery-coverflow').attr('id'); 1548 1549 if (sliderEl && sliderNavEl) { 1550 const navEl = $('#' + sliderNavEl); 1551 const navSlidesCount = navEl.find('.swiper-slide').length; 1552 const shouldLoopNav = navSlidesCount >= 6; 1553 const viewSlides = Math.min(navSlidesCount, 6); 1554 1555 if (!shouldLoopNav) { 1556 navEl.css('max-width', `${navSlidesCount * 125}px`); 1557 } 1558 1559 const galleryNav = new RBSwiper('#' + sliderNavEl, { 1560 spaceBetween: 15, 1561 slidesPerView: viewSlides, 1562 freeMode: self.themeSettings.sliderFMode, 1563 grabCursor: true, 1564 loop: shouldLoopNav, 1565 watchSlidesVisibility: shouldLoopNav, 1566 watchSlidesProgress: true, 1567 on: { 1568 init: function () { 1569 $(this.$wrapperEl).removeClass('pre-load'); 1570 }, 1571 }, 1572 }); 1573 1574 const gallerySlider = new RBSwiper('#' + sliderEl, { 1575 spaceBetween: 0, 1576 grabCursor: true, 1577 loop: true, 1578 pagination: { 1579 el: '.swiper-pagination-' + index, 1580 type: 'progressbar', 1581 clickable: true, 1582 }, 1583 on: { 1584 init: function () { 1585 section.addClass('is-loaded'); 1586 }, 1587 }, 1588 thumbs: { 1589 swiper: galleryNav, 1590 }, 1591 }); 1592 1593 gallerySlider.on('slideChange', function () { 1594 const index = this.activeIndex; 1595 if (index) { 1596 const label = $(this.$el).next().find('.current-slider-count'); 1597 label.fadeOut(0, function () { 1598 $(this) 1599 .html(index <= label.data('total') ? index : 1) 1600 .fadeIn(50); 1601 }); 1602 } 1603 }); 1604 } 1605 1606 if ('undefined' !== typeof carouselEl) { 1607 new RBSwiper('#' + carouselEl, { 1608 spaceBetween: 20, 1609 slidesPerView: 'auto', 1610 freeMode: self.themeSettings.sliderFMode, 1611 loop: false, 1612 grabCursor: true, 1613 scrollbar: { 1614 el: '.swiper-scrollbar-' + index, 1615 hide: true, 1616 }, 1617 on: { 1618 init: function () { 1619 $(this.$wrapperEl).removeClass('pre-load'); 1620 section.addClass('is-loaded'); 1621 }, 1622 }, 1623 }); 1624 } 1625 1626 if ('undefined' !== typeof coverflowEL) { 1627 new RBSwiper('#' + coverflowEL, { 1628 effect: 'coverflow', 1629 grabCursor: true, 1630 centeredSlides: true, 1631 slidesPerView: 1.2, 1632 coverflowEffect: { 1633 rotate: 50, 1634 stretch: 0, 1635 depth: 250, 1636 modifier: 1, 1637 slideShadows: true, 1638 }, 1639 breakpoints: { 1640 768: { 1641 slidesPerView: 3, 1642 }, 1643 }, 1644 on: { 1645 init: function () { 1646 $(this.$wrapperEl).removeClass('pre-load'); 1647 section.addClass('is-loaded'); 1648 }, 1649 }, 1650 pagination: { 1651 el: '.swiper-pagination-' + index, 1652 clickable: true, 1653 }, 1654 }); 1655 } 1656 } 1657 }); 1658 }; 1659 1660 Module.scrollBarSlider = function () { 1661 const self = this; 1662 const items = $('.gb-slider-scrollbar'); 1663 if (!items.length) return; 1664 1665 items.each(function (index, itemEl) { 1666 if ($(itemEl).hasClass('is-loaded')) return; 1667 1668 const autoplay = $(itemEl).data('autoplay') === 1; 1669 const caption = $(itemEl).closest('.gb-image-slider').find('.gb-image-caption'); 1670 const scrollbarEl = $(itemEl).find('.swiper-scrollbar')[0]; 1671 1672 $(itemEl).find('.swiper-wrapper').children().addClass('swiper-slide'); 1673 1674 const updateCaption = (swiper) => { 1675 const captionText = $(swiper.slides[swiper.activeIndex]).find('.wp-element-caption').html() || ''; 1676 caption.fadeOut(150, () => caption.html(captionText).fadeIn(200)); 1677 }; 1678 1679 new RBSwiper(itemEl, { 1680 slidesPerView: 1, 1681 loop: false, 1682 grabCursor: true, 1683 autoplay: autoplay 1684 ? { 1685 delay: self.themeSettings.sliderSpeed || 5000, 1686 disableOnInteraction: self.isElementorEditor ? true : window.outerWidth < 1025, 1687 } 1688 : false, 1689 scrollbar: { 1690 el: scrollbarEl, 1691 hide: false, 1692 }, 1693 on: { 1694 init() { 1695 $(itemEl).removeClass('pre-load').addClass('is-loaded'); 1696 updateCaption(this); 1697 }, 1698 slideChange() { 1699 updateCaption(this); 1700 }, 1701 }, 1702 }); 1703 }); 1704 }; 1705 1706 Module.highlightShares = function () { 1707 const self = this; 1708 1709 if ( 1710 !self.themeSettings.highlightShares || 1711 (window.matchMedia && window.matchMedia('(pointer: coarse)').matches) 1712 ) { 1713 return; 1714 } 1715 1716 const config = { 1717 selectableElements: ['.is-highlight-shares'], 1718 twitterUsername: self.themeSettings.twitterName, 1719 facebook: !!self.themeSettings.highlightShareFacebook, 1720 twitter: !!self.themeSettings.highlightShareTwitter, 1721 }; 1722 1723 const extra = self.themeSettings.highlightShareReddit 1724 ? [ 1725 { 1726 icon: '<i class="rbi rbi-reddit"></i>', 1727 url: 'https://reddit.com/submit?url=PAGE_URL&title=TEXT_SELECTION', 1728 }, 1729 ] 1730 : []; 1731 1732 Sharect.config(config).appendCustomShareButtons(extra).init(); 1733 }; 1734 1735 /** 1736 * 1737 * @returns {boolean} 1738 */ 1739 // Module-level floating video state 1740 Module._floatingVideo = { 1741 active: false, 1742 el: null, 1743 $el: null, 1744 isFloating: false, 1745 scrollHandler: null 1746 }; 1747 1748 Module.floatingVideo = function () { 1749 const self = this; 1750 const fv = self._floatingVideo; 1751 1752 // Already active, skip 1753 if (fv.active) return; 1754 1755 const floating = $('.floating-video').not('.is-loaded'); 1756 if (floating.length === 0 || window.outerWidth < 1025) { 1757 return false;
1758 } 1759 1760 // Mark as loaded and store references 1761 floating.addClass('is-loaded'); 1762 fv.active = true; 1763 fv.el = floating[0]; 1764 fv.$el = floating; 1765 fv.isFloating = false; 1766 1767 // Create scroll handler for floating video 1768 fv.scrollHandler = function () { 1769 if (!fv.el || !fv.active) return; 1770 const rect = fv.el.getBoundingClientRect(); 1771 const shouldFloat = rect.bottom < 0; 1772 1773 if (shouldFloat && !fv.isFloating) { 1774 fv.isFloating = true; 1775 fv.$el.addClass('floating-activated'); 1776 if (!fv.$el.find('.floating-close').length) { 1777 fv.$el.find('.float-holder') 1778 .prepend('<a class="floating-close close-popup-btn" href="#"><span class="close-icon"></span></a>'); 1779 } 1780 } else if (!shouldFloat && fv.isFloating) { 1781 fv.isFloating = false; 1782 fv.$el.removeClass('floating-activated'); 1783 } 1784 }; 1785 1786 self.addScrollHandler('floatingVideo', fv.scrollHandler); 1787 }; 1788 1789 Module.floatingVideoRemove = function () { 1790 const self = this; 1791 self._body.on('click', '.floating-close', function (e) { 1792 e.preventDefault(); 1793 e.stopPropagation(); 1794 1795 const fv = self._floatingVideo; 1796 if (fv.$el) { 1797 fv.$el.removeClass('floating-activated'); 1798 } 1799 self.removeScrollHandler('floatingVideo'); 1800 // Reset state 1801 fv.active = false; 1802 fv.el = null; 1803 fv.$el = null; 1804 fv.isFloating = false; 1805 fv.scrollHandler = null; 1806 }); 1807 }; 1808 1809 Module.siteAccessDetector = function () { 1810 const self = this; 1811 const method = self.themeSettings?.adDetectorMethod; 1812 1813 if (!method || self.siteAccessFlag || self.crwDetect()) { 1814 return; 1815 } 1816 1817 setTimeout(() => { 1818 if (self.siteAccessFlag) return; 1819 1820 switch (parseInt(method)) { 1821 case 1: 1822 self.baitElementDetector(); 1823 break; 1824 case 2: 1825 self.externalScriptDetector(); 1826 break; 1827 case 3: 1828 self.combinedDetector(); 1829 break; 1830 } 1831 }, 1500); 1832 }; 1833 1834 Module.baitElementDetector = function () { 1835 const self = this; 1836 const bait = self.createBaitElement(); 1837 document.body.appendChild(bait); 1838 1839 setTimeout(() => { 1840 const isBlocked = self.checkBaitElement(bait); 1841 bait.remove(); 1842 1843 if (isBlocked) { 1844 self.siteAccessFlag = true; 1845 $.magnificPopup.close(); 1846 setTimeout(() => { 1847 self.siteAccessNotification(); 1848 }, 200); 1849 } 1850 }, 100); 1851 }; 1852 1853 Module.externalScriptDetector = function () { 1854 const self = this; 1855 const testUrl = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js'; 1856 const script = document.createElement('script'); 1857 script.src = testUrl; 1858 script.async = true; 1859 1860 let completed = false; 1861 1862 const complete = (blocked) => { 1863 if (completed) return; 1864 completed = true; 1865 script.remove(); 1866 1867 if (blocked) { 1868 self.siteAccessFlag = true; 1869 $.magnificPopup.close(); 1870 setTimeout(() => { 1871 self.siteAccessNotification(); 1872 }, 200); 1873 } 1874 }; 1875 1876 script.onerror = () => complete(true); 1877 script.onload = () => complete(false); 1878 setTimeout(() => complete(true), 5000); 1879 1880 document.head.appendChild(script); 1881 }; 1882 1883 Module.combinedDetector = function () { 1884 const self = this; 1885 const bait = self.createBaitElement(); 1886 document.body.appendChild(bait); 1887 1888 setTimeout(() => { 1889 const baitBlocked = self.checkBaitElement(bait); 1890 bait.remove(); 1891 1892 if (baitBlocked) { 1893 self.siteAccessFlag = true; 1894 $.magnificPopup.close(); 1895 setTimeout(() => { 1896 self.siteAccessNotification(); 1897 }, 200); 1898 return; 1899 } 1900 1901 self.externalScriptDetector(); 1902 }, 100); 1903 }; 1904 1905 Module.createBaitElement = function () { 1906 const container = document.createElement('div'); 1907 container.id = 'rb-adcheck'; 1908 container.setAttribute('aria-hidden', 'true'); 1909 container.style.cssText = 'position:absolute;bottom:0;left:0;z-index:-1;pointer-events:none;overflow:hidden;'; 1910 1911 const inner = document.createElement('div'); 1912 inner.id = 'google_ads_iframe_test'; 1913 inner.className = 'adsbygoogle ad-slot adbanner ads-banner banner_ad ad-placeholder pub_300x250 textads adsbox'; 1914 inner.setAttribute('data-ad-slot', 'test'); 1915 inner.style.cssText = 'width:300px;height:250px;background:transparent;'; 1916 1917 container.appendChild(inner); 1918 return container; 1919 }; 1920 1921 Module.checkBaitElement = function (container) { 1922 const inner = container.querySelector('.adsbygoogle'); 1923 1924 if (!inner || !document.body.contains(inner)) { 1925 return true; 1926 } 1927 1928 const style = window.getComputedStyle(inner); 1929 const rect = inner.getBoundingClientRect(); 1930 1931 return ( 1932 rect.height < 1 || 1933 rect.width < 1 || 1934 style.display === 'none' || 1935 style.visibility === 'hidden' || 1936 parseFloat(style.opacity) === 0 || 1937 inner.offsetParent === null 1938 ); 1939 }; 1940 1941 Module.siteAccessNotification = function () { 1942 $.magnificPopup.open({ 1943 type: 'inline', 1944 preloader: false, 1945 showCloseBtn: false, 1946 closeBtnInside: false, 1947 enableEscapeKey: false, 1948 closeOnBgClick: false, 1949 removalDelay: 9999999, 1950 items: { 1951 src: $('#tmpl-rb-site-access').html(), 1952 type: 'inline', 1953 }, 1954 mainClass: 'rb-popup-center site-access-popup', 1955 fixedBgPos: true, 1956 fixedContentPos: true, 1957 }); 1958 1959 window.addEventListener('contextmenu', (event) => event.preventDefault()); 1960 }; 1961 1962 /** build gallery lightbox */ 1963 Module.galleryLightbox = function () { 1964 const self = this; 1965 if (!self.galleriesData) { 1966 return; 1967 } 1968 1969 $('.gallery-popup-trigger').on('click', function (e) { 1970 e.preventDefault(); 1971 e.stopPropagation(); 1972 1973 const target = $(this); 1974 const slideIndex = target.data('index'); 1975 1976 $.magnificPopup.open({ 1977 type: 'inline', 1978 mainClass: 'rb-gallery-popup rb-popup-center', 1979 closeMarkup: 1980 '<button title="%title%" class="mfp-close mfp-button"><i class="rbi rbi-close"></i></button>', 1981 closeOnBgClick: false, 1982 removalDelay: 400, 1983 showCloseBtn: true, 1984 fixedBgPos: true, 1985 fixedContentPos: true, 1986 preloader: false, 1987 gallery: { 1988 enabled: true, 1989 preload: [0, 2], 1990 arrowMarkup: 1991 '<button title="%title%" type="button" class="mfp-arrow mfp-button mfp-arrow-%dir%"><i class="rbi rbi-%dir%"></i></button>', 1992 tCounter: '<span>%curr% / %total%</span>', 1993 }, 1994 callbacks: { 1995 open: function () { 1996 let itemsArray = Object.values(self.galleriesData); 1997 let targetIndex = itemsArray.findIndex((item) => item.key === slideIndex); 1998 if (targetIndex !== -1) { 1999 $.magnificPopup.instance.goTo(targetIndex); 2000 } 2001 }, 2002 change: function () { 2003 let imgContainer = $('.gallery-popup-content'); 2004 let loader = imgContainer.find('.rb-loader'); 2005 let img = imgContainer.find('img'); 2006 loader.show(); 2007 2008 if (!img.length) { 2009 loader.hide(); 2010 return; 2011 } 2012 2013 let loaderTimeout = setTimeout(() => { 2014 loader.fadeIn(200); 2015 }, 300); // Show loader only if image takes longer 300ms 2016 2017 img.on('load', function () { 2018 clearTimeout(loaderTimeout); // Prevent loader from showing if image loads within 300ms 2019 loader.hide(); 2020 }).on('error', function () { 2021 clearTimeout(loaderTimeout); 2022 loader.hide(); 2023 }); 2024 }, 2025 afterClose: function () { 2026 $.magnificPopup.instance.popupsCache = {}; 2027 }, 2028 buildControls: function () { 2029 if (this.arrowLeft && this.arrowRight) { 2030 this.contentContainer 2031 .find('.gallery-popup-nav') 2032 .append(this.arrowLeft.add(this.arrowRight)); 2033 } 2034 }, 2035 }, 2036 inline: { 2037 markup: 2038 '<div class="gallery-popup-header light-scheme">' + 2039 '<div class="mfp-counter"></div><div class="mfp-title h5"></div>' + 2040 '<div class="popup-header-right"><div class="mfp-close"></div></div>' + 2041 '</div><div class="gallery-popup-nav"></div>' + 2042 '<div class="gallery-popup-content"><i class="rb-loader"></i>' + 2043 '<div class="gallery-popup-image mfp-image"></div>' + 2044 '<div class="gallery-popup-entry light-scheme">' + 2045 '<div class="h4 mfp-excerpt"></div>' + 2046 '<div class="description-text mfp-description"></div>' + 2047 '</div>' + 2048 '</div>', 2049 }, 2050 items: Object.values(self.galleriesData), 2051 }); 2052 2053 return false;
2054 }); 2055 }; 2056 2057 /** single featured lightbox */ 2058 Module.singleFeaturedLightbox = function () { 2059 $('.featured-lightbox-trigger').on('click', function (e) { 2060 e.preventDefault(); 2061 e.stopPropagation(); 2062 2063 const trigger = $(this); 2064 const source = '<img src="' + trigger.data('source') + '" alt="' + $(this).find('img').attr('alt') + '">'; 2065 const caption = trigger.data('caption'); 2066 const attribution = trigger.data('attribution'); 2067 2068 $.magnificPopup.open({ 2069 mainClass: 'rb-popup-center popup-no-overflow', 2070 closeOnBgClick: true, 2071 removalDelay: 400, 2072 showCloseBtn: true, 2073 fixedBgPos: true, 2074 fixedContentPos: true, 2075 preloader: false, 2076 closeMarkup: 2077 '<button title="%title%" class="mfp-close rb-popup-close"><i class="rbi rbi-close"></i></button>', 2078 callbacks: { 2079 afterClose: function () { 2080 $.magnificPopup.instance.popupsCache = {}; 2081 }, 2082 }, 2083 inline: { 2084 markup: 2085 '<div class="featured-popup-image"><div class="mfp-source"></div>' + 2086 '<div class="mfp-close rb-popup-close"></div></div>' + 2087 '<div class="gallery-popup-entry light-scheme">' + 2088 '<div class="h4 mfp-excerpt"></div>' + 2089 '<div class="description-text mfp-description"></div>' + 2090 '</div>', 2091 }, 2092 items: { 2093 source: source, 2094 excerpt: caption, 2095 description: attribution, 2096 }, 2097 }); 2098 }); 2099 }; 2100 2101 /** Ajax pagination */ 2102 Module.paginationNextPrev = function () { 2103 const self = this; 2104 self._body.on('click', '.pagination-trigger', function (e) { 2105 e.preventDefault(); 2106 e.stopPropagation(); 2107 const paginationTrigger = $(this); 2108 if (paginationTrigger.hasClass('is-disable')) { 2109 return; 2110 } 2111 2112 const block = paginationTrigger.parents('.block-wrap'); 2113 const uuid = block.attr('id'); 2114 2115 if (!self.ajaxData[uuid]) { 2116 self.ajaxData[uuid] = self.getBlockSettings(uuid); 2117 } 2118 if (self.ajaxData[uuid] && self.ajaxData[uuid].processing) { 2119 return; 2120 } 2121 self.ajaxData[uuid].processing = true; 2122 const type = paginationTrigger.data('type'); 2123 self.ajaxStartAnimation(block, 'replace'); 2124 self.ajaxReplaceLoad(block, uuid, type); 2125 }); 2126 }; 2127 2128 Module.ajaxReplaceLoad = function (block, uuid, type) { 2129 const self = this; 2130 2131 if (!self.ajaxData[uuid].paged) { 2132 self.ajaxData[uuid].paged = 1; 2133 } 2134 if ('prev' === type) { 2135 self.ajaxData[uuid].page_next = parseInt(self.ajaxData[uuid].paged) - 1; 2136 } else { 2137 self.ajaxData[uuid].page_next = parseInt(self.ajaxData[uuid].paged) + 1; 2138 } 2139 2140 const cacheID = self.cacheData.getCacheID(uuid, self.ajaxData[uuid].page_next); 2141 2142 /** use cache */ 2143 if (self.cacheData.exist(cacheID)) { 2144 const cache = self.cacheData.get(cacheID); 2145 if ('undefined' !== typeof cache.paged) { 2146 self.ajaxData[uuid].paged = cache.paged; 2147 } 2148 setTimeout(function () { 2149 self.ajaxRenderHTML(block, uuid, cache, 'replace'); 2150 }, 200); 2151 } else { 2152 /** POST AJAX */ 2153 $.ajax({ 2154 type: 'GET', 2155 url: self.ajaxURL, 2156 data: { 2157 action: 'rblivep', 2158 data: self.ajaxData[uuid], 2159 }, 2160 success: function (response) { 2161 response = JSON.parse(JSON.stringify(response)); 2162 if ('undefined' !== typeof response.paged) { 2163 self.ajaxData[uuid].paged = response.paged; 2164 } 2165 self.cacheData.set(cacheID, response); 2166 self.ajaxRenderHTML(block, uuid, response, 'replace'); 2167 }, 2168 }); 2169 } 2170 }; 2171 2172 Module.paginationLoadMore = function () { 2173 const self = this; 2174 self._body.on('click', '.loadmore-trigger', function (e) { 2175 e.preventDefault(); 2176 e.stopPropagation(); 2177 2178 const paginationTrigger = $(this); 2179 if (paginationTrigger.hasClass('is-disable')) { 2180 return; 2181 } 2182 2183 const block = paginationTrigger.parents('.block-wrap'); 2184 const uuid = block.attr('id'); 2185 2186 if (!self.ajaxData[uuid]) { 2187 self.ajaxData[uuid] = self.getBlockSettings(uuid); 2188 } 2189 if (self.ajaxData[uuid] && self.ajaxData[uuid].processing) { 2190 return; 2191 } 2192 self.ajaxData[uuid].processing = true; 2193 self.ajaxStartAnimation(block, 'append'); 2194 self.ajaxAppendLoad(block, uuid); 2195 }); 2196 }; 2197 2198 Module.paginationInfinite = function () { 2199 const self = this; 2200 2201 const infiniteElements = $('.pagination-infinite'); 2202 if (infiniteElements.length > 0) { 2203 infiniteElements.each(function () { 2204 const paginationTrigger = $(this); 2205 if (!paginationTrigger.hasClass('is-disable')) { 2206 const block = paginationTrigger.parents('.block-wrap'); 2207 if ( 2208 (block.hasClass('is-hoz-scroll') || 2209 block.hasClass('is-mhoz-scroll') || 2210 block.hasClass('is-thoz-scroll')) && 2211 window.outerWidth < 1025 2212 ) { 2213 paginationTrigger.addClass('is-disable'); 2214 return; 2215 } 2216 const uuid = block.attr('id'); 2217 const observerID = 'infinite_' + uuid; 2218 if (!self.ajaxData[uuid]) { 2219 self.ajaxData[uuid] = self.getBlockSettings(uuid); 2220 } 2221 RB_VIEWPORT_OBSERVER.observe(observerID, { 2222 element: paginationTrigger, 2223 offset: '132%', 2224 continuous: true, 2225 handler: function (direction) { 2226 if (self.ajaxData[uuid] && self.ajaxData[uuid].processing) { 2227 return; 2228 } 2229 if ('down' === direction) { 2230 self.ajaxData[uuid].processing = true; 2231 self.ajaxStartAnimation(block, 'append'); 2232 self.ajaxAppendLoad(block, uuid); 2233 } 2234 }, 2235 }); 2236 } 2237 }); 2238 } 2239 }; 2240 2241 Module.ajaxAppendLoad = function (block, uuid) { 2242 const self = this; 2243 if (!self.ajaxData[uuid].paged) { 2244 self.ajaxData[uuid].paged = 1; 2245 } 2246 if (self.ajaxData[uuid].paged >= self.ajaxData[uuid].page_max) { 2247 return; 2248 } 2249 self.ajaxData[uuid].page_next = parseInt(self.ajaxData[uuid].paged) + 1; 2250 $.ajax({ 2251 type: 'GET', 2252 url: self.ajaxURL, 2253 data: { 2254 action: 'rblivep', 2255 data: self.ajaxData[uuid], 2256 }, 2257 success: function (response) { 2258 response = JSON.parse(JSON.stringify(response)); 2259 if ('undefined' !== typeof response.paged) { 2260 self.ajaxData[uuid].paged = response.paged; 2261 } 2262 if ('undefined' !== typeof response.notice) { 2263 response.content = response.content + response.notice; 2264 } 2265 self.ajaxRenderHTML(block, uuid, response, 'append'); 2266 }, 2267 }); 2268 }; 2269 2270 Module.liveSearch = function () { 2271 const liveSearch = $('.live-search-form'); 2272 if (liveSearch.length === 0) { 2273 return; 2274 } 2275 2276 const self = this; 2277 2278 liveSearch.each(function () { 2279 const liveSearchEl = $(this); 2280 const input = liveSearchEl.find('input[type="text"]'); 2281 const responseWrap = liveSearchEl.find('.live-search-response'); 2282 const animation = liveSearchEl.find('.live-search-animation'); 2283 const limit = liveSearchEl.data('limit'); 2284 const search = liveSearchEl.data('search'); 2285 const follow = liveSearchEl.data('follow'); 2286 const tax = liveSearchEl.data('tax'); 2287 const dsource = liveSearchEl.data('dsource'); 2288 const ptype = liveSearchEl.data('ptype'); 2289 2290 input.attr('autocomplete', 'off'); 2291 2292 input.on('focus', function () { 2293 const param = $(this).val(); 2294 if (param && !responseWrap.is(':empty')) { 2295 responseWrap.css('height', 'auto').fadeIn(200); 2296 } 2297 }); 2298
2299 const delay = (function () { 2300 let timer = 0; 2301 return function (callback, ms) { 2302 clearTimeout(timer); 2303 timer = setTimeout(callback, ms); 2304 }; 2305 })(); 2306 2307 input.keyup(function () { 2308 const param = $(this).val(); 2309 delay(function () { 2310 if (param) { 2311 liveSearchEl.addClass('search-loading'); 2312 setTimeout(function () { 2313 animation.fadeIn(100); 2314 }, 120); 2315 2316 $.ajax({ 2317 type: 'GET', 2318 url: self.ajaxURL, 2319 data: { 2320 action: 'rbsearch', 2321 s: param, 2322 limit: limit, 2323 search: search, 2324 follow: follow, 2325 tax: tax, 2326 dsource: dsource, 2327 ptype: ptype, 2328 }, 2329 success: function (data) { 2330 data = $.parseJSON(JSON.stringify(data)); 2331 animation.fadeOut(200); 2332 setTimeout(function () { 2333 liveSearchEl.removeClass('search-loading'); 2334 }, 200); 2335 responseWrap.hide().empty().css('height', responseWrap.height()); 2336 responseWrap.html(data); 2337 if ('category' === search && follow && typeof FOXIZ_PERSONALIZE !== 'undefined') { 2338 FOXIZ_PERSONALIZE.syncLayoutCategories(); 2339 } 2340 responseWrap.css('height', 'auto').fadeIn(200); 2341 }, 2342 }); 2343 } else { 2344 responseWrap.fadeOut(200, function () { 2345 responseWrap.empty().css('height', 'auto'); 2346 }); 2347 } 2348 }, 300); 2349 }); 2350 }); 2351 }; 2352 2353 /** personalized block */ 2354 Module.personalizeBlocks = function () { 2355 const self = this; 2356 const elements = $('.is-ajax-block'); 2357 if (elements.length > 0) { 2358 const blockRequests = elements.map(function () { 2359 const block = $(this); 2360 const uuid = block.attr('id'); 2361 if (!self.ajaxData[uuid]) { 2362 self.ajaxData[uuid] = self.getBlockSettings(uuid); 2363 } 2364 2365 if ( 2366 self.ajaxData[uuid].content_source && 2367 self.ajaxData[uuid].content_source === 'recommended' && 2368 typeof foxizQueriedIDs !== 'undefined' && 2369 foxizQueriedIDs.data 2370 ) { 2371 self.ajaxData[uuid].post_not_in = foxizQueriedIDs.data; 2372 } 2373 2374 self.ajaxData[uuid].uID = self.getStorage('RBUUID', '0'); 2375 2376 return $.ajax({ 2377 type: 'GET', 2378 url: self.ajaxURL, 2379 data: { 2380 action: 'rbpersonalizeb', 2381 data: self.ajaxData[uuid], 2382 }, 2383 }); 2384 }); 2385 2386 Promise.all(blockRequests).then((responses) => { 2387 responses.forEach((response, index) => { 2388 const block = $(elements[index]); 2389 block.html(response).fadeIn(200); 2390 block.dequeue(); 2391 }); 2392 self.reloadBlockFunc(); 2393 }); 2394 } 2395 }; 2396 2397 /** personalized categories */ 2398 Module.personalizeCategories = function () { 2399 const self = this; 2400 const elements = $('.is-ajax-categories'); 2401 if (elements.length > 0) { 2402 const categoryRequests = elements.map(function () { 2403 const block = $(this); 2404 const uuid = block.attr('id'); 2405 if (!self.ajaxData[uuid]) { 2406 self.ajaxData[uuid] = self.getBlockSettings(uuid); 2407 } 2408 return $.ajax({ 2409 type: 'GET', 2410 url: self.ajaxURL, 2411 data: { 2412 action: 'rbpersonalizecat', 2413 data: self.ajaxData[uuid], 2414 }, 2415 }); 2416 }); 2417 2418 Promise.all(categoryRequests).then((responses) => {
2419 responses.forEach((response, index) => { 2420 const block = $(elements[index]); 2421 block.html(response).fadeIn(200); 2422 block.dequeue(); 2423 }); 2424 2425 if (typeof FOXIZ_PERSONALIZE !== 'undefined') { 2426 FOXIZ_PERSONALIZE.syncLayoutCategories(); 2427 } 2428 self.reloadBlockFunc(); 2429 }); 2430 } 2431 }; 2432 2433 Module.readingCollect = function () { 2434 const self = this; 2435 if (self.themeSettings.yesReadingHis === undefined) { 2436 return; 2437 } 2438 $.ajax({ 2439 type: 'GET', 2440 url: self.ajaxURL, 2441 data: { 2442 action: 'rbcollect', 2443 id: self.themeSettings.yesReadingHis, 2444 }, 2445 }); 2446 }; 2447 2448 /** header notification */ 2449 Module.newsNotification = function () { 2450 const notificationWrapper = $('.rb-notification'); 2451 if (notificationWrapper.length < 1) { 2452 return false; 2453 } 2454 2455 const self = this; 2456 const storageKey = this.personalizeUID + '-notification'; 2457 const dot = $('.notification-info'); 2458 2459 // Get reload interval (now in minutes, default 15) 2460 let reload = notificationWrapper.data('interval'); 2461 if (!reload || isNaN(reload) || reload <= 0) { 2462 reload = 15; 2463 } 2464 2465 // Helper: count NEW post IDs (in current but not in viewed) 2466 function countNewPosts(currentIds, viewedIds) { 2467 if (!currentIds) return 0; 2468 if (!viewedIds) return currentIds.split(',').length; 2469 2470 const current = currentIds.split(','); 2471 const viewed = viewedIds.split(','); 2472 let count = 0; 2473 for (let i = 0; i < current.length; i++) { 2474 if (viewed.indexOf(current[i]) === -1) { 2475 count++; 2476 } 2477 } 2478 return count; 2479 } 2480 2481 // Get cached data (contains: content, count, ids, viewedIds, ttl) 2482 const cached = self.getStorage(storageKey); 2483 2484 // Show cached content immediately for instant UX 2485 if (cached && cached.content) { 2486 notificationWrapper.append(cached.content); 2487 // Show count of NEW posts only (not total) 2488 const newCount = countNewPosts(cached.ids, cached.viewedIds); 2489 if (newCount > 0) { 2490 dot.append(newCount); 2491 dot.css('opacity', 1); 2492 } 2493 } 2494 2495 // Hide dot when user opens notification dropdown 2496 $('.notification-trigger').on('click', function () { 2497 dot.css('opacity', 0).empty(); 2498 // Mark current IDs as viewed 2499 const current = self.getStorage(storageKey); 2500 if (current && current.ids) { 2501 current.viewedIds = current.ids; 2502 self.setStorage(storageKey, current); 2503 } 2504 }); 2505 2506 // Check if refresh needed (expired or no cache) 2507 const isExpired = !cached || !cached.ttl || Date.now() > cached.ttl; 2508 2509 if (isExpired) { 2510 $.ajax({ 2511 type: 'GET', 2512 url: self.ajaxURL, 2513 data: { action: 'rbnotification' }, 2514 success: function (response) { 2515 response = $.parseJSON(JSON.stringify(response)); 2516 2517 const newIds = response.ids || ''; 2518 const oldIds = cached ? cached.ids || '' : ''; 2519 const viewedIds = cached ? cached.viewedIds || '' : ''; 2520 2521 // Store new data with TTL in minutes (preserve viewedIds) 2522 self.setStorage(storageKey, { 2523 content: response.content, 2524 count: response.count, 2525 ids: newIds, 2526 viewedIds: viewedIds, 2527 ttl: Date.now() + reload * 60000, 2528 }); 2529 2530 // Update DOM if: no local cache (first load) OR post IDs changed 2531 if (!cached || newIds !== oldIds) { 2532 notificationWrapper.empty().append(response.content); 2533 dot.empty(); 2534 // Show count of NEW posts only (or total if first load) 2535 const newCount = countNewPosts(newIds, viewedIds); 2536 if (newCount > 0) { 2537 dot.append(newCount); 2538 dot.css('opacity', 1); 2539 } 2540 } 2541 }, 2542 }); 2543 } 2544 }; 2545 2546 /** register cache object */ 2547 Module.cacheData = { 2548 data: {}, 2549 get: function (id) { 2550 return this.data[id]; 2551 }, 2552 2553 set: function (id, data) { 2554 this.remove(id); 2555 this.data[id] = data; 2556 }, 2557 2558 remove: function (id) { 2559 delete this.data[id]; 2560 }, 2561 2562 getCacheID: function (blockID, currentPage) { 2563 return JSON.stringify('RB_' + blockID + '_' + currentPage); 2564 }, 2565 2566 exist: function (id) { 2567 return this.data.hasOwnProperty(id) && this.data[id] !== null; 2568 }, 2569 }; 2570 2571 /** 2572 * ajax start animation 2573 * @param block 2574 * @param action 2575 */ 2576 Module.ajaxStartAnimation = function (block, action) { 2577 const inner = block.find('.block-inner'); 2578 block.find('.pagination-trigger').addClass('is-disable'); 2579 inner.stop(); 2580 2581 if ('replace' === action) { 2582 inner.css('min-height', inner.outerHeight()); 2583 inner.fadeTo('200', 0.05); 2584 inner.after('<i class="rb-loader loader-absolute"></i>'); 2585 } else { 2586 block.find('.loadmore-trigger').addClass('loading'); 2587 block.find('.rb-loader').css({ display: 'block' }).delay(200).animate({ opacity: 1 }, 200); 2588 } 2589 }; 2590 2591 /** 2592 * render ajax 2593 * @param block 2594 * @param uuid 2595 * @param response 2596 * @param action 2597 */ 2598 Module.ajaxRenderHTML = function (block, uuid, response, action) { 2599 const self = this; 2600 2601 block.delay(50).queue(function () { 2602 const uuid = block.attr('id'); 2603 const inner = block.find('.block-inner'); 2604 block.find('.pagination-trigger').removeClass('is-disable'); 2605 inner.stop(); 2606 2607 if ('replace' === action) { 2608 inner.html(response.content); 2609 block.find('.rb-loader').animate({ opacity: 0 }, 200, function () { 2610 $(this).remove(); 2611 }); 2612 inner.css('min-height', ''); 2613 inner.fadeTo(200, 1); 2614 } else { 2615 const content = $(response.content); 2616 inner.append(content); 2617 content.addClass('is-invisible'); 2618 content.addClass('opacity-animate'); 2619 2620 block.find('.rb-loader').animate({ opacity: 0 }, 200, function () { 2621 $(this).css({ display: 'none' }); 2622 }); 2623 setTimeout(function () { 2624 content.removeClass('is-invisible'); 2625 }, 200); 2626 block.find('.loadmore-trigger').removeClass('loading'); 2627 } 2628 2629 /** reload */ 2630 self.ajaxTriggerState(block, uuid); 2631 self.ajaxData[uuid].processing = false;
2632 2633 // Refresh viewport observer for infinite scroll after content change 2634 var observerID = 'infinite_' + uuid; 2635 if (RB_VIEWPORT_OBSERVER.has(observerID)) { 2636 RB_VIEWPORT_OBSERVER.refresh(observerID); 2637 } 2638 2639 block.dequeue(); 2640 self.reloadBlockFunc(); 2641 }); 2642 }; 2643 2644 /** 2645 * set 2646 * @param block 2647 * @param uuid 2648 */ 2649 Module.ajaxTriggerState = function (block, uuid) { 2650 const self = this; 2651 block.find('.pagination-trigger').removeClass('is-disable'); 2652 if (self.ajaxData[uuid].paged < 2) { 2653 block.find('[data-type="prev"]').addClass('is-disable'); 2654 } else if (self.ajaxData[uuid].paged >= self.ajaxData[uuid].page_max) { 2655 block.find('[data-type="next"]').addClass('is-disable'); 2656 block.find('.loadmore-trigger').addClass('is-disable').hide(); 2657 block.find('.pagination-infinite').addClass('is-disable').hide(); 2658 } 2659 }; 2660 2661 Module.getBlockSettings = function (uuid) { 2662 const settings = typeof window[uuid] !== 'undefined' ? window[uuid] : undefined; 2663 return this.cleanNull(settings); 2664 }; 2665 2666 Module.cleanNull = function (data) { 2667 if (typeof data === 'string') { 2668 return data; 2669 } 2670 2671 if (data && typeof data === 'object') { 2672 Object.keys(data).forEach((key) => { 2673 if (data[key] === '' || data[key] === null) { 2674 delete data[key]; 2675 } 2676 }); 2677 } 2678 2679 return data; 2680 }; 2681 2682 /* SINGLE INFINITE */ 2683 Module.singleInfiniteLoadNext = function () { 2684 const infiniteWrapper = $('#single-post-infinite'); 2685 const self = this; 2686 2687 if (!infiniteWrapper.length || self.disabledLoadNext()) { 2688 return; 2689 } 2690 2691 self.singleLoadNextCounter = 1; 2692 self.singleLoadNextLimit = self.themeSettings?.singleLoadNextLimit 2693 ? parseInt(self.themeSettings.singleLoadNextLimit, 10) 2694 : 20; 2695 2696 const infiniteLoadPoint = $('#single-infinite-point'); 2697 const animationIcon = infiniteLoadPoint.find('.rb-loader'); 2698 const rootURL = new URL(window.location.href); 2699 const rootGetParams = rootURL.searchParams; 2700 2701 RB_VIEWPORT_OBSERVER.observe('ajaxSingleNextPosts', { 2702 element: infiniteLoadPoint, 2703 offset: '138%', 2704 continuous: true, 2705 handler: function (direction) { 2706 if ( 2707 self.ajaxData.singleProcessing || 2708 direction === 'up' || 2709 self.singleLoadNextCounter > self.singleLoadNextLimit 2710 ) { 2711 return; 2712 } 2713 const nextPostURL = new URL(infiniteWrapper.data('nextposturl')); 2714 nextPostURL.searchParams.set('rbsnp', '1'); 2715 if (rootGetParams) { 2716 rootGetParams.forEach((value, key) => { 2717 if (key !== 'rbsnp' && 'p' !== key) { 2718 nextPostURL.searchParams.set(key, value); 2719 } 2720 }); 2721 } 2722 self.ajaxData.singleProcessing = true; 2723 animationIcon.css('display', 'block').animate({ opacity: 1 }, 200); 2724 2725 $.ajax({ 2726 type: 'GET', 2727 url: nextPostURL.toString(), 2728 dataType: 'html', 2729 success: function (response) { 2730 response = $('<div id="temp-dom"></div>') 2731 .append($.parseHTML(response)) 2732 .find('.single-post-outer'); 2733 const nextPostURL = response.data('nextposturl'); 2734 2735 if (nextPostURL) { 2736 infiniteWrapper.data('nextposturl', nextPostURL); 2737 } else { 2738 infiniteWrapper.removeAttr('id'); 2739 infiniteLoadPoint.remove(); 2740 RB_VIEWPORT_OBSERVER.unobserve('ajaxSingleNextPosts'); 2741 } 2742 2743 animationIcon.animate({ opacity: 0 }, 200, function () { 2744 $(this).css('display', 'none'); 2745 }); 2746 infiniteWrapper.append(response); 2747 self.ajaxData.singleProcessing = false;
2748 self.singleLoadNextCounter++; 2749 2750 // Refresh observer for next trigger 2751 if (RB_VIEWPORT_OBSERVER.has('ajaxSingleNextPosts')) { 2752 RB_VIEWPORT_OBSERVER.refresh('ajaxSingleNextPosts'); 2753 } 2754 2755 setTimeout(function () { 2756 self.reInitAll(); 2757 if (typeof FOXIZ_CORE_SCRIPT !== 'undefined') { 2758 FOXIZ_CORE_SCRIPT.loadGoogleAds(response); 2759 FOXIZ_CORE_SCRIPT.loadInstagram(response); 2760 FOXIZ_CORE_SCRIPT.loadTwttr(); 2761 FOXIZ_CORE_SCRIPT.loadTikTok && FOXIZ_CORE_SCRIPT.loadTikTok(response); 2762 FOXIZ_CORE_SCRIPT.loadThreads && FOXIZ_CORE_SCRIPT.loadThreads(response); 2763 FOXIZ_CORE_SCRIPT.loadBluesky && FOXIZ_CORE_SCRIPT.loadBluesky(response); 2764 } 2765 }, 1); 2766 }, 2767 error: function () { 2768 animationIcon.animate({ opacity: 0 }, 200, function () { 2769 $(this).css('display', 'none'); 2770 }); 2771 self.ajaxData.singleProcessing = false; 2772 }, 2773 }); 2774 }, 2775 }); 2776 }; 2777 2778 Module.singleScrollRefresh = function () { 2779 const infiniteWrapper = $('#single-post-infinite'); 2780 if (!infiniteWrapper.length) { 2781 return; 2782 } 2783 const self = this; 2784 self.articleData = []; 2785 const articleOuter = infiniteWrapper.find('.single-post-outer'); 2786 2787 if (articleOuter.length > 0) { 2788 self.inviewPostID = articleOuter.eq(0).data('postid'); 2789 2790 articleOuter.each(function () { 2791 const article = $(this); 2792 const itemData = { 2793 postID: article.data('postid'), 2794 postURL: article.data('postlink'), 2795 postTitle: article.find('h1.s-title').text(), 2796 shareList: article.find('.sticky-share-list-buffer').html(), 2797 top: article.offset().top, 2798 bottom: article.offset().top + article.outerHeight(true), 2799 }; 2800 2801 if (self.readIndicator.length > 0) { 2802 const content = article.find('.rbct').eq(0); 2803 itemData.indicatorTop = content.offset().top; 2804 itemData.indicatorHeight = content.outerHeight(true) - self._window.height(); 2805 } 2806 self.articleData.push(itemData); 2807 }); 2808 2809 // Only add scroll listener once 2810 if (!self._singleScrollListenerAdded) { 2811 self._singleScrollListenerAdded = true; 2812 self.addScrollHandler('singleScroll', self.scrollToUpdateArticle.bind(self)); 2813 } 2814 } 2815 }; 2816 2817 /** scrollToUpdateArticle */ 2818 Module.scrollToUpdateArticle = function () { 2819 const self = this; 2820 const scroll = self._window.scrollTop(); 2821 2822 self.articleData.every((article) => { 2823 if (scroll > article.top + 5 && scroll < article.bottom - 5) { 2824 if (article.indicatorTop) { 2825 self.readIndicatorPercent = Math.min( 2826 ((scroll - article.indicatorTop) / article.indicatorHeight) * 100, 2827 100 2828 ); 2829 if (self.readIndicatorPercent <= 100) { 2830 self.readIndicator.css('width', `${self.readIndicatorPercent}%`); 2831 } 2832 } 2833 2834 if (article.postID !== self.inviewPostID) { 2835 self.inviewPostID = article.postID; 2836 2837 const articleEl = $('[data-postid="' + article.postID + '"]'); 2838 2839 // Always update URL and title 2840 if (article.postURL) { 2841 history.replaceState({ postId: article.postID }, article.postTitle, article.postURL); 2842 self.updateCanonicalURL(article.postURL); 2843 } 2844 document.title = article.postTitle; 2845 2846 $('.single-post-outer').removeClass('activated'); 2847 articleEl.addClass('activated'); 2848 $('#s-title-sticky .sticky-title').hide().html(article.postTitle).fadeIn(300); 2849 $('#s-title-sticky .sticky-share-list').html(article.shareList); 2850 self._body.find('.floating-video').removeClass('floating-activated'); 2851 2852 // Only trigger analytics if NOT in teaser mode (full content visible) 2853 const hasContinueReading = articleEl.hasClass('has-continue-reading'); 2854 const continueBtn = articleEl.find('.continue-reading'); 2855 const isTeaserMode = hasContinueReading && continueBtn.length > 0 && continueBtn.is(':visible'); 2856 2857 if (!isTeaserMode && typeof FOXIZ_CORE_SCRIPT !== 'undefined') { 2858 FOXIZ_CORE_SCRIPT.updateGA(article); 2859 } 2860 } 2861 return false;
2862 } 2863 2864 return true; 2865 }); 2866 }; 2867 2868 /** 2869 * Update canonical URL for SEO 2870 * @param {string} url 2871 */ 2872 Module.updateCanonicalURL = function (url) { 2873 if (!url) return; 2874 2875 let canonical = document.querySelector('link[rel="canonical"]'); 2876 if (canonical) { 2877 canonical.href = url; 2878 } 2879 2880 // Update Open Graph URL 2881 let ogUrl = document.querySelector('meta[property="og:url"]'); 2882 if (ogUrl) { 2883 ogUrl.content = url; 2884 } 2885 }; 2886 2887 /** 2888 * @returns {boolean} 2889 */ 2890 Module.crwDetect = function () { 2891 const botPatterns = [ 2892 /alexa|altavista|ask jeeves|attentio|baiduspider|bingbot|chtml generic|crawler|fastmobilecrawl|feedfetcher-google|firefly|froogle|gigabot|googlebot|googlebot-mobile|heritrix|httrack|ia_archiver|irlbot|iescholar|infoseek|jumpbot|linkcheck|lycos|mediapartners|mediobot|motionbot|msnbot|mshots|openbot|pss-webkit-request|pythumbnail|scooter|slurp|snapbot|spider|taptubot|technoratisnoop|teoma|twiceler|yahooseeker|yahooysmcm|yammybot|ahrefsbot|pingdom.com_bot|kraken|yandexbot|twitterbot|tweetmemebot|openhosebot|queryseekerspider|linkdexbot|grokkit-crawler|livelapbot|germcrawler|domaintunocrawler|grapeshotcrawler|cloudflare-alwaysonline/i, 2893 ]; 2894 2895 const userAgent = navigator.userAgent; 2896 return botPatterns.some((pattern) => pattern.test(userAgent)); 2897 }; 2898 2899 /** 2900 * 2901 * @returns {boolean} 2902 */ 2903 Module.disabledLoadNext = function () { 2904 if (this.themeSettings.crwLoadNext) { 2905 return false; 2906 } 2907 2908 return this.crwDetect(); 2909 }; 2910 2911 /** productQuantity */ 2912 Module.productQuantity = function () { 2913 this._document.on('click', '.quantity .quantity-btn', function (e) { 2914 e.preventDefault(); 2915 e.stopPropagation(); 2916 2917 const button = $(this); 2918 const input = button.parent().find('input'); 2919 2920 let step = 1; 2921 let min = 1; 2922 let max = 9999; 2923 let value_old = parseInt(input.val()); 2924 let value_new = parseInt(input.val()); 2925 2926 if (input.attr('step')) { 2927 step = parseInt(input.attr('step')); 2928 } 2929 2930 if (input.attr('min')) { 2931 min = parseInt(input.attr('min')); 2932 } 2933 2934 if (input.attr('max')) { 2935 max = parseInt(input.attr('max')); 2936 } 2937 2938 if (button.hasClass('up')) { 2939 if (value_old < max) { 2940 value_new = value_old + step; 2941 } else { 2942 value_new = 1; 2943 } 2944 } else if (button.hasClass('down')) { 2945 if (value_old > min) { 2946 value_new = value_old - step; 2947 } else { 2948 value_new = 0; 2949 } 2950 } 2951 2952 if (!input.attr('disabled')) { 2953 input.val(value_new).change(); 2954 } 2955 }); 2956 }; 2957 2958 Module.cartNotification = function () { 2959 const self = this; 2960 const element = $('#add-cart-popup'); 2961 2962 self._body.on('added_to_cart', function () { 2963 element.fadeIn(200); 2964 self.cartNotificationTimeOut = setTimeout(function () { 2965 element.fadeOut(200); 2966 }, 5000); 2967 self.hoveringNotification(element); 2968 }); 2969 }; 2970 2971 Module.hoveringNotification = function (element) { 2972 const self = this; 2973 2974 element.on('mouseenter', function () { 2975 clearTimeout(self.cartNotificationTimeOut); 2976 }); 2977 2978 element.on('mouseleave', function () { 2979 setTimeout(function () { 2980 element.fadeOut(200); 2981 }, 1500); 2982 }); 2983 }; 2984 2985 /** like/dislike */ 2986 Module.likeToggle = function () { 2987 const self = this; 2988 let reaction = ''; 2989 self._body.on('click', '.like-trigger, .dislike-trigger', function (e) { 2990 e.preventDefault(); 2991 e.stopPropagation(); 2992 2993 const target = $(this); 2994 const wrap = target.parent('[data-like]'); 2995 const pid = wrap.data('like'); 2996 2997 if (!pid || self.isProgress) return; 2998 2999 self.isProgress = true; 3000 const storageKey = self.getLikeKey(pid); 3001 const isLike = target.hasClass('like-trigger'); 3002 const isDislike = target.hasClass('dislike-trigger'); 3003 const sibEl = target.siblings(); 3004 const likeCountEl = wrap.find('.like-count'); 3005 const dislikeCountEl = wrap.find('.dislike-count'); 3006 let likeCountText = likeCountEl.text(); 3007 let dislikeCountText = dislikeCountEl.text(); 3008 3009 if (isLike) { 3010 if (!target.hasClass('triggered')) { 3011 reaction = 'like'; 3012 if (!/[kKmM]/.test(likeCountText)) { 3013 likeCountText = parseInt(likeCountText); 3014 if (isNaN(likeCountText)) { 3015 likeCountText = 0; 3016 } 3017 likeCountEl.text(likeCountText + 1); 3018 } 3019 target.addClass('triggered'); 3020 3021 if (sibEl.hasClass('triggered')) { 3022 sibEl.removeClass('triggered'); 3023 if (!/[kKmM]/.test(dislikeCountText)) { 3024 dislikeCountText = parseInt(dislikeCountText) - 1; 3025 if (isNaN(dislikeCountText) || dislikeCountText < 1) { 3026 dislikeCountText = ''; 3027 } 3028 dislikeCountEl.text(dislikeCountText); 3029 } 3030 } 3031 self.setStorage(storageKey, 'like'); 3032 } else { 3033 reaction = 'rmlike'; 3034 if (!/[kKmM]/.test(likeCountText)) { 3035 likeCountText = parseInt(likeCountText) - 1; 3036 if (isNaN(likeCountText) || likeCountText < 1) { 3037 likeCountText = ''; 3038 } 3039 likeCountEl.text(likeCountText); 3040 } 3041 target.removeClass('triggered'); 3042 self.deleteStorage(storageKey); 3043 } 3044 } else if (isDislike) { 3045 if (!target.hasClass('triggered')) { 3046 reaction = 'dislike'; 3047 if (!/[kKmM]/.test(dislikeCountText)) { 3048 dislikeCountText = parseInt(dislikeCountText); 3049 if (isNaN(dislikeCountText)) { 3050 dislikeCountText = 0; 3051 } 3052 dislikeCountEl.text(dislikeCountText + 1); 3053 } 3054 target.addClass('triggered'); 3055 if (sibEl.hasClass('triggered')) { 3056 sibEl.removeClass('triggered'); 3057 if (!/[kKmM]/.test(likeCountText)) { 3058 likeCountText = parseInt(likeCountText) - 1; 3059 if (isNaN(likeCountText) || likeCountText < 1) { 3060 likeCountText = ''; 3061 } 3062 likeCountEl.text(likeCountText); 3063 } 3064 } 3065 self.setStorage(storageKey, 'dislike'); 3066 } else { 3067 reaction = 'rmdislike'; 3068 if (!/[kKmM]/.test(dislikeCountText)) { 3069 likeCountText = parseInt(likeCountText) - 1; 3070 if (isNaN(likeCountText) || likeCountText < 1) { 3071 likeCountText = ''; 3072 } 3073 dislikeCountEl.text(likeCountText); 3074 } 3075 target.removeClass('triggered'); 3076 self.deleteStorage(storageKey); 3077 } 3078 } 3079 3080 $.ajax({ 3081 type: 'GET', 3082 url: self.ajaxURL, 3083 data: { 3084 uuid: self.personalizeUID, 3085 action: 'rbvoting', 3086 value: reaction, 3087 pid: pid, 3088 }, 3089 complete: () => { 3090 self.isProgress = false;
3091 }, 3092 }); 3093 }); 3094 }; 3095 3096 /** sync layout */ 3097 Module.syncLayoutLike = function () { 3098 this.isProgress = true; 3099 const likeElements = document.querySelectorAll('[data-like]:not(.loaded)'); 3100 const jsCount = this._body.hasClass('is-jscount'); 3101 let count, countEl; 3102 3103 for (const el of likeElements) { 3104 el.classList.add('loaded'); 3105 const key = this.getLikeKey(el.getAttribute('data-like')); 3106 const triggered = this.getStorage(key); 3107 3108 if (!triggered) continue; 3109 3110 const likeEl = el.querySelector('.el-like'); 3111 const dislikeEl = el.querySelector('.el-dislike'); 3112 3113 if (!likeEl || !dislikeEl) continue; 3114 3115 if (triggered === 'like') { 3116 likeEl.classList.add('triggered'); 3117 countEl = jsCount ? likeEl.querySelector('.like-count') : null; 3118 if (countEl) { 3119 count = parseInt(countEl.textContent.trim()) || 0; 3120 countEl.textContent = count + 1; 3121 } 3122 } else if (triggered === 'dislike') { 3123 dislikeEl.classList.add('triggered'); 3124 countEl = jsCount ? dislikeEl.querySelector('.dislike-count') : null; 3125 if (countEl) { 3126 count = parseInt(countEl.textContent.trim()) || 0; 3127 countEl.textContent = count + 1; 3128 } 3129 } 3130 } 3131 3132 this.isProgress = false; 3133 }; 3134 3135 /** like key */ 3136 Module.getLikeKey = function (id) { 3137 return this.personalizeUID + '-like-' + id; 3138 }; 3139 3140 /** live blog */ 3141 Module.liveBlog = function () { 3142 const self = this; 3143 3144 const liveEntry = $('.rb-live-entry'); 3145 3146 if (liveEntry.length === 0) { 3147 return false; 3148 } 3149 3150 let intervalId; 3151 let delayTimeoutId; 3152 const interval = Math.min(1800, Math.max(15, this.themeSettings.liveInterval || 1800)); 3153 const liveSwitcher = $('#live-interval-switcher'); 3154 const storedSetting = this.getStorage('liveIntervalCheckbox'); 3155 3156 // Start the regular interval (no initial delay) 3157 const startInterval = () => { 3158 clearInterval(intervalId); 3159 intervalId = setInterval(() => this.updateLiveBlog(liveEntry), interval * 1000); 3160 }; 3161 3162 // Stop all timers 3163 const stopAll = () => { 3164 clearInterval(intervalId); 3165 clearTimeout(delayTimeoutId); 3166 }; 3167 3168 // Handle manual toggle with 5s delay to avoid rapid triggering 3169 const handleToggle = () => { 3170 stopAll(); 3171 3172 if (liveSwitcher.prop('checked')) { 3173 // Delay 3s before first load, then continue with regular interval 3174 delayTimeoutId = setTimeout(() => { 3175 this.updateLiveBlog(liveEntry); 3176 startInterval(); 3177 }, 3000); 3178 self.setStorage('liveIntervalCheckbox', 'yes'); 3179 } else { 3180 self.setStorage('liveIntervalCheckbox', 'no'); 3181 } 3182 }; 3183 3184 // Initialize from stored setting 3185 if (storedSetting !== null) { 3186 liveSwitcher.prop('checked', storedSetting === 'yes'); 3187 } else { 3188 self.setStorage('liveIntervalCheckbox', 'yes'); 3189 } 3190 3191 // On page load: start interval immediately if checked (no delay) 3192 if (liveSwitcher.prop('checked')) { 3193 startInterval(); 3194 } 3195 3196 // On manual toggle: use 5s delay 3197 liveSwitcher.on('change', handleToggle); 3198 }; 3199 3200 Module.updateLiveBlog = function (liveEntry) { 3201 const self = this; 3202 const liveURL = new URL(window.location.href); 3203 liveURL.searchParams.set('rblive', '1'); 3204 $.ajax({ 3205 type: 'GET', 3206 url: liveURL.toString(), 3207 dataType: 'html', 3208 success: function (response) { 3209 response = $('<div id="temp-dom"></div>').append($.parseHTML(response)).find('#rb-live-content'); 3210 liveEntry.html(response.html()); 3211 const liveCountElement = liveEntry.prev().find('.live-count'); 3212 if (liveCountElement.length) { 3213 liveCountElement.text(response.data('total')); 3214 } 3215 setTimeout(function () { 3216 self.reInitAll(); 3217 if (typeof FOXIZ_CORE_SCRIPT !== 'undefined') { 3218 FOXIZ_CORE_SCRIPT.loadGoogleAds(response); 3219 FOXIZ_CORE_SCRIPT.loadInstagram(response); 3220 FOXIZ_CORE_SCRIPT.loadTwttr(); 3221 } 3222 }, 1); 3223 }, 3224 }); 3225 }; 3226 3227 Module.accordion = function () { 3228 $('.gb-accordion').each(function () { 3229 const accordion = $(this); 3230 if (accordion.hasClass('yesLoaded')) return; 3231 3232 accordion.addClass('yesLoaded'); 3233 const accordionItems = accordion.find('.gb-accordion-item'); 3234 3235 if (accordion.hasClass('yes-open')) { 3236 accordionItems.first().addClass('active').find('.accordion-item-content').css('display', 'block'); 3237 } 3238 3239 accordion.on('click', '.accordion-item-header', function (e) { 3240 e.preventDefault(); 3241 3242 const header = $(this); 3243 const item = header.closest('.gb-accordion-item'); 3244 const content = item.find('.accordion-item-content'); 3245 3246 if (item.hasClass('active')) { 3247 item.removeClass('active'); 3248 content.stop().slideUp(200); 3249 } else { 3250 const activeItem = accordionItems.filter('.active'); 3251 activeItem.removeClass('active').find('.accordion-item-content').stop().slideUp(200); 3252 item.addClass('active'); 3253 content.stop().slideDown(200); 3254 } 3255 }); 3256 }); 3257 }; 3258 3259 Module.resIframeClassic = function () { 3260 if (!document.body.classList.contains('res-iframe-classic')) return; 3261 const iframes = document.querySelectorAll('.rbct iframe');
3262 iframes.forEach((iframe) => { 3263 const parent = iframe.parentElement; 3264 const grandParent = parent.parentElement; 3265 const greatGrandParent = grandParent.parentElement; 3266 3267 if ( 3268 [parent, grandParent, greatGrandParent].some((element) => { 3269 const classNames = Array.from(element.classList); 3270 return classNames.some((className) => className.indexOf('wp-block') !== -1); 3271 }) 3272 ) 3273 return; 3274 3275 if (!iframe.parentElement.classList.contains('rb-video-ires')) { 3276 if ( 3277 iframe.src.includes('youtube.com') || 3278 iframe.src.includes('youtu.be') || 3279 iframe.src.includes('vimeo.com') || 3280 iframe.src.includes('dailymotion.com') 3281 ) { 3282 iframe.parentElement.classList.add('rb-video-ires'); 3283 } 3284 } 3285 }); 3286 }; 3287 3288 Module.taxBasedAccordion = function () { 3289 const self = this; 3290 $('.block-tax-accordion').each(function () { 3291 const accordion = $(this); 3292 if (accordion.hasClass('is-loaded')) { 3293 return; 3294 } 3295 accordion.addClass('is-loaded'); 3296 const accordionItems = accordion.find('.tax-accordion-item'); 3297 const lastOpenedTab = self.getStorage(accordion.attr('id') + '_lastOpenedTab', null); 3298 3299 if (lastOpenedTab) { 3300 const tabToOpen = accordion.find('[data-tab="' + lastOpenedTab + '"] .tax-accordion-sub'); 3301 if (tabToOpen.length !== 0) { 3302 tabToOpen.show(); 3303 } 3304 } 3305 3306 accordionItems.each(function () { 3307 const item = $(this); 3308 const trigger = item.find('.tax-accordion-trigger'); 3309 const subMenu = item.find('.tax-accordion-sub'); 3310 3311 trigger.click(function () { 3312 if (!subMenu.is(':visible')) { 3313 accordion.find('.tax-accordion-sub').not(subMenu).slideUp(); 3314 } 3315 subMenu.slideToggle(function () { 3316 if (subMenu.is(':visible')) { 3317 self.setStorage(accordion.attr('id') + '_lastOpenedTab', item.attr('data-tab')); 3318 } else { 3319 self.deleteStorage(accordion.attr('id') + '_lastOpenedTab'); 3320 } 3321 }); 3322 }); 3323 }); 3324 }); 3325 }; 3326 3327 Module.sequentialGalleryDisplay = function () { 3328 const galleries = Array.from(document.querySelectorAll('.gallery-animated')); 3329 galleries.forEach((gallery, galleryIndex) => { 3330 const images = Array.from(gallery.querySelectorAll('.e-gallery-item')); 3331 RB_VIEWPORT_OBSERVER.observe('gallery_' + galleryIndex, { 3332 element: gallery, 3333 offset: '100%', 3334 once: true, 3335 handler: function (direction) { 3336 if (direction === 'down') { 3337 images.forEach((image, index) => { 3338 requestAnimationFrame(() => { 3339 setTimeout(() => { 3340 image.classList.add('gallery-visible'); 3341 }, index * 120); 3342 }); 3343 }); 3344 } 3345 }, 3346 }); 3347 }); 3348 }; 3349 3350 Module.reloadCaptchaPopups = function (delay = 50) { 3351 setTimeout(() => { 3352 const $content = $($.magnificPopup?.instance?.content || []); 3353 if (!$content.length) return; 3354 3355 const removeDuplicateCaptchas = (form) => { 3356 const seen = new Set(); 3357 $(form) 3358 .find( 3359 '.g-recaptcha, .h-captcha, .cf-turnstile, .turnstile-widget, .frc-captcha, [data-arkose-public-key], .arkose-enforcement, .geetest_holder, .geetest_panel' 3360 ) 3361 .each(function () { 3362 const cls = this.className; 3363 const type = [ 3364 'g-recaptcha', 3365 'h-captcha', 3366 'cf-turnstile', 3367 'turnstile-widget', 3368 'frc-captcha', 3369 'arkose', 3370 'geetest', 3371 ].find( 3372 (t) => 3373 cls.includes(t) || 3374 $(this).data('arkose-public-key') || 3375 $(this).hasClass('arkose-enforcement') 3376 ); 3377 if (!type) return;
3378 const key = `${type}`; 3379 if (seen.has(key)) { 3380 $(this).remove(); 3381 } else { 3382 seen.add(key); 3383 } 3384 }); 3385 }; 3386 3387 try { 3388 // Remove duplicates per form 3389 $content.find('form').each(function () { 3390 removeDuplicateCaptchas(this); 3391 }); 3392 3393 // Google reCAPTCHA 3394 if (typeof grecaptcha !== 'undefined' && grecaptcha?.reset) { 3395 $content.find('.g-recaptcha').each(function () { 3396 const wid = this.dataset.widgetId; 3397 if (wid) { 3398 try { 3399 grecaptcha.reset(Number(wid)); 3400 } catch {} 3401 } 3402 }); 3403 } 3404 3405 // Cloudflare Turnstile 3406 if (typeof turnstile !== 'undefined' && turnstile?.reset) { 3407 $content.find('.cf-turnstile, .turnstile-widget').each(function () { 3408 const iframe = this.querySelector('iframe'); 3409 const wid = iframe?.dataset?.wid; 3410 if (wid) { 3411 try { 3412 turnstile.reset(wid); 3413 } catch {} 3414 } 3415 }); 3416 } 3417 3418 // hCaptcha 3419 if (typeof hcaptcha !== 'undefined' && hcaptcha?.reset) { 3420 $content.find('.h-captcha').each(function () { 3421 const wid = this.dataset.widgetId; 3422 if (wid) { 3423 try { 3424 hcaptcha.reset(Number(wid)); 3425 } catch {} 3426 } 3427 }); 3428 } 3429 3430 // FriendlyCaptcha 3431 if (typeof friendlycaptcha !== 'undefined' && friendlycaptcha?.widget) { 3432 $content.find('.frc-captcha').each(function () { 3433 const stored = $(this).data('frc-widget'); 3434 if (stored?.reset) { 3435 try { 3436 stored.reset(); 3437 } catch {} 3438 } 3439 }); 3440 } 3441 3442 // Arkose Labs 3443 if (window?.arkose?.reset || typeof ECArkose !== 'undefined') { 3444 const $arkoseEls = $content.find('[data-arkose-public-key], .arkose-enforcement'); 3445 if ($arkoseEls.length) { 3446 try { 3447 window?.arkose?.reset?.(); 3448 ECArkose?.reset?.(); 3449 } catch {} 3450 } 3451 } 3452 3453 // GeeTest 3454 if (typeof initGeetest !== 'undefined' || typeof GeetInit !== 'undefined') { 3455 $content.find('.geetest_holder, .geetest_panel').each(function () { 3456 const inst = this.geetestInstance; 3457 if (inst?.reset) { 3458 try { 3459 inst.reset(); 3460 } catch {} 3461 } 3462 }); 3463 } 3464 } catch (err) {} 3465 }, delay); 3466 }; 3467 3468 return Module; 3469})(FOXIZ_MAIN_SCRIPT || {}, jQuery); 3470 3471/** init */ 3472jQuery(document).ready(function ($) { 3473 FOXIZ_MAIN_SCRIPT.init(); 3474}); 3475 3476/** Elementor editor */ 3477jQuery(window).on('elementor/frontend/init', function () { 3478 if ( 3479 typeof elementorFrontend !== 'undefined' && 3480 typeof elementorFrontend.isEditMode === 'function' && 3481 elementorFrontend.isEditMode() 3482 ) { 3483 FOXIZ_MAIN_SCRIPT.isElementorEditor = true; 3484 FOXIZ_MAIN_SCRIPT.editorDarkModeInit = false; 3485 3486 elementorFrontend.hooks.addAction('frontend/element_ready/widget', FOXIZ_MAIN_SCRIPT.initElementor); 3487 } 3488});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.