BackgroundImage component: support specific image sizes and lazy loading
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useSelect } from '@wordpress/data';
|
import { select } from '@wordpress/data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BackgroundImage
|
* BackgroundImage
|
||||||
@@ -6,28 +6,48 @@ import { useSelect } from '@wordpress/data';
|
|||||||
* This component is used to display a background image for a block based on its attributes.
|
* This component is used to display a background image for a block based on its attributes.
|
||||||
*
|
*
|
||||||
* @param {object} props
|
* @param {object} props
|
||||||
* @param {string} props.background_image The url of the background image.
|
* @param {string} props.background_url The desired full size url.
|
||||||
|
* @param {string} props.background_url_lazy Tiny lazy url.
|
||||||
|
* @param {boolean} props.background_lazy Whether or not to lazy load the background image.
|
||||||
* @param {string} props.background_position The background-position property.
|
* @param {string} props.background_position The background-position property.
|
||||||
* @param {boolean} props.background_fixed Toggle for background-attachment: fixed.
|
* @param {boolean} props.background_fixed Toggle for background-attachment: fixed.
|
||||||
* @param {number} props.background_opacity The opacity value applied to the image.
|
* @param {number} props.background_opacity The opacity value applied to the image.
|
||||||
* @returns {*} React JSX
|
* @returns {*} React JSX
|
||||||
*/
|
*/
|
||||||
export default function BackgroundImage({ background_url, background_position = 'center', background_fixed = false, background_opacity = 70 }) {
|
export default function BackgroundImage({
|
||||||
|
background_url,
|
||||||
|
background_url_lazy,
|
||||||
|
background_lazy,
|
||||||
|
background_position = 'center',
|
||||||
|
background_fixed = false,
|
||||||
|
background_opacity = 70,
|
||||||
|
}) {
|
||||||
|
|
||||||
|
if (background_url) {
|
||||||
|
let styles = {
|
||||||
|
backgroundImage: `url(${background_url})`,
|
||||||
|
backgroundPosition: background_position,
|
||||||
|
backgroundSize: 'cover',
|
||||||
|
backgroundAttachment: background_fixed ? 'fixed' : 'scroll',
|
||||||
|
opacity: Number(background_opacity) * 0.01,
|
||||||
|
}
|
||||||
|
|
||||||
|
let attributes = {
|
||||||
|
className: 'badegg-block-background',
|
||||||
|
style: styles,
|
||||||
|
};
|
||||||
|
|
||||||
|
if(background_lazy) {
|
||||||
|
attributes['data-bg'] = background_url;
|
||||||
|
attributes.style.backgroundImage = `url(${background_url_lazy})`;
|
||||||
|
attributes.className += ' lazy-bg';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div { ...attributes } />
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{background_url && (
|
|
||||||
<div
|
|
||||||
className="badegg-block-background"
|
|
||||||
style={{
|
|
||||||
backgroundImage: `url(${background_url})`,
|
|
||||||
backgroundPosition: background_position,
|
|
||||||
backgroundSize: 'cover',
|
|
||||||
backgroundAttachment: background_fixed ? 'fixed' : 'scroll',
|
|
||||||
opacity: Number(background_opacity) * 0.01,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { useSelect } from '@wordpress/data';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BlockSettings
|
* BlockSettings
|
||||||
*
|
*
|
||||||
@@ -12,6 +10,7 @@ import { useSelect } from '@wordpress/data';
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { select } from '@wordpress/data';
|
||||||
import { useState, useEffect } from '@wordpress/element';
|
import { useState, useEffect } from '@wordpress/element';
|
||||||
import apiFetch from '@wordpress/api-fetch';
|
import apiFetch from '@wordpress/api-fetch';
|
||||||
|
|
||||||
@@ -85,7 +84,8 @@ export default function BlockSettings({ attributes, setAttributes }) {
|
|||||||
background_hex,
|
background_hex,
|
||||||
background_tint,
|
background_tint,
|
||||||
background_image,
|
background_image,
|
||||||
background_url,
|
background_lazy,
|
||||||
|
background_size,
|
||||||
background_opacity,
|
background_opacity,
|
||||||
background_contrast,
|
background_contrast,
|
||||||
background_fixed,
|
background_fixed,
|
||||||
@@ -159,7 +159,7 @@ export default function BlockSettings({ attributes, setAttributes }) {
|
|||||||
{ 'background_colour' in attributes && attributes.background_colour && ![0, '0', 'white', 'black'].includes(attributes.background_colour) ? (
|
{ 'background_colour' in attributes && attributes.background_colour && ![0, '0', 'white', 'black'].includes(attributes.background_colour) ? (
|
||||||
<>
|
<>
|
||||||
<SelectControl
|
<SelectControl
|
||||||
label={ __("Background Tint", "badegg") }
|
label={ __("Tint", "badegg") }
|
||||||
value={ background_tint }
|
value={ background_tint }
|
||||||
options={ configOptions.tints }
|
options={ configOptions.tints }
|
||||||
onChange={ (value) => setAttributes({ background_tint: value }) }
|
onChange={ (value) => setAttributes({ background_tint: value }) }
|
||||||
@@ -183,6 +183,12 @@ export default function BlockSettings({ attributes, setAttributes }) {
|
|||||||
onChange={(value) => setAttributes({ background_fixed: value }) }
|
onChange={(value) => setAttributes({ background_fixed: value }) }
|
||||||
__nextHasNoMarginBottom
|
__nextHasNoMarginBottom
|
||||||
/>
|
/>
|
||||||
|
<ToggleControl
|
||||||
|
label={ __('Lazy Loaded', 'badegg') }
|
||||||
|
checked={ background_lazy }
|
||||||
|
onChange={(value) => setAttributes({ background_lazy: value }) }
|
||||||
|
__nextHasNoMarginBottom
|
||||||
|
/>
|
||||||
<RangeControl
|
<RangeControl
|
||||||
__next40pxDefaultSize
|
__next40pxDefaultSize
|
||||||
__nextHasNoMarginBottom
|
__nextHasNoMarginBottom
|
||||||
@@ -199,10 +205,21 @@ export default function BlockSettings({ attributes, setAttributes }) {
|
|||||||
<MediaUploadCheck>
|
<MediaUploadCheck>
|
||||||
<MediaUpload
|
<MediaUpload
|
||||||
onSelect={ (media) => {
|
onSelect={ (media) => {
|
||||||
setAttributes({
|
|
||||||
|
let bgAttributes = {
|
||||||
background_image: media.id,
|
background_image: media.id,
|
||||||
background_url: media.url,
|
background_url: media.url,
|
||||||
});
|
background_url_lazy: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
const image = select('core').getEntityRecord('postType', 'attachment', media.id);
|
||||||
|
|
||||||
|
if(image && image.media_details) {
|
||||||
|
bgAttributes.background_url_lazy = image.media_details.sizes.lazy.source_url;
|
||||||
|
bgAttributes.background_url = image.media_details.sizes.hero.source_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAttributes( bgAttributes );
|
||||||
}}
|
}}
|
||||||
allowedTypes={ ['image'] }
|
allowedTypes={ ['image'] }
|
||||||
value={ background_image }
|
value={ background_image }
|
||||||
@@ -219,7 +236,11 @@ export default function BlockSettings({ attributes, setAttributes }) {
|
|||||||
|
|
||||||
{ background_image != 0 && (
|
{ background_image != 0 && (
|
||||||
<Button
|
<Button
|
||||||
onClick={ () => setAttributes({ background_image: 0, background_url: '' }) }
|
onClick={ () => setAttributes({
|
||||||
|
background_image: 0,
|
||||||
|
background_url: '',
|
||||||
|
background_url_lazy: '',
|
||||||
|
}) }
|
||||||
isDestructive
|
isDestructive
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,59 +1,54 @@
|
|||||||
export default function LazyLoadInit()
|
export default function LazyLoadInit()
|
||||||
{
|
{
|
||||||
document.addEventListener('DOMContentLoaded', LazyLoad());
|
document.addEventListener('DOMContentLoaded', LazyLoad());
|
||||||
document.addEventListener('DOMContentLoaded', LazyBG());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function LazyLoad() {
|
function LazyLoad() {
|
||||||
|
|
||||||
var lazyImages = [].slice.call(document.querySelectorAll('img.lazy'));
|
const lazyElements = [].slice.call(
|
||||||
|
document.querySelectorAll('img.lazy, .lazy-bg')
|
||||||
|
);
|
||||||
|
|
||||||
if ('IntersectionObserver' in window) {
|
if ('IntersectionObserver' in window) {
|
||||||
let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
|
const lazyObserver = new IntersectionObserver((entries, observer) => {
|
||||||
entries.forEach(function(entry) {
|
entries.forEach(entry => {
|
||||||
if (entry.isIntersecting) {
|
if (!entry.isIntersecting) return;
|
||||||
let lazyImage = entry.target;
|
|
||||||
lazyImage.src = lazyImage.dataset.src;
|
|
||||||
|
|
||||||
if(lazyImage.dataset.srcset) {
|
const el = entry.target;
|
||||||
lazyImage.srcset = lazyImage.dataset.srcset;
|
|
||||||
|
// Handle <img>
|
||||||
|
if (el.tagName === 'IMG') {
|
||||||
|
el.src = el.dataset.src;
|
||||||
|
|
||||||
|
if (el.dataset.srcset) {
|
||||||
|
el.srcset = el.dataset.srcset;
|
||||||
}
|
}
|
||||||
|
|
||||||
lazyImage.classList.remove('lazy');
|
el.classList.remove('lazy');
|
||||||
lazyImageObserver.unobserve(lazyImage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle background images
|
||||||
|
else {
|
||||||
|
if (el.dataset.bg) {
|
||||||
|
el.style.backgroundImage = `url("${el.dataset.bg}")`;
|
||||||
|
el.classList.remove('lazy-bg');
|
||||||
|
el.classList.add('lazy-loaded');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
observer.unobserve(el);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
lazyImages.forEach(function(lazyImage) {
|
lazyElements.forEach(el => lazyObserver.observe(el));
|
||||||
lazyImageObserver.observe(lazyImage);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
// Possibly fall back to a more compatible method here
|
// Optional fallback: load everything immediately
|
||||||
}
|
lazyElements.forEach(el => {
|
||||||
}
|
if (el.tagName === 'IMG' && el.dataset.src) {
|
||||||
|
el.src = el.dataset.src;
|
||||||
function LazyBG() {
|
} else if (el.dataset.bg) {
|
||||||
|
el.style.backgroundImage = `url("${el.dataset.bg}")`;
|
||||||
var lazyImages = [].slice.call(document.querySelectorAll('.lazy-bg'));
|
}
|
||||||
|
});
|
||||||
if ('IntersectionObserver' in window) {
|
|
||||||
let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
|
|
||||||
entries.forEach(function(entry) {
|
|
||||||
if (entry.isIntersecting) {
|
|
||||||
let lazyImage = entry.target;
|
|
||||||
lazyImage.computedStyleMap.backgroundImage = `url(${lazyImage.dataset.bg})`;
|
|
||||||
|
|
||||||
lazyImage.classList.remove('lazy-bg');
|
|
||||||
lazyImageObserver.unobserve(lazyImage);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
lazyImages.forEach(function(lazyImage) {
|
|
||||||
lazyImageObserver.observe(lazyImage);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Possibly fall back to a more compatible method here
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,8 +31,16 @@
|
|||||||
"default": 0
|
"default": 0
|
||||||
},
|
},
|
||||||
"background_url": {
|
"background_url": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": ""
|
"default": ""
|
||||||
|
},
|
||||||
|
"background_url_lazy": {
|
||||||
|
"type": "string",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"background_lazy": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
},
|
},
|
||||||
"background_opacity": {
|
"background_opacity": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
@@ -40,7 +48,7 @@
|
|||||||
},
|
},
|
||||||
"background_position": {
|
"background_position": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": ""
|
"default": "center center"
|
||||||
},
|
},
|
||||||
"background_fixed": {
|
"background_fixed": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
Reference in New Issue
Block a user