chunks
1 week ago
vendor
8 months ago
admin.build.js
1 week ago
admin.js
3 months ago
analytics-tracker.js
4 weeks ago
analytics.build.js
1 week ago
blocks.build.js
1 week ago
carousel.js
1 year ago
custom-player.build.js
1 week ago
documents-viewer-script.js
3 months ago
ep-pdf-lightbox.js
3 months ago
ep-view-count.js
1 week ago
ep-yt-queue.js
4 weeks ago
feature-notices.js
7 months ago
front.js
4 weeks ago
frontend.build.js
3 months ago
gallery-justify.js
1 week ago
gutneberg-script.js
1 month ago
index.html
7 years ago
initCarousel.js
2 years ago
initplyr.js
1 month ago
instafeed.js
4 weeks ago
instagram-shortcode-generator.js
1 month ago
lazy-load.js
6 months ago
license.js
3 months ago
meetup-timezone.js
3 months ago
onboarding.build.js
1 week ago
pdf-gallery-elementor-editor.js
3 months ago
pdf-gallery.js
3 months ago
preview.js
8 months ago
settings.js
3 months ago
sponsored.js
9 months ago
lazy-load.js
150 lines
| 1 | /** |
| 2 | * EmbedPress Lazy Load |
| 3 | * |
| 4 | * Custom lazy loading implementation for iframe embeds using Intersection Observer API |
| 5 | * Only loads iframes when they're about to enter the viewport |
| 6 | * |
| 7 | * @package EmbedPress |
| 8 | * @since 4.0.0 |
| 9 | */ |
| 10 | |
| 11 | (function() { |
| 12 | 'use strict'; |
| 13 | |
| 14 | // Check if Intersection Observer is supported |
| 15 | if (!('IntersectionObserver' in window)) { |
| 16 | console.warn('EmbedPress Lazy Load: IntersectionObserver not supported, loading all iframes immediately'); |
| 17 | loadAllIframes(); |
| 18 | return; |
| 19 | } |
| 20 | |
| 21 | /** |
| 22 | * Get dynamic root margin based on viewport height |
| 23 | * This prevents lazy loading from triggering immediately on short pages |
| 24 | * Uses 50% of viewport height or 200px, whichever is smaller |
| 25 | */ |
| 26 | function getObserverConfig() { |
| 27 | const viewportHeight = window.innerHeight; |
| 28 | const margin = Math.min(200, Math.max(50, viewportHeight * 0.25)); |
| 29 | |
| 30 | return { |
| 31 | rootMargin: margin + 'px 0px', |
| 32 | threshold: 0.01 |
| 33 | }; |
| 34 | } |
| 35 | |
| 36 | const observerConfig = getObserverConfig(); |
| 37 | |
| 38 | /** |
| 39 | * Callback function when iframe placeholder enters viewport |
| 40 | */ |
| 41 | function onIntersection(entries, observer) { |
| 42 | entries.forEach(function(entry) { |
| 43 | if (entry.isIntersecting) { |
| 44 | const placeholder = entry.target; |
| 45 | loadIframe(placeholder); |
| 46 | observer.unobserve(placeholder); |
| 47 | } |
| 48 | }); |
| 49 | } |
| 50 | |
| 51 | /** |
| 52 | * Load the actual iframe from placeholder |
| 53 | */ |
| 54 | function loadIframe(placeholder) { |
| 55 | const iframeSrc = placeholder.getAttribute('data-ep-lazy-src'); |
| 56 | |
| 57 | if (!iframeSrc) { |
| 58 | console.warn('EmbedPress Lazy Load: No data-ep-lazy-src found on placeholder'); |
| 59 | return; |
| 60 | } |
| 61 | |
| 62 | // Create iframe element |
| 63 | const iframe = document.createElement('iframe'); |
| 64 | iframe.src = iframeSrc; |
| 65 | |
| 66 | // Copy style |
| 67 | const iframeStyle = placeholder.getAttribute('data-ep-iframe-style'); |
| 68 | if (iframeStyle) { |
| 69 | iframe.setAttribute('style', iframeStyle); |
| 70 | } |
| 71 | |
| 72 | // Copy all data-ep-iframe-* attributes |
| 73 | Array.from(placeholder.attributes).forEach(function(attr) { |
| 74 | if (attr.name.startsWith('data-ep-iframe-')) { |
| 75 | const iframeAttr = attr.name.replace('data-ep-iframe-', ''); |
| 76 | if (iframeAttr !== 'style') { |
| 77 | iframe.setAttribute(iframeAttr, attr.value); |
| 78 | } |
| 79 | } |
| 80 | }); |
| 81 | |
| 82 | // Copy class (remove placeholder class) |
| 83 | if (placeholder.hasAttribute('class')) { |
| 84 | const classes = placeholder.getAttribute('class').replace(/ep-lazy-iframe-placeholder/g, '').trim(); |
| 85 | if (classes) { |
| 86 | iframe.setAttribute('class', classes); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | // Copy other important attributes |
| 91 | ['data-emid', 'data-embedpress-content', 'data-embed-type', 'title'].forEach(function(attr) { |
| 92 | if (placeholder.hasAttribute(attr)) { |
| 93 | iframe.setAttribute(attr, placeholder.getAttribute(attr)); |
| 94 | } |
| 95 | }); |
| 96 | |
| 97 | // Replace placeholder with iframe |
| 98 | if (placeholder.parentNode) { |
| 99 | placeholder.parentNode.replaceChild(iframe, placeholder); |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | /** |
| 104 | * Fallback: Load all iframes immediately (for unsupported browsers) |
| 105 | */ |
| 106 | function loadAllIframes() { |
| 107 | const placeholders = document.querySelectorAll('.ep-lazy-iframe-placeholder'); |
| 108 | placeholders.forEach(function(placeholder) { |
| 109 | // Add 2 second delay before loading iframe |
| 110 | loadIframe(placeholder); |
| 111 | }); |
| 112 | } |
| 113 | |
| 114 | /** |
| 115 | * Initialize lazy loading |
| 116 | */ |
| 117 | function initLazyLoad() { |
| 118 | const placeholders = document.querySelectorAll('.ep-lazy-iframe-placeholder'); |
| 119 | |
| 120 | if (placeholders.length === 0) { |
| 121 | return; |
| 122 | } |
| 123 | |
| 124 | // Create observer |
| 125 | const observer = new IntersectionObserver(onIntersection, observerConfig); |
| 126 | |
| 127 | // Observe all placeholders |
| 128 | placeholders.forEach(function(placeholder) { |
| 129 | observer.observe(placeholder); |
| 130 | }); |
| 131 | } |
| 132 | |
| 133 | /** |
| 134 | * Run on DOM ready |
| 135 | */ |
| 136 | if (document.readyState === 'loading') { |
| 137 | // Add 2 second delay before initializing lazy load |
| 138 | setTimeout(initLazyLoad, 1000); |
| 139 | } else { |
| 140 | setTimeout(initLazyLoad, 1000); |
| 141 | } |
| 142 | |
| 143 | /** |
| 144 | * Re-initialize for dynamically added content (e.g., AJAX loaded content) |
| 145 | */ |
| 146 | window.epReinitLazyLoad = initLazyLoad; |
| 147 | |
| 148 | })(); |
| 149 | |
| 150 |