Skip to content

Instantly share code, notes, and snippets.

@hssktm
Last active December 20, 2024 03:03
Show Gist options
  • Save hssktm/b8634d3df640a7e77a26ebdffd2aaf09 to your computer and use it in GitHub Desktop.
Save hssktm/b8634d3df640a7e77a26ebdffd2aaf09 to your computer and use it in GitHub Desktop.
Element Oxygen Builder Load More
{"component":{"id":329,"name":"ct_div_block","options":{"ct_id":329,"ct_parent":3,"selector":"div_block-329-77","original":[],"nicename":"Element Load More"},"depth":4,"children":[{"id":330,"name":"ct_div_block","options":{"ct_id":330,"ct_parent":329,"selector":"div_block-330-77","original":{"custom-attributes":[{"name":"data-load-more-selector","value":"#id-and-class","pinned":true},{"name":"data-load-more","value":"click","pinned":true},{"name":"data-load-more-animation","value":"x-fadeZoomOut","pinned":true},{"name":"data-load-more-animation-initial","value":"false","pinned":true}],"custom-css":"","text-align":"left","flex-direction":"row","display":"flex","gap":"10","padding-top":"10","padding-bottom":"10","padding-left":"20","padding-right":"20","align-items":"center","border-radius":"100","background-color":"#5b2ae0","color":"#ffffff"},"nicename":"Load More","classes":["x-load-more"],"activeselector":false},"depth":5,"children":[{"id":331,"name":"ct_text_block","options":{"ct_id":331,"ct_parent":330,"selector":"text_block-331-77","original":{"custom-attributes":[],"custom-css":"","conditionspreview":"2","globalConditionsResult":true},"nicename":"Text","ct_content":"Load More","classes":[]},"depth":6},{"id":332,"name":"ct_div_block","options":{"ct_id":332,"ct_parent":330,"selector":"div_block-332-77","original":{"flex-direction":"row","display":"flex","gap":"5"},"nicename":"Counts","classes":[]},"depth":6,"children":[{"id":333,"name":"ct_text_block","options":{"ct_id":333,"ct_parent":332,"selector":"text_block-333-77","original":[],"nicename":"Count Next Page","classes":["x-load-more-count"],"ct_content":"0","activeselector":"x-load-more-count"},"depth":7},{"id":334,"name":"ct_text_block","options":{"ct_id":334,"ct_parent":332,"selector":"text_block-334-77","original":[],"nicename":"Text (#242)","ct_content":"of","classes":["x-load-more-separator"]},"depth":7},{"id":335,"name":"ct_text_block","options":{"ct_id":335,"ct_parent":332,"selector":"text_block-335-77","original":[],"nicename":"Count Total","ct_content":"0","classes":["x-load-more-total"],"activeselector":"x-load-more-total"},"depth":7}]},{"id":336,"name":"ct_div_block","options":{"ct_id":336,"ct_parent":330,"selector":"div_block-336-77","original":{"text-align":"left","flex-direction":"row","display":"flex"},"nicename":"Icons","classes":[]},"depth":6,"children":[{"id":337,"name":"ct_fancy_icon","options":{"ct_id":337,"ct_parent":336,"selector":"fancy_icon-337-77","original":{"icon-id":"FontAwesomeicon-plus"},"nicename":"Icon (Plus)","classes":["x-load-more-button-icon-plus","x-load-more-button-icon"]},"depth":7},{"id":338,"name":"ct_fancy_icon","options":{"ct_id":338,"ct_parent":336,"selector":"fancy_icon-338-77","original":{"icon-id":"FontAwesomeicon-refresh"},"nicename":"Icon (Loading)","classes":["x-load-more-button-icon-loading","x-load-more-button-icon"]},"depth":7}]}]},{"id":346,"name":"ct_code_block","options":{"ct_id":346,"ct_parent":329,"selector":"code_block-346-77","original":{"code-css":"/*Icons*/\n.x-load-more-button-icon-loading {\n display: none !important; \n}\n\n.x-loading .x-load-more-button-icon-loading, \n.ct-component .x-load-more-button-icon-loading {\n display: flex !important; \n}\n\n\n.x-loading .x-load-more-button-icon-plus{\n display: none !important; \n}\n\n@keyframes spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(360deg);\n }\n}\n.x-load-more-button-icon-loading {\n animation: spin 0.7s linear infinite;\n}\n\n.ct-component .x-load-more-button-icon-loading {\n animation: spin 0s;\n}\n\n/*End Icons*/\n\n\n/*Animations*/\n\n/*Animation Fade*/\n@keyframes xFade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n.x-fade {\n opacity: 0;\n animation: xFade 0.5s ease-out forwards;\n}\n\n/*Animation Fade Up*/\n@keyframes xFadeUp {\n 0% {\n opacity: 0;\n transform: translateY(-50px);\n }\n 100% {\n opacity: 1;\n transform: translateY(0px);\n }\n}\n\n.x-fadeUp {\n opacity: 0;\n animation: xFadeUp 0.5s ease-out forwards;\n}\n\n/*Animation Fade Down*/\n@keyframes xFadeDown {\n 0% {\n opacity: 0;\n transform: translateY(50px);\n }\n 100% {\n opacity: 1;\n transform: translateY(0px);\n }\n}\n\n.x-fadeDown {\n opacity: 0;\n animation: xFadeDown 0.5s ease-out forwards;\n}\n\n/*Animation Zoom Out*/\n@keyframes xFadeZoomOut {\n 0% {\n opacity: 0;\n transform: scale(1.1);\n }\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n.x-fadeZoomOut {\n opacity: 0;\n transform: scale(1.1);\n animation: xFadeZoomOut 0.5s ease-out forwards;\n}\n\n/*Animation Zoom In*/\n@keyframes xFadeZoomIn {\n 0% {\n opacity: 0;\n transform: scale(0.9);\n }\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n.x-fadeZoomIn {\n opacity: 0;\n transform: scale(0.9);\n animation: xFadeZoomIn 0.5s ease-out forwards;\n}\n\n\n","code-js":"let uniqueIdCounter = 0;\n\nconst initializeUniqueIdCounter = () => {\n const loadMoreButtons = document.querySelectorAll('.x-load-more');\n loadMoreButtons.forEach(button => {\n const containerSelector = button.getAttribute('data-load-more-selector');\n const container = document.querySelector(containerSelector);\n if (container) {\n const allElementsWithId = container.querySelectorAll('[id]');\n allElementsWithId.forEach(el => {\n const parts = el.id.split('-');\n const lastPart = parseInt(parts[parts.length - 1], 10);\n if (!isNaN(lastPart) && lastPart >= uniqueIdCounter) {\n uniqueIdCounter = lastPart + 1;\n }\n });\n }\n });\n};\n\nconst xApplyAnimationDelay = (items, animationInitial) => {\n items.forEach((item, index) => {\n if (!animationInitial) {\n item.style.animationDuration = '0s';\n } else {\n item.style.animationDelay = `${index * 0.2}s`;\n item.style.removeProperty('animation-duration');\n }\n });\n};\n\nconst xGetLastPageNumber = (container) => {\n const paginationWrap = container.querySelector('.oxy-repeater-pages-wrap');\n if (!paginationWrap) return 1;\n const links = paginationWrap.querySelectorAll('.oxy-repeater-pages a.page-numbers:not(.next)');\n if (!links.length) return 1;\n const lastPageLink = links[links.length - 1];\n const match = lastPageLink.href.match(/page\\/(\\d+)\\//);\n return match ? parseInt(match[1], 10) : 1;\n};\n\nconst xGetItemsCountOnPage = async (pageUrl, containerSelector) => {\n try {\n const response = await fetch(pageUrl);\n if (!response.ok) return 0;\n const html = await response.text();\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, 'text/html');\n const items = doc.querySelectorAll(`${containerSelector} > .ct-div-block`);\n return items.length;\n } catch {\n return 0;\n }\n};\n\nconst xInitializeTotal = async (loadMoreButton) => {\n const containerSelector = loadMoreButton.getAttribute('data-load-more-selector');\n const container = document.querySelector(containerSelector);\n if (!container) return;\n const items = container.querySelectorAll(':scope > .ct-div-block');\n const itemsPerPage = items.length;\n const lastPageNumber = xGetLastPageNumber(container);\n let lastPageUrl = null;\n const links = container.querySelectorAll('.oxy-repeater-pages-wrap a.page-numbers:not(.next)');\n if (links.length) {\n const lastPageLink = links[links.length - 1];\n lastPageUrl = lastPageLink.href;\n }\n let lastPageItems = 0;\n if (lastPageUrl) {\n lastPageItems = await xGetItemsCountOnPage(lastPageUrl, containerSelector);\n } else {\n lastPageItems = itemsPerPage;\n }\n const totalItems = (itemsPerPage * (lastPageNumber - 1)) + lastPageItems - itemsPerPage;\n loadMoreButton.dataset.totalItems = totalItems;\n const totalElement = loadMoreButton.querySelector('.x-load-more-total');\n if (totalElement) totalElement.textContent = totalItems;\n};\n\nconst xUpdateLoadMoreCount = async (loadMoreButton) => {\n const countElement = loadMoreButton.querySelector('.x-load-more-count');\n const containerSelector = loadMoreButton.getAttribute('data-load-more-selector');\n const container = document.querySelector(containerSelector);\n if (!container) return;\n const nextPageButton = container.querySelector('.next.page-numbers');\n if (countElement && nextPageButton) {\n const nextPageUrl = nextPageButton.href;\n try {\n const response = await fetch(nextPageUrl);\n if (!response.ok) return;\n const html = await response.text();\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, 'text/html');\n const newItems = doc.querySelectorAll(`${containerSelector} > .ct-div-block`);\n countElement.textContent = newItems.length;\n } catch {}\n }\n};\n\nconst assignSequentialIDs = (mainItem) => {\n if (mainItem.id) {\n const parts = mainItem.id.split('-');\n parts[parts.length - 1] = uniqueIdCounter;\n mainItem.id = parts.join('-');\n }\n mainItem.querySelectorAll('[id]').forEach(el => {\n const parts = el.id.split('-');\n parts[parts.length - 1] = uniqueIdCounter;\n el.id = parts.join('-');\n });\n uniqueIdCounter++;\n};\n\nconst xInitializePageForButton = async (loadMoreButton) => {\n const containerSelector = loadMoreButton.getAttribute('data-load-more-selector');\n const container = document.querySelector(containerSelector);\n if (!container) {\n loadMoreButton.remove();\n return;\n }\n const nextPageButton = container.querySelector('.next.page-numbers');\n if (!nextPageButton) {\n loadMoreButton.remove();\n return;\n }\n const initialItems = container.querySelectorAll(':scope > .ct-div-block');\n const animationInitial = loadMoreButton.getAttribute('data-load-more-animation-initial') !== 'false';\n xApplyAnimationDelay(initialItems, animationInitial);\n const animationClass = loadMoreButton.getAttribute('data-load-more-animation');\n if (animationClass) {\n initialItems.forEach((item) => item.classList.add(animationClass));\n }\n await xInitializeTotal(loadMoreButton);\n xUpdateLoadMoreCount(loadMoreButton);\n};\n\nconst xLoadMoreItems = async (button) => {\n const containerSelector = button.getAttribute('data-load-more-selector');\n const container = document.querySelector(containerSelector);\n if (!container) {\n button.remove();\n return;\n }\n const nextPageButton = container.querySelector('.next.page-numbers');\n if (!nextPageButton) {\n button.remove();\n return;\n }\n const nextPageUrl = nextPageButton.href;\n button.classList.add('x-loading');\n try {\n const response = await fetch(nextPageUrl);\n if (!response.ok) {\n button.remove();\n return;\n }\n const html = await response.text();\n const parser = new DOMParser();\n const doc = parser.parseFromString(html, 'text/html');\n const fetchedContainer = doc.querySelector(containerSelector);\n if (!fetchedContainer) {\n button.remove();\n return;\n }\n const fetchedItems = fetchedContainer.querySelectorAll(':scope > .ct-div-block');\n if (fetchedItems.length > 0) {\n const animationClass = button.getAttribute('data-load-more-animation') || '';\n fetchedItems.forEach((item, index) => {\n const clonedItem = item.cloneNode(true);\n if (animationClass) {\n clonedItem.classList.add(animationClass);\n }\n clonedItem.style.animationDelay = `${index * 0.2}s`;\n assignSequentialIDs(clonedItem);\n container.appendChild(clonedItem);\n if (button.dataset.totalItems) {\n button.dataset.totalItems = parseInt(button.dataset.totalItems, 10) - 1;\n }\n });\n const totalElement = button.querySelector('.x-load-more-total');\n if (totalElement) {\n totalElement.textContent = button.dataset.totalItems;\n }\n const updatedNextPageButton = fetchedContainer.querySelector('.next.page-numbers');\n if (updatedNextPageButton) {\n nextPageButton.href = updatedNextPageButton.href;\n } else {\n nextPageButton.remove();\n button.remove();\n }\n xUpdateLoadMoreCount(button);\n } else {\n button.remove();\n }\n } catch {\n button.remove();\n } finally {\n if (button && document.body.contains(button)) {\n button.classList.remove('x-loading');\n }\n }\n};\n\nconst xHandleScrollLoad = (button) => {\n const rect = button.getBoundingClientRect();\n if (rect.top <= window.innerHeight && !button.classList.contains('x-loading')) {\n xLoadMoreItems(button);\n }\n};\n\nconst xInitializeLoadMoreForButton = (loadMoreButton) => {\n const loadType = loadMoreButton.getAttribute('data-load-more');\n if (loadType === 'scroll') {\n window.addEventListener('scroll', () => xHandleScrollLoad(loadMoreButton));\n } else if (loadType === 'click') {\n loadMoreButton.addEventListener('click', (e) => {\n e.preventDefault();\n const button = e.currentTarget.closest('.x-load-more');\n if (button) {\n xLoadMoreItems(button);\n }\n });\n }\n};\n\nconst xInitialize = () => {\n initializeUniqueIdCounter();\n const loadMoreButtons = document.querySelectorAll('.x-load-more');\n if (loadMoreButtons.length === 0) return;\n loadMoreButtons.forEach((button) => {\n const containerSelector = button.getAttribute('data-load-more-selector');\n const container = document.querySelector(containerSelector);\n if (!container) {\n button.remove();\n return;\n }\n const repeaterPagesWrap = container.querySelector('.oxy-repeater-pages-wrap');\n if (!repeaterPagesWrap) {\n button.remove();\n return;\n }\n repeaterPagesWrap.style.display = 'none';\n xInitializePageForButton(button);\n xInitializeLoadMoreForButton(button);\n });\n};\n\ndocument.addEventListener('DOMContentLoaded', xInitialize);\n","code-php":"<!---->"},"nicename":"Code Css & JS","activeselector":false},"depth":5}]},"classes":{"x-load-more":{"key":"x-load-more","original":{"selector-locked":"true","custom-css":"cursor: pointer;"}},"x-load-more-count":{"key":"x-load-more-count","original":{"selector-locked":"true"}},"x-load-more-separator":{"key":"x-load-more-separator","original":{}},"x-load-more-total":{"key":"x-load-more-total","original":{"selector-locked":"true"}},"x-load-more-button-icon-plus":{"key":"x-load-more-button-icon-plus","original":{"selector-locked":"true"}},"x-load-more-button-icon":{"key":"x-load-more-button-icon","original":{"icon-size":"20","icon-color":"#ffffff"}},"x-load-more-button-icon-loading":{"key":"x-load-more-button-icon-loading","original":{"selector-locked":"true"}}}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment