Lazy Load for CSS Images - php

I have the following lazy load function which works for <img>.
<script>
document.addEventListener("DOMContentLoaded", function() {
var lazyloadImages;
if ("IntersectionObserver" in window) {
lazyloadImages = document.querySelectorAll(".lazy");
var imageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
var image = entry.target;
image.src = image.dataset.src;
image.classList.remove("lazy");
imageObserver.unobserve(image);
}
});
});
lazyloadImages.forEach(function(image) {
imageObserver.observe(image);
});
} else {
var lazyloadThrottleTimeout;
lazyloadImages = document.querySelectorAll(".lazy");
function lazyload () {
if(lazyloadThrottleTimeout) {
clearTimeout(lazyloadThrottleTimeout);
}
lazyloadThrottleTimeout = setTimeout(function() {
var scrollTop = window.pageYOffset;
lazyloadImages.forEach(function(img) {
if(img.offsetTop < (window.innerHeight + scrollTop)) {
img.src = img.dataset.src;
img.classList.remove('lazy');
}
});
if(lazyloadImages.length == 0) {
document.removeEventListener("scroll", lazyload);
window.removeEventListener("resize", lazyload);
window.removeEventListener("orientationChange", lazyload);
}
}, 20);
}
document.addEventListener("scroll", lazyload);
window.addEventListener("resize", lazyload);
window.addEventListener("orientationChange", lazyload);
}
})
</script>
The function isn't mine and I need to know how to modify it to work for the next example which load images from CSS:
<div class="col-md-2 col-sm-3 col-xs-4 photo" style="padding: 2.5px">
<span onclick="window.location.href=\''.$link.'\';"
class="thumbnail"
role="img"
style="background-image: url(\''.$image.'\'); cursor: pointer; margin: 0; margin-top: 5px;"
aria-label="' . $row["topic_title"] . '"
title="'.$row['topic_title'].'">
</span>
<center>
<p class="name" style="margin 0 2px; color: white; margin-top: 5px;">
' . $title . '
</p>
</center>
</div>
On a page with 24 gifs, the page loads relatively slow and I'd like to change that.
I could load the images as normal using <img>, but I want the page to be more dynamic because using span I have different temathic.
Here is how I managed to do the script and it works correctly.
Hope someone will find it useful.
if (entry.isIntersecting) {
var image = entry.target;
image.src = image.dataset.src;
var imageUrl = "url" + "(" + "'" + image.src + "')";
entry.target.style.backgroundImage = imageUrl;
image.classList.remove("lazy");
imageObserver.unobserve(image);
}

On a page with 24 gifs, the page loads relatively slow and I'd like to
change that.
Images in general are really heavy on websites. That's most likely whats slowing the site down. If your website needs that many GIFs I would firstly look at compression techniques. Search for GIF to WebP converters and file compressors (ImageAlpha, ImageOptim, Handbrake to name a few).
Good luck!

Related

jQuery Splide, responsive height based on image

We got this slide based on Splide, used as article's photo slider, with attached second instance that act as a thumbnail paginator.
At the moment, it doesn't take care of the height of the pics, but just use the height of the taller image, making the thumbnails remain down when a 16/9 image is displayed, leaving a big white space unused.
Even if it is an huge layout swift, we need thumbnails staying glued to the bottom of the image, sliding up or down when an image change, can we achieve this situation?
Currently, my code is:
<!-- Slideshow container -->
<section id="main-carousel" class="splide" role="group" style="margin-top: 30px" >
<div class="splide__track">
<ul class="splide__list">
<?php
$i = 0;
foreach(get_field('gallery') as $image ) {
if ($i == 0) { $active = 'active'; } else { $active = '';}
echo '<li class="splide__slide" data-splide-interval="3000">';
echo '<div class="splide__slide__container" style="max-height: fit-content>';
echo '<a href="' . $image .'" data-lightbox="image-' . ($i + 1) . '">';
echo '<img src="' . $image . '" style="width:100%" />';
echo '</a>';
echo '</div>';
echo '</li>';
$i++;
}
?>
</ul>
</div>
<br class="clear" />
</section>
<script>
var splide = new Splide( '.splide' );
splide.mount();
</script>
<section id="thumbnail-carousel" class="splide" style="margin-top: 10px; height: auto">
<div class="splide__track">
<ul class="splide__list" style="height:auto!important">
<?php
$i = 0;
foreach(get_field('gallery') as $image ) {
if ($i == 0) { $active = 'active'; } else { $active = '';}
echo '<li class="splide__slide" style="height:auto or 100%">';
echo '<img src="' . $image . '" style="width:100%; height: auto or 100%" />';
echo '</li>';
$i++;
}
?>
</ul>
</div>
</section>
<style>
.splide__list {
align-items: flex-start!important;
}
.clear { clear: both; }
</style>
<script>
document.addEventListener( 'DOMContentLoaded', function () {
var main = new Splide( '#main-carousel', {
type : 'loop',
rewind : true,
pagination: false,
arrows : false,
autoHeight: true,
autoWidth: true,
//autoplay : true,
autoStart : true,
lazyLoad: true,
perPage : 1,
perMove: 1,
autoScroll: {
speed: 1,
},
} );
var thumbnails = new Splide( '#thumbnail-carousel', {
fixedWidth : 100,
fixedHeight : 58,
gap : 8,
rewind : true,
pagination : false,
isNavigation: true,
//autoHeight: true,
breakpoints : {
600: {
fixedWidth : 60,
fixedHeight: 44,
},
},
} );
main.sync( thumbnails );
main.mount( window.splide.Extensions );
thumbnails.mount();
} );
</script>
<?php } ?>
You will need to dynamically change the slide height using the height of the next image before the carousel moves to keep the thumbnails 'glued' to the slider.
Use the Splide#on() method to listen to the ready event (to apply the first slide height) and the move event (to apply the slide height when the carousel moves).
To know which slide the carousel is moving to, use the instance property index. To change the slide height, use the property options.
var main = new Splide('#main-carousel');
main.on('ready', function() {
setHeightCarousel(0); // index = 0
})
main.mount();
main.on('move', function() {
const currentIndex = main.index;
setHeightCarousel(currentIndex);
})
And here's how setHeightCarousel(index) could look like. Note I added the class splide__img in the HTML on each <img> tag to target them.
function setHeightCarousel(index) {
const image = document.querySelectorAll('.splide__img')[index];
let imgHeight;
if (image.complete) {
imgHeight = image.naturalHeight;
main.options = {
height: imgHeight + 'px'
}
} else {
image.addEventListener('load', function() {
imgHeight = this.naturalHeight;
main.options = {
height: imgHeight + 'px'
}
})
}
}
Because the ready event fires before the image is loaded the function first checks whether the image is loaded, and if not adds a load event listener. A callback or promise is purposefully avoided here, but can be used to improve the code depending on the implementation.
The naturalHeight property is used to get the intrinsic height of the image, in the presumption you might want to (down)scale the image first.
Here's a working example in a JSFiddle using Splide V4.1.4.
Or view it in a snippet:
document.addEventListener('DOMContentLoaded', function() {
var main = new Splide('#main-carousel', {
type: 'fade',
rewind: true,
pagination: false,
arrows: false,
lazyLoad: 'sequential'
})
var thumbnails = new Splide('#thumbnail-carousel', {
fixedWidth: 100,
fixedHeight: 60,
gap: 10,
rewind: true,
pagination: false,
isNavigation: true,
breakpoints: {
600: {
fixedWidth: 60,
fixedHeight: 44,
},
}
})
main.on('ready', function() {
setHeightCarousel(0);
})
main.sync(thumbnails);
main.mount();
thumbnails.mount();
main.on('move', function() {
const currentIndex = main.index;
setHeightCarousel(currentIndex);
})
function setHeightCarousel(index) {
const image = document.querySelectorAll('.splide__img')[index];
let imgHeight;
if (image.complete) {
imgHeight = image.naturalHeight;
main.options = {
height: imgHeight + 'px'
}
} else {
image.addEventListener('load', function() {
imgHeight = this.naturalHeight;
main.options = {
height: imgHeight + 'px'
}
})
}
}
})
.container {
margin: 1rem 1rem;
}
#thumbnail-carousel .splide__track .splide__list .splide__slide img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* Centers the image */
/*
.splide__slide img {
width: 100%;
height: 100%;
object-fit: scale-down;
}
*/
<script src="https://cdn.jsdelivr.net/npm/#splidejs/splide#4.1.4/dist/js/splide.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/#splidejs/splide#4.1.4/dist/css/splide.min.css">
<div class="container">
<section id="main-carousel" class="splide" aria-label="Beautiful Images">
<div class="splide__track">
<ul class="splide__list">
<li class="splide__slide">
<div class="splide__slide__container">
<img data-splide-lazy="https://via.placeholder.com/250x140" alt="" class="splide__img">
</div>
</li>
<li class="splide__slide">
<div class="splide__slide__container">
<img data-splide-lazy="https://via.placeholder.com/140x250" alt="" class="splide__img">
</div>
</li>
<li class="splide__slide">
<div class="splide__slide__container">
<img data-splide-lazy="https://via.placeholder.com/250x140" alt="" class="splide__img">
</div>
</li>
</ul>
</div>
</section>
<section id="thumbnail-carousel" class="splide">
<div class="splide__track">
<ul class="splide__list">
<li class="splide__slide">
<img src="https://via.placeholder.com/250x140" alt="">
</li>
<li class="splide__slide">
<img src="https://via.placeholder.com/140x250" alt="">
</li>
<li class="splide__slide">
<img src="https://via.placeholder.com/250x140" alt="">
</li>
</ul>
</div>
</section>
</div>
A few notes.
To make lazy load work, the img element in the slide must have the data-splide-lazy attribute that indicates the path or URL to the source file.
By changing the height of the slider and therefore the position of the thumbnails you are shifting the layout. This is generally considered poor UX and can be measured using the Cumulative Layout Shift. Alternatives are to position the thumbnails on top or aside the main carousel, or by centering the 16:9 image (leaving white-space around it versus just below it).

Taking a value from javascript and sending it to a php script with Ajax

I would like to use apache2 and php for my raspberry pi webserver since I already have many php files that I can use.
Everything is installed and working, but now I have to do an asynchronous request to my raspberry:
When I move a slider on my website, without refreshing the page, I want to send the new value to a php/python script.
the structure is inside:
/var/www/html/SCRIPTS (php/python scripts)
/var/www/html/WEB (web interface)
/var/www/html (an index that redirects inside WEB folder)
My index file contains the following code. I have a CSS to create three sliders. When 'oninput' I would like to call the script that sends a string to the server. The script contains the function edited();
<title>JMT Botler 1: admin panel</title>
<style type="text/css">
.slidecontainer {
width: 100%; /* Width of the outside container */
}
.slider {
-webkit-appearance: none; /* Override default CSS styles */
appearance: none;
width: 100%; /* Full-width */
height: 25px; /* Specified height */
background: #d3d3d3; /* Grey background */
outline: none; /* Remove outline */
opacity: 0.7; /* Set transparency (for mouse-over effects on hover) */
-webkit-transition: .2s; /* 0.2 seconds transition on hover */
transition: opacity .2s;
}
</style>
<script type="text/javascript">
function edited(str) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = this.responseText;
}
};
xmlhttp.open('GET', '/var/www/html/SCRIPTS/test_rec.php?v=' + str, true);
xmlhttp.send();
}
}
</script>
</head>
<body>
<div align="center">
<p>STEERING</p>
</div>
<div class="slidecontainer">
<input type="range" min="1" max="179" value="90" class="slider" onchange="edited(this.value)" id="myRange" width="500">
</div>
<div align="center">
<p>Value: <span id="steering">-1</span></p>
</div>
<div align="center">
<p>THROTTLE</p>
</div>
<div class="slidecontainer">
<input type="range" min="1" max="179" value="90" class="slider" id="myRange2" width="500">
</div>
<div align="center">
<p>Value: <span id="throttle">90</span></p>
</div>
<div align="center">
<p>STER OPT</p>
</div>
<div class="slidecontainer">
<input type="range" min="1" max="179" value="90" class="slider" id="myRange3" width="500">
</div>
<div align="center">
<p>Value: <span id="steropt">90</span></p>
</div>
<div align="center">
<p>Value: <span id="demo"></span></p>
</div>
<script type="text/javascript">
var slider = document.getElementById('myRange');
var output = document.getElementById('steering');
var slider2 = document.getElementById('myRange2');
var output2 = document.getElementById('throttle');
var slider3 = document.getElementById('myRange3');
var output3 = document.getElementById('steropt');
var vs = slider.value;
var vt = slider2.value;
var so = slider3.value;
output.innerHTML = slider.value;
output2.innerHTML = slider2.value;
output3.innerHTML = slider3.value;
slider.oninput = function() {
steering.innerHTML = slider.value - 90;
edited("OPT");
}
slider2.oninput = function() {
throttle.innerHTML = slider2.value - 90;
edited("OPT");
}
slider3.oninput = function() {
steropt.innerHTML = slider3.value - 90;
edited("OPT");
}
</script>
</body></html>
Finally the php script that receives the string should write it on a document.
Obviously it does not work. It is my first time building something like that. How much off course am I?
<?php
$ric=$_GET['v'];
$my_file = 'log.txt';
$handle = fopen($my_file, 'a+');
$data = 'NUOVO DATO RICEVUTO';
fwrite($handle, $data);
$new_data = "\n".$ric;
fwrite($handle, $new_data);
?>
Thanks in advance!
I think that the problem resides in this line:
xmlhttp.open('GET', '/var/www/html/SCRIPTS/test_rec.php?v=' + str, true);
Are you sure that this request is correct?
Usually, /var/www/html is outside the document root of the VirtualHost.
Try changing it with:
xmlhttp.open('GET', '/SCRIPTS/test_rec.php?v=' + str, true);
Also, the third parameter of open is deprecated.

javascript hover on dynamic function not working

hai iam trying to place hover in an dynamic image have to show a dynamic div, if remove mouse div has to be hidden, if i over to the div after hover on image div needs to remain visible if i move out from the div it has to be hidden i tried something like this, but not working as expected, If i over to image div appears if i place mouseout tag there it hides the div once i remove the mouse couldn't use the options in the div, if i place the mouse out in div once i remove the mouse from image the div not closing, sorry for bad english as solutions for this case?
<img onmouseover="GoView_respond(<?php echo $print->Friend_id;?>);" onmouseout="ExitView_respond_one(<?php echo $print->Friend_id;?>);">
<div class="respond_request" style="display:none;" id="pending_req_<?php echo $print->Friend_id;?>" >
<p class="user_details" onmouseout="ExitView_respond(<?php echo $print->Friend_id;?>);">
</div>
<script>
function GoView_respond(id){
console.log('hovering');
document.getElementById("pending_req_"+id).style.display="block";
}
var cl=0;
function ExitView_respond(id){
console.log('not hovering');
if(cl!=1){
document.getElementById("pending_req_"+id).style.display="none";
}
}
</script>
Well, there are various ways to achieve this.
You could for example trick by setting a little timeout that will allow the mouse to reach the user details html node and vice-versa.
Let me be more explicit, according to your case
<?php
class Friend
{
public $Friend_id;
public $Friend_details;
public $Friend_image;
public function __construct($id, $details, $image){
$this->Friend_id = $id;
$this->Friend_details = $details;
$this->Friend_image = $image;
}
}
$print = new Friend(1, 'The very first user', 'http://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png');
?>
<img class="user_image" id="user_image_<?php echo $print->Friend_id; ?>" src="<?php echo $print->Friend_image; ?>" alt="some image" />
<div class="user_details" id="user_details_<?php echo $print->Friend_id; ?>">
<h5>User details</h5>
<?php echo $print->Friend_details; ?>
</div>
<style>
.user_details {
display: none;
background-color: lightgray;
width: 250px;
padding: 15px;
}
</style>
<script>
var userImages = document.getElementsByClassName('user_image');
for(var i = 0; i < userImages.length; i++){
var
userImage = userImages[i],
userId = userImage.id.replace('user_image_', ''),
thisUserDetails = document.getElementById('user_details_' + userId),
mouseOutTimeout = 100, // Here is the trick
mouseTimer = null; // Needed in order to hide the details after that little timeout
userImage.addEventListener('mouseout', function(){
mouseTimer = setTimeout(function(){
thisUserDetails.style.display = 'none';
}, mouseOutTimeout);
});
userImage.addEventListener('mouseover', function(){
clearTimeout(mouseTimer);
thisUserDetails.style.display = 'block';
});
thisUserDetails.addEventListener('mouseout', function(){
var _this = this;
mouseTimer = setTimeout(function(){
_this.style.display = 'none';
}, mouseOutTimeout);
});
thisUserDetails.addEventListener('mouseover', function(){
clearTimeout(mouseTimer);
});
}
</script>
Note: I've used getElementsByClassName and addEventListener here, that are not compatible with IE8 and earlier. Check this link for getElementsByClassName compatibility and this one for addEventListener.
Hope it help.

get data on mousehover for different id

I have a listing of products each with differnt ID. Now on frontend I want to get prodouct data(say, name,price and a addtocart button) on mousover.
Here is my code:
This is in loop to get all products:
HTML:
<div class="prod">
<a class="product-image pi_470" title="Cushion Tsavorites" href="/tsavorite/cushion-tsavorites-1328.html"><img height="135" width="135" alt="Cushion Tsavorites" src="/small_image.jpg"></a>
<div style="display: none; margin: -65px 0px 0px 5px; position: absolute; z-index: 30;" class="mouse_hover_470">
<input type="hidden" id="prod_id" value="470">
<h2 class="product-name"><a title="Cushion Tsavorites" href="/tsavorite/cushion-tsavorites-1328.html">Cushion Tsavorites</a></h2>
<div class="price-box">
<span id="product-price-470" class="regular-price">
<span class="price">$387.15</span>
</span>
</div>
<div class="actions">
<button onclick="setLocation('http://dev614.trigma.us/chocolate/index.php/checkout/cart/add/uenc/aHR0cDovL2RldjYxNC50cmlnbWEudXMvY2hvY29sYXRlL2luZGV4LnBocC90c2F2b3JpdGUuaHRtbA,,/product/470/form_key/4BR7w0TqeeO9AC0g/')" class="button btn-cart" title="Add to Cart" type="button"><span><span>Add to Cart</span></span></button>
</div>
</div>
</div>
jQuery:
jQuery(document).ready(function() {
var bla = jQuery('#prod_id').val();
jQuery(".pi_" + bla).mouseover(function() {
//alert("hello");
jQuery(".mouse_hover_" + bla).css("display", "block");
});
jQuery(".pi_" + bla).mouseout(function() {
jQuery(".mouse_hover_" + bla).css("display", "none");
});
});
But Iam getting only data of first product on mouseover. Its not working for rest of products
Looks like you are executing the above block of code in a loop, once per each product. In that case the problem is jQuery('#prod_id').val(); it will always return the value of first element with id prod_id.
In your case you don't have to do that, you can
jQuery(function ($) {
$('.prod .product-image').hover(function () {
$(this).next().show();
}, function () {
$(this).next().hide();
})
});
There is a much, much easier way to do this:
jQuery(document).ready(function() {
jQuery(".product-image").hover(function() {
$(this).next().show();
}, function() {
$(this).next().hide();
});
});
Demo: JSBin
You can use each() function in jQuery
NOTE: Instead of using id="prod_id", use class, i.e class="prod_id". Since you told that the div is dynamically created it is using the same id attribute
Now loop the product div on ready function
jQuery(document).ready(function() {
jQuery('.prod').each(function(){
var bla = jQuery('.prod_id').val();
jQuery(".pi_" + bla).on('mouseover',function() {
//alert("hello");
jQuery(".mouse_hover_" + bla).css("display", "block");
});
jQuery(".pi_" + bla).on('mouseout',function() {
jQuery(".mouse_hover_" + bla).css("display", "none");
});
});
});
You can checkout this jQuery each()
Ashi,
try using
var bla = jQuery(input[id*='prod_id']).val();
instead of
var bla = jQuery('#prod_id').val();
This will give you all the hidden inputs so loop all of them and bind the mouseover event.
For example:
jQuery(input[id*='prod_id']).each(function(){
var bla = jQuery(this).val();
//carry out your logic..
// you can use jquery().live('mouseover'function(){}) for dynamically created html
});
Hope this will work!!
Cheers!!
function handler(ev) {
var target = $(ev.target);
var elId = target.attr('id');
if( target.is(".el") ) {
alert('The mouse was over'+ elId );
}
}
$(".el").mouseleave(handler);
http://jsfiddle.net/roXon/dJgf4/

jquery display loading text on keypress

I need the jquery script for the following
while typing inside the text field, the 'Load' text need to be displayed near the text field.
If i stop typing the 'Load' text need to change as 'Del'
If click this 'Del' Text the text field should be cleared.
In the mean time i need to display the search result for the entered text.
For this i used the following script
$("#lets_search").keyup(function() {
var value = $('#str').val();
$.post('db_query.php',{value:value}, function(data){
$("#search_results").html(data);
});
return false;
});
});
Here is the html part of the file
<form id="lets_search" action="" style="width:400px;margin:0 auto;text-align:left;">
Search:
<div> </div>
<div style="float:left; width:250px;">
<div style="background-color:#fff; padding:3px; width:200px; float:left; border-left:1px solid #eee; border-top:1px solid #eee; border-bottom:1px solid #eee;">
<input name="str" id="str" type="text" style="border:0px; width:150px;">
<div style="float:right; padding-top:3px;" id="loader">Load</div>
</div>
</div>
</form>
<div id="search_results"></div>
In this <div style="float:right; padding-top:3px;" id="loader">Load</div>
I have to display the text (del, Loading etc...)
Please do the needful. Thanks
I think the best way to do this is with a setTimeout, like so:
var pTimeout = null;
$("#lets_search").keyup(function()
{
var value = $('#str').val();
$('#loader').text('Loading...').unbind('click');
if(pTimeout) clearTimeout(pTimeout);
pTimeout = setTimeout(function () { GetResult(value); }, 50);
});
function GetResult(value)
{
$.post('db_query.php',{value:value}, function(data){
pTimeout = null;
$('#loader').text('del').click(function () {
$("#search_results").empty();
$('#str').val('');
});
$("#search_results").html(data);
});
}
There is always a better way of doing it, but must give you the idea.
PS I did not test the code :)
var searchTimeout = null;
$("#str").keyup(function() {
// Clear any existing timeout
if (searchTimeout) {
clearTimeout(searchTimeout);
}
// Put "Load" text in
$('#loader').html('Load');
// Set a timeout for end of typing detection
searchTimeout = setTimeout(function() {
$('#loader').html('Del');
}, 500);
// Get the value from the text field and send it to the server
var value = $(this).val();
$.post('db_query.php',{value:value}, function(data){
$("#search_results").html(data);
});
});
// Clears the search box value
function clearSearch() {
$("#str").val('');
};

Categories