Lazy load images on include content - php

I'm working on this [page][1]
The problem is that Homepage has a lot of items to show, so it loads really slow. The solution I found is to use lazy load on images (I'm using this plugin). It works on the left column (Which is not content included. You can see the images load as you scroll down) but it is not working with the items of the center and right columns which is the content I'm including.
I'm including the center and right column content this way:
<?php include("parts/backbone_tmpl_productos_main.php"); ?>
And this is the contents of the backbone_tmpl_productos_main.php file:
<script id="tmpl_Post" type="template">
<div class="image"><img src="<%= post_item.image_url.url %>" /></div>
<div class="obra_meta">
<span class="nombre_artista"><%
_.each(taxonomy_product_cat, function(item){
if(item.parent === 146){%><%= item.title %><% }
if(item.parent === 216){%><%= item.title %><% }
})
%></span>
<span class="nombre_obra"><%= title %></span>
</div>
<div class="descripcion_obra"></div>
<div class="buy_opts">
<?php if (ICL_LANGUAGE_CODE == 'en') {
echo '<div class="precio pull-left">From: 24.99 €</div>';
}else{
echo '<% if(price != "") {%><div class="precio pull-left"><%= price %></div><% } %>';
}
?>
<div class="pull-right"><button class="btn btn-default boton_comprar comprar"><?=__('COMPRAR');?></button></div>
</div>
</script>
I think the problem that the plugin doesn't work with the include content is because the content is loaded after the plugin loads.
Any idea what's the real problem? how can I fix it?

This wordpress plugin - https://wordpress.org/plugins/unveil-lazy-load/ uses the data-src attribute for lazy-loading. Hence,
Change
<div class="image"><img src="<%= post_item.image_url.url %>" /></div>
To
<div class="image"><img data-src="<%= post_item.image_url.url %>" /></div>
Reference - https://github.com/luis-almeida/unveil/blob/master/jquery.unveil.js

Lazy loading is a JavaScript (browser-side) effect. If has nothing to do with the "include" in PHP.
Basically PHP generates the page, including all includes, and passes to browser. Browser then executes JS and initiates lazy loading.[1] The exact method with how PHP generates the page is irrelevant.
Where the problem lies is most likely with the fact you have another script that appears to be positioning the "product" classes absolutely - presumable from the "datos" object you have in code. The datos script itself might be forcing the loading as otherwise it won't know the size in order to position them - check what's going on in this script.
Also, there's no guarantee what script is going to win; when your lazy-load script runs through all the products, finds they are "top 0" which is "above the fold" and so loads the images straight away. Then the datos script presumably then goes and positions those products below the fold, but it's too late, they are loading (if not already loaded). Can't be sure of the exact mechanics, but this is the most likely scenario.
Solution:
Firstly, check the datos script isn't forcing a load in order to position the item. If it is, do you really need them absolutely positioned? Why not let them flow, then you can remove the src as below? If you do need absolutely position, I think it's "tough".
Secondly: Assuming the datos script is not forcing a load, copy a bit of what coding-idiot suggested, and move the "src" into "data-src", but then you need to modify the lazy-load script to pull the image from there. The code references a "settings.data_attribute" but there is nothing in the documentation. A quick read suggests that setting "dettings.data_atribute" to "src" may work, or ask the developer how to use those settings. (You may also need settings-placeholder at the same time). But by moving out of "src" and into a data attribute you stop the browser from loading initially and let the script do it's job, because...
Finally: Add a timeout in the lazy-load script so it triggers after the other script that positions the products.
Other note: Plugins are great, but if you have this many, you'd probably be better off programming some of these yourself. They appear to conflict. Also, the lazy load plugin could be improved by storing/caching the $(element) jQuery object as opposed to repeatedly recreating it. You also have malformed HTML by adding scripts after the HTML closing tag. Some small improvements that may encourage you to dig deeper into exactly what is going on.
[1] Note: to avoid comments, this is simplifying things as it IS possible to get JS to start before the entire page is loaded; buy you have the include at the bottom of the body so argument is mute.

You could try to add later-reload-script to reload any failed to load
images, that sometime the server refuse to process the incoming request.
Here is the workaround that help me solved the problem.
Add below javascript snippet in your template or view page
function reload_img(idx, no_of_try)
{
console.log("Reload fired " + idx);
var MAX_RETRIES = 100;
var glob = true;
$.each($("img"), function(index, value){
if ( this.naturalWidth == 0)
{
$(this).attr("src", $(this).attr("src"));
console.log( $(this).attr('src'));
glob = false;
}
} );
if ( !glob && no_of_try < MAX_RETRIES )
setTimeout(function(){ reload_img(idx + 1, no_of_try + 1); }, 1500);
}
setTimeout(function(){ reload_img(1,1); }, 1500); // start the reload_img() here
The code simply checks if an element is loaded and rendered.
If not, then retry to load the image with max of 100 retries.

Related

How would I go about adding a download "button" in Swipebox?

I have done the easy bit and actually added a "Download Image" anchor into the swipebox.js html and formatted it with the CSS to make it play properly with the caption/title.
My specific problem lies in trying to add in a new data attribute containing the naked directory url to the image file and using that info to append it to the href of my created anchor so that I can link to the original size for each image.
Most other JQuery lightboxes can do this, but I stuck myself with using Swipebox because it was easier at the time and now it is returning to bite me in the ass.
You can check out what I have done so far # http://kazenracing.com/?page=1964_Griffith
It is not as pretty as some of my other sites, but people will want the larger images.
You can see I am using timthumb for both the thumbnails and the viewed image, so things will run a bit faster on slower connections and so I do not have to create three separate images "by hand". If I did not care about load times and if my customer did not care about load times I would just have the full image be the viewed one and just use timthumb for the thumbnails alone.
You can also see a data-href attribute ready to go on everything except the videos, which I have already accounted for.
EDIT:
What I tried to do before was add in a function inside the swipebox JS called "setDownload" and tried many ways to pull the data-href into the href of the Download anchor.
The last one I tried that worked but only for the first image was:
setDownload : function () {
$('a[data-href]').each(function() {
$('#swipebox-download').attr('href', $('.swipebox').attr('data-href'));
});
},
I even tried following the logic of setTitle, but that got me nowhere.
EDIT: Okay, now it has become; Who has got a better idea than putting it in the title attribute? Like so:
title="Image Name <a id="swipebox-download" href="path/to/image.jpg">Download</a>"
It does accomplish what I want, but it just seems dirty and wrong.
Well I got off my lazy ass and just figured it out the way I wanted it in the first place.
The big problem I had was wrapping my head around using data attributes.
After I got my head around it I pretty much monkeyed the code in using brutaldesign's already existing code for attributes. I even added an option to change the text of the download link in case it is used for something completely different.
Here is the beef of the code I added:
setDownload : function ( index ) {
var datahref = null;
$( '#swipebox-download' ).empty();
if ( elements[ index ] !== undefined ) {
datahref = elements[ index ].datahref;
}
if ( datahref ) {
$( '#swipebox-download' ).append( plugin.settings.downloadText );
$( '#swipebox-download' ).attr( "href", datahref );
} else {
$( '#swipebox-download' ).hide();
}
},
All the changes are documented here on Github.
Well, I guess, thank you for not answering my question.
I found it way more fulfilling figuring it out on my own than having it handed to me.
Oh, and the forked project page is here, if anyone would like to use it.

Compress/Alternative code:-

I spent half a day writing the content section of my index page of my website but when I tried adding another image to the list of images (There is currently 6) it was a very long and annoying process. (Website: http://rikahiyuka.com)
Is there a way to write the code so that it will be easier to add more buttons (The Images)?
Things that are linked per image listed:
- JQuery
- Div (Link)
The most annoying part is adding to the JQuery.
Is there a better way to write the code for the buttons/images in the content section so it is more compact and easier to edit?
Note: The only section of the index.php file that uses PHP is the footer for the year number.
Instead of doing each image individually, just write one function:
function showhide(shownum) {
$("#Ip1, #Ip2, #Ip3, #Ip4, #Ip5, #Ip6").hide();
$("#Il1, #Il2, #Il3, #Il4, #Il5, #Il6, #IDTopic").hide();
$("#Ip" + shownum + ", #IDTopic, #Il" + shownum).show();
}
Then, if you want to show something, you simply call this function:
showhide(6);
You can put it in your HTML (like so:)
<td>
<img id="Iimg1" class="c-img" src="#" title="Show 1" onclick="showhide(1) />
</td>
or edit your JavaScript:
$("#Iimg1").click(function(){
showhide(1);
});
Replacing 1 with whichever link you want to show. This will make it much quicker and much less annoying because you won't have to list out each element to show and hide. Just call the showhide function :) It basically works by, instead of worrying about hiding everything except the one clicked on, hiding ALL of the links. Then, showing the one requested.

Don't load content In X element

My layout is like the above.
1, 2, 3 and 4 divs can be dragged and dropped into any position 1-4 and in the dock. Now these are just php includes. When i drop them in the dock i use css to:
display:none;
This hides everything in the div except the title. Perfect. However the content is still being loaded in the "background" and i plan on having plenty of these "widgets" and i can see this becoming a serious issue with loading all these content.
What i would like to happen is:
If dropped into dock then don't load everything between:
<p><?php include('example.php'); ?></p>
But if dragged back into 1, 2, 3 or 4 then allow the content in the paragraph to be loaded.
I was thinking maybe getting the parent div using jQuery.
I just need a little push in the right direction in regards which language could solve my issue and maybe some simple examples. Now another thing would this be "dynamic" as in as soon as i drag it from the dock to 1, 2, 3 or 4. It would instantly update or would i need to constantly reload either the page or this div to allow the content to check its location and decide whether it is allowed to load or not.
Thank you.
If you want to find out what element you are landing in when you do the drop, it's ->
$('element').droppable({
//other logic
drop: function(event, ui){
//$(this) is now the element you just dropped nito
if($(this).prop('id') == 'dock'){
console.log("This is the Dock...We don't add content here.");
}else{
//function to pull data to your container...$.load() or whatever
}
}
});

Preloading pictures for refresh, cache

I have these two php variables: $img1src and $img2src, (them being PHP is irrelevant as you can echo a php variable anywhere) they both hold a URL of an image. I was wondering if I was able to preload these images, or cache them.
My goal is: when someone refreshes the page I want these pictures to instantly appear in a <img src >.
I'm not going to provide specific code, because I don't want to give you a fish, but rather show how google is a fishing pole.
I googled "php cache images tutorial" just to see what would come up. Below is a great resource.
http://dtbaker.com.au/random-bits/how-to-cache-images-generated-by-php.html
Can't get much better than that.
Caching an image isn't really a job for PHP. PHP should be used to decide whether or not to display it. (There are caching things you can do with PHP, but not in the same sense.) Essentially, what you want to do is make the clients browser request the second image. Once the browser gets the image, it should automatically send an "if-modified-by" parameter in the header. Next time you load the page, the response code should be 304 and your image should load instantly. You can choose from a variety of ways to do this. Load the image with javascript after the page has loaded (to prevent additional load time) or you can just include an image tag that is hidden on the page some where.
I also haven't tested it, but you might be able to send an ajax request to the image directly. I'm not sure if that way would cache it or not.
EDIT:
This isn't the most elegant solution, but it should get the idea across.
JS Example:
<?php
session_start();
if (!isset($_SESSION['graphic'])) $_SESSION['graphic'] = "http://www.tomsfreelance.com/laptop/DSC_0011.JPG";
else $_SESSION['graphic'] = "http://www.tomsfreelance.com/laptop/DSC_0012.JPG";
?>
<html>
<head>
<script>
function loadImage() {
document.getElementById('preload').style.backgroundImage = "url(http://www.tomsfreelance.com/laptop/DSC_0012.JPG)";
}
</script>
</head>
<body onload="loadImage();">
<div id="preload" style="display: none;"></div>
<img src="<?php echo $_SESSION['graphic'];?>">
</body>
</html>
Sure you can, try this javascript:
var image1 = new Image(), image2 = new Image();
image1.src = <?php echo $img1src; ?>;
image2.src = ?<php echo $img2src; ?>;
That should preload the image so when you append an img tag to the DOM the image should appear right away.
If your aim is to make less http requests overall: you can try CSS Sprites and/or Data Url methods of displaying these images. These methods will be the most effective when the images are smaller.

Div doesn't display when using jScrollPane()

This should be exceedingly simple, but here goes. I have a simple div container that gets populated by a Twitter feed (jTweetsAnywhere):
<div id='twitter-feed'></div>
This functionality works fine and gives me a simple container with a Twitter feed, with overflow:auto. Again: works fine, overflow is scrollable with the standard ugly scrollbar.
After loading jquery.jScrollPane.min.js, jquery.scrollpane.css, jquery.mousewheel.js, and mwheelintent.js, and initializing like so:
$(document).ready(function(){
. . .
$("#twitter-feed").jScrollPane();
});
...the #twitter-feed div no longer displays, and no runtime error is thrown.
Thoughts?
My initial guess is that .jsScrollPane() is getting called long before jTweets returns anything. This means that there is a good chance that it is setting the height of the container while its empty, so it probebly is set to 0. Have you tried to give #twitter-feed a static height?
Having the same exact issue..and viewing Chrome built in debugger i've found our problem and posted in the jscrollpane google group..I'm almost afraid we might have to alter jTweetsAnywhere code to get this to work correctly..If this is true, I'll do it and make sure I post the solution here and a link...in a nutshell:
jTweetsAnywhere dynamically creates this before your jScrollPane call:
<div id="twitter-feed">
<div class="jta-tweets-list">
<ul><li>tweet</li><li>tweet</li></ul>
</div>
</div>
After the jScrollPane call, your code inside the #twitter-feed container is modified to function like this:
<div id="twitter-feed">
<div class="jta-tweets-list">
<div class="jspContainer"><!-- I believe this is where the tweets <ul> needs to be loaded? --><div class="jspPane"></div></div>
<ul><li>tweet</li><li>tweet</li></ul>
</div>
</div>
jScrollPane.js has a nifty little method autoReinitialise, that when set to true basically adds a setInterval() that is constantly checking for the content within your target div.
Just make your call to jScrollPane AFTER your jTweetsAnywhere call:
$('.jta-tweets-list').jTweetsAnywhere({ stuff in here })
and pass it an object with autoReinitialise: true-
$('.jta-tweets-list').jScrollPane(
{
autoReinitialise: true
}
);
Hope this helps!

Categories