#1
#2
#3
#4
#5
#6
#7
#8
#9

Add-ons

Scripts you can use to add more custom functionality on top of CMS Library components.

Pass filters Params to URL and load page with filters pre-selected

On the first page where the links should be in.

  • The button that we'll add the filter should be a link element i.e. <a> tag.
  • The users needs to define the buttons class, the url to the next page and the filters to be applied. They can add as much as they need to to this array.
 <!-- Add filter params to links that apply filters on page load - pt.1 -->
<script>
const filterURLDetails = [
 {
   filterBtnClass: '.test',  // The button to which we'll add the URL
   url: 'https://test.com',  // URL to the page which will be loaded already filtered
   filters: [
     'green', 'blue', 'yellow' // The filters to be applied
   ]
 }
]

// Add url to buttons
// For each button
for (const filterBtn of filterURLDetails) {
   const button = document.querySelector(filterBtn.filterBtnClass);

   // define the url and add to a variable
   let url = new URL(filterBtn.url);

   // For each filter
   for (const filter of filterBtn.filters) {
     let filterParams;

     // Assign the filter as a query param to the URL
     if (filterBtn.filters.indexOf(filter) === 0) {
       filterParams = '?filter0=' + filter;
     } else {
       filterParams = '&filter' + filterBtn.filters.indexOf(filter) + '=' + filter;
     }
     url = url + filterParams;
   }
   // Add the final URL to the button
   button.href = url;
}
</script>
Copy code

On the second page that needs to be filtered on load.

  • The users needs to define the wrapper of filter buttons and the class of the filter buttons within the wrapper.
  • They need to make sure this are defined in the order in which they declared the buttons in the first page, otherwise it won't work.
<!-- Add filter params to links that apply filters on page load - pt. 2--><script>
const filterTriggers = [
 {
   wrapperClass: '.filters-colors',
   buttonsClass: '.sort-button'
 },
 {
   wrapperClass: '.filters-services',
   buttonsClass: '.sort-button'
 }
]

// Get params from the URL
var getParamsArray = function (url) {
var params = {};
var parser = document.createElement('a');
parser.href = url;
var query = parser.search.substring(1);
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
params[pair[0]] = decodeURIComponent(pair[1]);
 }

 const valuesArray = Object.values(params);
return valuesArray;
};
const filterArrays = getParamsArray(window.location.href);// If there are filter params

if(filterArrays) {
// For each filterArray item
 for (const filterParam of filterArrays) {
   // For each defined trigger
   for (const singleTrigger of filterTriggers) {
      const elems = document.querySelector(singleTrigger.wrapperClass);
      buttons = elems.querySelectorAll(singleTrigger.buttonsClass);
     // If button exists get the button
     filterButton = Array.from(buttons).find(v => v.innerText.toLowerCase().replace(/\s/g,'') === filterParam.toLowerCase().replace(/\s/g,''));
     // If the button exists, click it
     if (filterButton) { filterButton.click(); }
   }
}
}
</script>
Copy code

Load filter buttons from a CMS list

For each button text block, add the class '.filter-by-text', then add this script.

<!-- Add filter-by attribute to filter buttons loaded by CMS -->

<script>
   // Get values for each element with .filter-by-text class within the parent DOM       and store in a variable
    var filterByTextElements = document.querySelectorAll('.filter-by-text');

  // For each filter by text element
  for (element of filterByTextElements) {
      // Get each element text and store in a variable
  var elementText = element.innerText;

      // set attribute to the parent element dynamically
      element.parentElement.setAttribute('filter-by', elementText);
   }
</script>
Copy code

Load filter checkboxes from a CMS list

For each checkbox add this classes. The checkbox form '.checkbox-form', filter by text text-block '.filter-by-text' and the checkbox element '.checkbox-class', then add this script.

<!-- Add filter-by attribute to filter checkboxes loaded by CMS -->

<script>

// Get the form elements containing the checkboxes
var formElements = document.querySelectorAll('.checkbox-form');

// For each form element
for (el of formElements) {
  // Get the filter-by-text text
   var filterByTextElement = el.querySelector('.filter-by-text').innerText;

   // Get the checkbox element
   var checkboxEl = el.querySelector('.checkbox-class');

   // set attribute to the checkbox element dynamically
   checkboxEl.setAttribute('filter-by', filterByTextElement);
}
</script>

Copy code

Scroll back to top after items have been filtered

For each checkbox add this classes. The checkbox form '.checkbox-form', filter by text text-block '.filter-by-text' and the checkbox element '.checkbox-class', then add this script.

<!-- Scroll back to top after items have been filtered -->

<script>
// Get all the filter buttons by class name
var filterButtons = document.querySelectorAll('.sort-button');

// For each filter button
for (button of filterButtons) {
// When clicked trigger the scrollToElem function to scroll the page back to top
    button.addEventListener('click', scrollToElem, false);
}

// define the scrollToElem function
function scrollToElem() {
        // scroll the browser page in an animation
$('html,body').animate({
  // specify the element to scroll to
    // specify the distance it will scroll to from the top of your element
  scrollTop: $('.collection-list').offset().top - 80

    // specify the duration in milliseconds
}, 1000);
}
</script>
Copy code

Counter For Filtered Items

Define this classes. The collection list item, the collection list and the counter element class.

 <!-- Counter For Filtered Items -->

<script>
// Works best when animation duration is set to 0
function triggerCounter() {
// Get all elements in the CMS collection, store in a variable and convert to an array
 var countVisible = document.querySelectorAll(".collection-list .collection-list-item:not([style='display: none;'])").length;

// Get the element to update the number of items being displayed
 var divEl = document.querySelector(".counter");

// Updated the text of the element
 divEl.innerHTML = `<div>There are <span class="filtered-items-number">${countVisible}</span> items showing on this list</div>`
}

// On page load get the number of all items
window.addEventListener("DOMContentLoaded", triggerCounter, false);

// Listen to DOM when it updates then trigger the counter function
var observer = new MutationObserver(triggerCounter);
var target = document.querySelector(".collection-list");
observer.observe(target, { attributes : true, childList: true, subtree: true, attributeFilter : ['style'] });

</script>
Copy code

Scroll to nth element in collection list after load more

This hack scrolls to a specific element after you click the load more button. Define the nth element number you want to scroll to.

<!-- Scroll to nth element in collection list after load more -->
<script>
var elementToScrollTo = 0;
function scrollToEl() {
var items = document.querySelectorAll('.collection-list .collection-list-item');

// elementToScrollTo is zero-based
// elementToScrollTo is the row number that you want to see into view after scroll
items[elementToScrollTo].scrollIntoView({
   behavior: 'smooth',
   block: 'start',
   inline: 'nearest'
});
elementToScrollTo = elementToScrollTo + 2;
}
const loadMoreBtns = document.querySelector('.load-more-button');
loadMoreBtns.addEventListener('click', () => setTimeout(scrollToEl, 1000), false);
</script>
Copy code

Load All items when a filter or sort button is clicked

To be able to achieve this, you need to define the filter/sort button class and the load more button class, then add this script.

<!-- Load All items when a filter or sort button is clicked -->

<script>
const filterButtonsClass = '.filterBtnClass';
const loadMoreBtnClass = '.btn-load-more';
let filterButtons = document.querySelectorAll(filterButtonsClass);
filterButtons.forEach((button) => {
 button.addEventListener('click', (event) => {
    let loadMoreButton = document.querySelector(loadMoreBtnClass);
    if (loadMoreButton) {
      event.stopPropagation();
      triggerLoadMoreUntilAllItemsLoad(loadMoreButton);
    }   })
})
function triggerLoadMoreUntilAllItemsLoad(loadMoreBtn) {
   if (loadMoreBtn) {
       loadMoreBtn.click();
       setTimeout(500, triggerLoadMoreUntilAllItemsLoad);
   }
}
</script>
Copy code

scroll back to top of collection list when navigating to next page on pagination

Add an ID to the element you need to scroll up to, say list-start.

<script>
function setScrollId() {
   const fsContainer = document.querySelector('#wf-fslib-pagination');
   fsContainer.querySelectorAll('li a').forEach(aEl => {
       aEl.href = '#list-start'
   })
}document.querySelector('.pagination-container').addEventListener('DOMNodeInserted', (e) => {
   setScrollId();
})
</script>
Copy code

change the 'previous' and 'next' text in pagination buttons

Follow the steps below to achieve this functionality

  • Copy the script below after the pagination script
  • Change the 'changedPrevText' and 'changedNextText' texts in the script with the new texts that you would like to replace 'Previous' and 'Next' with respectively
<script>

function checkIfPaginationIsAdded(mutationsList, observer) {
   for(const mutation of mutationsList) {
       if(mutation.type === 'childList') {
         if (mutation.target.classList.contains('pagination-container')) {
          addChangeTextObserver();
          // bodyObserver.disconnect();
         }  
       }
   }
}

function addChangeTextObserver() {

 // Select the node that will be observed for mutations
 const targetNode = document.querySelector('.fs-pagination');

// Options for the observer (which mutations to observe)
 const config = { attributes: true, childList: true, subtree: false };

// Create an observer instance linked to the callback function
 const observer = new MutationObserver(changePrevNextText);

// Start observing the target node for configured mutations
 observer.observe(targetNode, config);  changePrevNextText();
}

function changePrevNextText(mutationsList, observer) {    

   const prevBtn = document.querySelector('.fs-pagination-prev a');
   const nextBtn = document.querySelector('.fs-pagination-next a');
   if (prevBtn) {
       prevBtn.innerText = 'changedPrevText';
   }
   if (nextBtn) {
       nextBtn.innerText = 'changedNextText';
   }
}

document.addEventListener('DOMContentLoaded', () => {
   const body = document.querySelector('body');
   const bodyMutationConfig = { attributes: true, childList: true, subtree: true };
   const bodyObserver = new MutationObserver(checkIfPaginationIsAdded);
   bodyObserver.observe(body, bodyMutationConfig);
   })
</script>
Copy code