1jQuery(window).on('elementor/frontend/init', function () { 2 3 const FRMListingHandler = function ($scope, $) { 4 // Prevent duplicate bindings when Elementor re-initializes the same widget (e.g. after AJAX updates) 5 $scope.off('.frymoListing'); 6 7 // Get the widget configuration 8 function getWidgetConfig() { 9 var rawData = $scope.data('frymo-widget-settings'); // Get data attribute 10 11 if (!rawData) { 12 console.warn('Warning: frymo-widget-settings is missing or undefined.'); 13 return {}; // Return empty object as a fallback 14 } 15 16 try { 17 // Attempt to parse JSON if the data is a JSON string 18 return typeof rawData === "string" ? JSON.parse(rawData) : rawData; 19 } catch (error) { 20 console.error('Error parsing widget config:', error); 21 return {}; // Return empty object on error 22 } 23 } 24 25 if ($scope.find('.swiper-slider-container.frymo-listing-slider').length) { 26 var sliderSettings = JSON.parse($scope.find('.swiper-slider-container.frymo-listing-slider').attr('data-slider-settings')); 27 } else { 28 var sliderSettings = { 29 'enable_slider': '' 30 } 31 } 32 33 // External event. 34 $scope.on( 'update_widget.frymoListing', function ( event, listingConfig, frymoQuery, $triggerWidget ) { 35 update_widget( listingConfig, frymoQuery, $triggerWidget ); 36 } ); 37 38 /** 39 * Helper function to parse current URL and frymo_query from browser. 40 * 41 * @param {Object} listingConfig - Widget configuration 42 * @returns {Object} Object containing currentUrl, hashFragment, and frymoQuery 43 */ 44 function parseCurrentUrlAndQuery(listingConfig) { 45 // Get the full URL and strip out the hash fragment 46 var fullUrl = window.location.href; 47 var hashIndex = fullUrl.indexOf('#'); 48 var hashFragment = ''; 49 var currentUrl = fullUrl; 50 51 if (hashIndex !== -1) { 52 hashFragment = fullUrl.substring(hashIndex); // keep the '#' too 53 currentUrl = fullUrl.substring(0, hashIndex); // manipulate this 54 } 55 56 // Get current frymo_query param from URL if present 57 var frymoQueryRaw = location.search.split('frymo_query=')[1]; 58 var frymoQuery = {}; 59 60 if (typeof frymoQueryRaw !== 'undefined') { 61 try { 62 frymoQuery = JSON.parse(decodeURIComponent(frymoQueryRaw)); 63 } catch (err) { 64 console.warn('Invalid frymo_query parameter', err); 65 } 66 } 67 68 if (typeof listingConfig.query_id === 'undefined') { 69 listingConfig.query_id = ''; 70 } 71 72 if (typeof frymoQuery[listingConfig.query_id] === 'undefined') { 73 frymoQuery[listingConfig.query_id] = {}; 74 } 75 76 return { 77 currentUrl: currentUrl, 78 hashFragment: hashFragment, 79 frymoQuery: frymoQuery 80 }; 81 } 82 83 /** 84 * Helper function to build URL with frymo_query parameter. 85 * 86 * @param {string} currentUrl - Base URL without hash 87 * @param {string} hashFragment - Hash fragment to reattach 88 * @param {Object} frymoQuery - Query object 89 * @returns {string} New URL with query parameters 90 */ 91 function buildUrlWithFrymoQuery(currentUrl, hashFragment, frymoQuery) { 92 // Clean up empty query_id objects 93 Object.keys(frymoQuery).forEach(function(queryId) { 94 if (Object.keys(frymoQuery[queryId]).length === 0) { 95 delete frymoQuery[queryId]; 96 } 97 }); 98 99 var newUrl; 100 if (Object.keys(frymoQuery).length !== 0) { 101 newUrl = frymoReplaceUrlParam(currentUrl, 'frymo_query', encodeURIComponent(JSON.stringify(frymoQuery))); 102 } else { 103 newUrl = frymoRemoveParameterFromUrl(currentUrl, 'frymo_query'); 104 } 105 106 // Reattach hash fragment if any 107 newUrl += hashFragment; 108 109 return newUrl; 110 } 111 112 /** 113 * Helper function to build frymoQuery and URL for pagination/load more. 114 * 115 * @param {Object} listingConfig - Widget configuration 116 * @param {number} pagenum - Page number to load 117 * @returns {Object} Object containing frymoQuery (for AJAX), newUrl, and shouldUpdateHistory flag 118 */ 119 function buildFrymoQueryAndUrl(listingConfig, pagenum) { 120 var urlData = parseCurrentUrlAndQuery(listingConfig); 121 var currentUrl = urlData.currentUrl; 122 var hashFragment = urlData.hashFragment; 123 var frymoQuery = urlData.frymoQuery; 124 125 // Check if pagination is enabled by checking for .wp-pagenavi presence 126 var isPaginationEnabled = $scope.find('.wp-pagenavi').length > 0; 127 128 // Always include pagenum in query for AJAX to work (if > 1) 129 if (pagenum > 1) { 130 frymoQuery[listingConfig.query_id]['pagenum'] = pagenum; 131 } else { 132 delete frymoQuery[listingConfig.query_id]['pagenum']; 133 } 134 135 // For URL updates: only include pagenum if pagination is enabled 136 var frymoQueryForUrl = {}; 137 if (isPaginationEnabled) { 138 frymoQueryForUrl = JSON.parse(JSON.stringify(frymoQuery)); // Deep copy 139 } else { 140 // Exclude pagenum from URL query when pagination is disabled 141 frymoQueryForUrl = JSON.parse(JSON.stringify(frymoQuery)); // Deep copy 142 if (frymoQueryForUrl[listingConfig.query_id] && 'pagenum' in frymoQueryForUrl[listingConfig.query_id]) { 143 delete frymoQueryForUrl[listingConfig.query_id]['pagenum']; 144 } 145 } 146 147 // Build the new URL with updated frymo_query (only if pagination is enabled) 148 var newUrl = currentUrl; 149 if (isPaginationEnabled) { 150 newUrl = buildUrlWithFrymoQuery(currentUrl, hashFragment, frymoQueryForUrl); 151 } else { 152 newUrl += hashFragment; 153 } 154 155 return { 156 frymoQuery: frymoQuery, 157 newUrl: newUrl, 158 shouldUpdateHistory: isPaginationEnabled 159 }; 160 } 161 162 // Pagination click 163 // $scope.on('click.frymoListing', '.wp-pagenavi:not(.current_query):not(.apply-type-reload
163) a:not(.current), .load-more-wrapper .frymo-submit', function (e) { 164 $scope.on('click.frymoListing', '.wp-pagenavi:not(.apply-type-reload) a:not(.current), .load-more-wrapper .frymo-submit', function (e) { 165 e.preventDefault(); 166 167 var $body = $('body'); 168 if ($body.hasClass('elementor-editor-active') || $body.hasClass('elementor-editor-preview')) { 169 return; 170 } 171 172 var listingConfig = getWidgetConfig(); 173 var pagenum = parseInt($(this).attr('data-page')); 174 var type = $(this).attr('data-type') || 'pagination'; 175 176 // Build frymoQuery and URL using helper function 177 var queryResult = buildFrymoQueryAndUrl(listingConfig, pagenum); 178 var frymoQuery = queryResult.frymoQuery; 179 var newUrl = queryResult.newUrl; 180 var shouldUpdateHistory = queryResult.shouldUpdateHistory; 181 182 if (type == 'pagination') { 183 // Update the widget with the new query data 184 update_widget(listingConfig, frymoQuery); 185 } else if (type == 'load-more') { 186 // Load more button click 187 loadMoreAddNewItems(listingConfig, frymoQuery); 188 } 189 190 // Push the new URL to browser history (only if pagination is enabled) 191 if (shouldUpdateHistory) { 192 window.history.pushState(JSON.stringify(frymoQuery), '', newUrl); 193 } 194 }); 195 196 197 198 // Event handler for order-by select change 199 $scope.on('change.frymoListing', '.frymo-orderby-select', function (e) { 200 var listingConfig = getWidgetConfig(); 201 var orderBy = $(this).val(); 202 203 // Parse current URL and query using helper function 204 var urlData = parseCurrentUrlAndQuery(listingConfig); 205 var currentUrl = urlData.currentUrl; 206 var hashFragment = urlData.hashFragment; 207 var frymoQuery = urlData.frymoQuery; 208 209 // Update or remove the order_by parameter 210 if (orderBy && orderBy !== 'default') { 211 frymoQuery[listingConfig.query_id]['order_by'] = orderBy; 212 } else { 213 delete frymoQuery[listingConfig.query_id]['order_by']; 214 } 215 216 // Remove pagination when changing sort order 217 delete frymoQuery[listingConfig.query_id]['pagenum']; 218 219 // Build the new URL with updated query parameters 220 var newUrl = buildUrlWithFrymoQuery(currentUrl, hashFragment, frymoQuery); 221 222 // Remove any /2/ or pagination-style path segments 223 newUrl = frymoRemovePageSegmentFromUrl(newUrl); 224 225 // Update the widget and browser history 226 update_widget(listingConfig, frymoQuery); 227 228 // Clean up title if pagination was previously in it 229 frymoRemovePaginationFromTitle(); 230 231 // Push clean URL to browser history so it persists on reload 232 window.history.pushState(JSON.stringify(frymoQuery), '', newUrl); 233 }); 234 235 236 237 238 239 240 241 242 243 // // Navigation 244 // $(window).on('popstate', function (event) { 245 246 // console.log('event', event); 247 248 // var widgetConfig = getWidgetConfig(); 249 // var newConfig = widgetConfig; 250 // var state = JSON.parse(event.originalEvent.state); 251 // if (state !== null) { 252 // newConfig = Object.assign(widgetConfig, state[widgetConfig.query_id]); 253 // } 254 255 // update_widget(newConfig, {}, undefined, event); 256 // }); 257 258 259 260 // Infinite scroll observer instance 261 var infiniteScrollObserver = null; 262 var isInfiniteScrollLoading = false; 263 264 // Initialize infinite scroll observer 265 function initInfiniteScroll() { 266 // Check if infinite scroll is enabled 267 var listingConfig = getWidgetConfig(); 268 if (listingConfig.load_more_type !== 'infinite_scroll') { 269 return; 270 } 271 272 // Disconnect existing observer if any 273 if (infiniteScrollObserver) { 274 infiniteScrollObserver.disconnect(); 275 infiniteScrollObserver = null; 276 } 277 278 // Check if sentinel element exists
279 var $sentinel = $scope.find('.frymo-infinite-sentinel'); 280 if (!$sentinel.length || $sentinel.closest('.load-more-wrapper').is(':hidden')) { 281 return; 282 } 283 284 // Don't initialize in Elementor editor 285 var $body = $('body'); 286 if ($body.hasClass('elementor-editor-active') || $body.hasClass('elementor-editor-preview')) { 287 return; 288 } 289 290 // Check if IntersectionObserver is supported 291 if (typeof IntersectionObserver === 'undefined') { 292 console.warn('IntersectionObserver is not supported in this browser'); 293 return; 294 } 295 296 // Create observer with threshold slightly before element comes into view 297 infiniteScrollObserver = new IntersectionObserver(function(entries) { 298 entries.forEach(function(entry) { 299 // Only trigger if sentinel is intersecting and not currently loading 300 if (entry.isIntersecting && !isInfiniteScrollLoading) { 301 var $target = $(entry.target); 302 var pagenum = parseInt($target.attr('data-page')); 303 304 if (pagenum && !isNaN(pagenum)) { 305 isInfiniteScrollLoading = true; 306 307 // Build frymoQuery and URL using helper function 308 var queryResult = buildFrymoQueryAndUrl(listingConfig, pagenum); 309 var frymoQuery = queryResult.frymoQuery; 310 var newUrl = queryResult.newUrl; 311 var shouldUpdateHistory = queryResult.shouldUpdateHistory; 312 313 // Load more items 314 loadMoreAddNewItems(listingConfig, frymoQuery); 315 316 // Push the new URL to browser history (only if pagination is enabled) 317 if (shouldUpdateHistory) { 318 window.history.pushState(JSON.stringify(frymoQuery), '', newUrl); 319 } 320 } 321 } 322 }); 323 }, { 324 root: null, 325 rootMargin: '200px', // Start loading 200px before sentinel comes into view 326 threshold: 0.1 327 }); 328 329 // Observe the sentinel element 330 infiniteScrollObserver.observe($sentinel[0]); 331 } 332 333 // Load more AJAX request 334 function loadMoreAddNewItems(listingConfig = {}, frymoQuery = {}) { 335 var $loadMoreWrapper = $scope.find('.load-more-wrapper'); 336 var $paginationWrapper = $scope.find('.wp-pagenavi'); 337 $loadMoreWrapper.addClass('frymo-loading'); 338 $paginationWrapper.addClass('frymo-loading'); 339 340 var data = { 341 action: 'frymo_render_listing_widget', 342 listing_config: listingConfig, 343 frymo_query: JSON.stringify(frymoQuery) 344 }; 345 346 $.post(frymo.ajaxurl, data) 347 .success(function (response) { 348 // Get <article> elements from response 349 var $response = $(response); 350 var $articles = $response.find('article'); 351 352 // Append articles to $scope.find('.frymo-listing') 353 $scope.find('.frymo-listing').append($articles); 354 init_elementor_widgets($articles); 355 init_all_image_sliders(); 356 357 // Handle load more button (.load-more-wrapper .frymo-submit) in current scope with the one from response 358 var $newLoadMoreButton = $response.find('.load-more-wrapper .frymo-submit'); 359 var $existingLoadMoreButton = $scope.find('.load-more-wrapper .frymo-submit'); 360 361 if ($newLoadMoreButton.length) { 362 // New load more button found, replace or append it 363 if ($existingLoadMoreButton.length) { 364 $existingLoadMoreButton.replaceWith($newLoadMoreButton); 365 } else { 366 $scope.find('.load-more-wrapper').append($newLoadMoreButton); 367 } 368 } else {
369 // No load more button in response (last page), hide the existing one 370 if ($existingLoadMoreButton.length) { 371 $existingLoadMoreButton.closest('.load-more-wrapper').hide(); 372 } 373 } 374 375 // Handle infinite scroll sentinel (.frymo-infinite-sentinel) replacement 376 var $newInfiniteSentinel = $response.find('.frymo-infinite-sentinel'); 377 var $existingInfiniteSentinel = $scope.find('.frymo-infinite-sentinel'); 378 379 if ($newInfiniteSentinel.length) { 380 // New infinite scroll sentinel found, replace the existing one 381 if ($existingInfiniteSentinel.length) { 382 $existingInfiniteSentinel.replaceWith($newInfiniteSentinel); 383 } else { 384 // Replace the entire wrapper 385 var $existingWrapper = $scope.find('.load-more-wrapper[data-type="infinite_scroll"]'); 386 var $newWrapper = $response.find('.load-more-wrapper[data-type="infinite_scroll"]'); 387 if ($existingWrapper.length && $newWrapper.length) { 388 $existingWrapper.replaceWith($newWrapper); 389 } 390 } 391 // Re-initialize observer after new sentinel is added 392 if (infiniteScrollObserver) { 393 infiniteScrollObserver.disconnect(); 394 initInfiniteScroll(); 395 } 396 } else { 397 // No infinite scroll sentinel in response (last page), hide the wrapper 398 if ($existingInfiniteSentinel.length) { 399 $existingInfiniteSentinel.closest('.load-more-wrapper').hide(); 400 } 401 // Disconnect observer when no more pages 402 if (infiniteScrollObserver) { 403 infiniteScrollObserver.disconnect(); 404 infiniteScrollObserver = null; 405 } 406 } 407 408 // Replace pagination (.wp-pagenavi) in current scope with the one from response 409 var $newPagenavi = $response.find('.wp-pagenavi'); 410 if ($newPagenavi.length) { 411 var $existingPagenavi = $scope.find('.wp-pagenavi'); 412 if ($existingPagenavi.length) { 413 $existingPagenavi.replaceWith($newPagenavi); 414 } else { 415 $scope.append($newPagenavi); 416 } 417 } 418 419 }) 420 .fail(function (jqXHR, textStatus, errorThrown) { 421 console.error('AJAX error', textStatus, errorThrown); 422 }) 423 .always(function () { 424 $loadMoreWrapper.removeClass('frymo-loading'); 425 $paginationWrapper.removeClass('frymo-loading'); 426 // Reset infinite scroll loading flag 427 isInfiniteScrollLoading = false; 428 }); 429 } 430 431 432 433 434 // Update listing function 435 function update_widget( listingConfig = {}, frymoQuery = {}, $filter = $scope, event = {} ) { 436 437 $scope.fadeTo(100, 0.5); 438 $filter.addClass('frymo-loading'); 439 var data = { 440 action: 'frymo_render_listing_widget', 441 listing_config: listingConfig, 442 frymo_query: JSON.stringify(frymoQuery) 443 }; 444 445 // console.log('data', data); 446 447 if (sliderSettings.enable_slider == 'yes') { 448 // update only articles to keep swiper instance 449 450 $.post(frymo.ajaxurl, data, function (response) { 451 var $response = $(response); 452 var articles = $response.find('.frymo-listing-item'); 453 454 // Check if we have results 455 if (articles.length > 0) { 456 // Has results - update slider items 457 $scope.find('.frymo-listing .frymo-listing-item').remove(); 458 $scope.find('.frymo-listing').append(articles); 459 init_elementor_widgets(articles); 460 $scope.find('.frymo-no-results-message').remove(); 461 init_all_image_sliders(); 462 463 // Check if slider needs to be reinitialized 464 if (!swiperSlider || !swiperSlider.initialized) { 465 init_swiper(); 466 } else { 467 swiperSlider.update(); 468 swiperSlider.slideTo(0, 0); 469 } 470 } else { 471 // No results - replace entire content 472 var noResultsMessage = $response.find('.frymo-no-results-message'); 473 $scope.find('.frymo-listing').empty().append(noResultsMessage); 474 475 if (swiperSlider && swiperSlider.initialized) { 476 swiperSlider.destroy(true, true); 477 swiperSlider = null; 478 } 479 } 480 481 $scope.fadeTo(200, 1); 482 $filter.removeClass('frymo-loading'); 483 484 $scope.find('select.frymo-orderby-select').each(function () { 485 frymoAdjustSelectWidth($(this), 40); 486 }); 487 488 if (listingConfig.scrolltop_offset) { 489 $('html, body').stop(true); 490 $('html, body').animate({ 491 scrollTop: $scope.offset().top - listingConfig.scrolltop_offset 492 }, 700, 'swing'); 493 } 494 // Re-initialize infinite scroll after widget update (slider mode) 495 initInfiniteScroll(); 496 }); 497 } else { 498 // update widget content 499 $.post(frymo.ajaxurl, data, function (response) { 500 $scope.html(response).fadeTo(200, 1); 501 init_elementor_widgets($scope); 502 init_all_image_sliders(); 503 504 $scope.find('select.frymo-orderby-select').each(function () { 505 frymoAdjustSelectWidth($(this), 40); 506 }); 507 508 $filter.removeClass('frymo-loading'); 509 if (listingConfig.scrolltop_offset) { 510 $('html, body').stop(true); 511 $('html, body').animate({ 512 scrollTop: $scope.offset().top - listingConfig.scrolltop_offset 513 }, 700, 'swing'); 514 } 515 // Re-initialize infinite scroll after widget update 516 initInfiniteScroll(); 517 }); 518 } 519 } 520 521 if (sliderSettings.enable_slider == 'yes') { 522 var swiperSlider; 523 init_swiper(); 524 } 525 526 function init_swiper() { 527 var sliderElement = $scope.find('.swiper-slider-container'); 528 var swiperSliderDataConfig = sliderSettings; 529 var swiperSliderConfig = { 530 speed: parseInt(swiperSliderDataConfig.speed), 531 navigation: { 532 // TODO: Avoid using .elementor-widget-container due to Elementor optimized HTML feature 533 prevEl: $scope.find('> .elementor-widget-container > .button-prev')[0] || null, 534 nextEl: $scope.find('> .elementor-widget-container > .button-next')[0] || null, 535 }, 536 breakpoints: swiperSliderDataConfig.breakpoints, 537 spaceBetween: parseInt(swiperSliderDataConfig.spaceBetween), 538 loop: swiperSliderDataConfig.loop, 539 freeMode: swiperSliderDataConfig.freeMode || false, 540 centeredSlides: swiperSliderDataConfig.centeredSlides || false,
541 autoplay: swiperSliderDataConfig.autoplay ? { 542 delay: swiperSliderDataConfig.autoplay_delay || 1, 543 disableOnInteraction: false, 544 } : false, 545 }; 546 547 if (swiperSliderDataConfig.pagination_type != 'none') { 548 swiperSliderConfig.pagination = { 549 el: $scope.find('.swiper-pagination')[0], type: swiperSliderDataConfig.pagination_type, clickable: true, 550 }; 551 } 552 553 if (swiperSliderDataConfig.autoplay == 'yes') { 554 swiperSliderConfig.autoplay = { 555 delay: swiperSliderDataConfig.autoplay_delay, 556 }; 557 } 558 559 if ('undefined' === typeof Swiper) { // Improved Asset Loading enabled 560 var asyncSwiper = elementorFrontend.utils.swiper; 561 new asyncSwiper(sliderElement[0], swiperSliderConfig).then(function (newSwiperSliderInstance) { 562 swiperSlider = newSwiperSliderInstance; 563 }); 564 } else { // Improved Asset Loading disabled 565 swiperSlider = new Swiper(sliderElement[0], swiperSliderConfig); 566 } 567 568 if (swiperSliderDataConfig.autoplay_pause_on_hover == 'yes') { 569 $(sliderElement).on('mouseenter', function(e){ 570 swiperSlider.autoplay.pause(); 571 }); 572 $(sliderElement).on('mouseleave', function(e){ 573 swiperSlider.autoplay.run(); 574 }); 575 } 576 } 577 578 // Maybe init image sliders on hover 579 // var isImagesSliderEnabled = getWidgetConfig(); 580 581 if (getWidgetConfig().enable_images_slider == 'yes') { 582 583 // De-duplicate document-level binding across Elementor re-inits 584 $(document).off('touchmove.frymoListingImages touchenter.frymoListingImages mouseenter.frymoListingImages', '.frymo-listing-images-slider'); 585 $(document).on('touchmove.frymoListingImages touchenter.frymoListingImages mouseenter.frymoListingImages', '.frymo-listing-images-slider', function () { 586 var $slider_element = $(this); 587 init_images_swiper($slider_element); 588 }); 589 590 init_all_image_sliders(); 591 592 // $(document).on('click', '.frymo-listing-images-slider .button-next', function (e) { 593 // e.preventDefault(); 594 // var $slider_element = $(this).closest('.frymo-listing-images-slider'); 595 // init_images_swiper($slider_element, true); 596 // }); 597 } 598 599 function init_images_swiper($slider_element, slide_to_next = false) { 600 if ($slider_element.hasClass('swiper-initialized') || $slider_element.hasClass('swiper-container-initialized')) { 601 return false; 602 } 603 604 var images_slider_config = { 605 speed: parseInt(getWidgetConfig().images_transition_duration.size) || 300, 606 navigation: { 607 prevEl: $slider_element.find('.button-prev')[0], 608 nextEl: $slider_element.find('.button-next')[0], 609 }, pagination: { 610 el: $slider_element.find('.swiper-pagination')[0], 611 type: 'bullets', 612 } 613 }; 614 615 if ('undefined' === typeof Swiper) { // Improved Asset Loading enabled 616 var asyncSwiper = elementorFrontend.utils.swiper; 617 new asyncSwiper($slider_element[0], images_slider_config).then(function (newSwiperSliderInstance) { 618 var swiperImagesSlider = newSwiperSliderInstance; 619 // if (slide_to_next) { 620 // swiperImagesSlider.slideNext() 621 // } 622 }); 623 } else { // Improved Asset Loading disabled 624 var swiperImagesSlider = new Swiper($slider_element[0], images_slider_config); 625 // if (slide_to_next) { 626 // swiperImagesSlider.slideNext() 627 // } 628 } 629 } 630 631 function init_all_image_sliders() { 632 if (getWidgetConfig().enable_images_slider != 'yes') { 633 return; 634 } 635 636 $scope.find('.frymo-listing-images-slider').each(function () { 637 init_images_swiper($(this)); 638 }); 639 } 640 641 function init_elementor_widgets($context) { 642 if ( 643 typeof elementorFrontend === 'undefined' || 644 !elementorFrontend.elementsHandler || 645 typeof elementorFrontend.elementsHandler.runReadyTrigger !== 'function' 646 ) { 647 return; 648 } 649 650 var $elements = $context.filter('.elementor-element').add($context.find('.elementor-element')); 651 652 if (!$elements.length) { 653 $elements = $context; 654 } 655 656 $elements.each(function () { 657 elementorFrontend.elementsHandler.runReadyTrigger($(this)); 658 }); 659 } 660 661 // Adjust width on page load 662 $scope.find('select.frymo-orderby-select').each(function () { 663 frymoAdjustSelectWidth($(this), 40); 664 }); 665 666 // Adjust width on change 667 $scope.on('change.frymoListing', 'select.frymo-orderby-select', function () { 668 frymoAdjustSelectWidth($(this), 40); 669 }); 670 671 // Initialize infinite scroll on widget load 672 initInfiniteScroll(); 673 }; 674 675 elementorFrontend.hooks.addAction('frontend/element_ready/frymo-listing.grid-skin', FRMListingHandler); 676 elementorFrontend.hooks.addAction('frontend/element_ready/frymo-listing.list-skin', FRMListingHandler); 677 elementorFrontend.hooks.addAction('frontend/element_ready/frymo-listing.loop-item-skin', FRMListingHandler); 678 679 ['grid-skin', 'list-skin', 'loop-item-skin', 'table-skin'].forEach(function (skin) { 680 elementorFrontend.hooks.addAction('frontend/element_ready/frymo-fpe-units-listing.' + skin, FRMListingHandler); 681 }); 682});
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.