I have a problem.
A strange problem.
I have this part of code:
Actions.loadWizzard = function(href)
{
alert(1);
var wizardTimer;
var wizardTimer2;
if (navigationObject.getLocation(href) === "ProductInformationWizzard") {
navigationObject.newPage("loading");
wizardTimer = setTimeout("navigationObject.newPage('contentProductInformationWizzard');", 3000);
wizardTimer2 = setTimeout("window.productInformationWizzardObject.init()", 1000);
} else if (navigationObject.getLocation(href) === "contentAdviceWizzard") {
navigationObject.newPage("loading");
wizardTimer2 = setTimeout("window.adviceWizzardObject.init()", 10000);
}
return;
};
And on the normal browser it works excactly as it should work.
As a WRT though (or phonegap app) it doesn't.
It doesn't give me the alert (used for debugging). It doesn't use the setTimeout. evaluates instantly or something. And the loading page is not shown.
yeah, sometimes it shows up once.
Another problem is that the loading div has a GIF img. It;s like a loading img.
But the thing is just static. It's like normal image instead of a animated GIF.
How is this possible.
Some notes to the code:
navigationObject.newPage(page);
This hides the current div i'm viewing and shows the div i pass to it.
window.adviceWizzardObject.init();
This makes an ajax request to a jsonrpc server and then evaluates the data json retreived and set's up the wizard.
Thanks in advance,
Erik
It does work,
But becouse of some caching or something the old versions were loaded or something like that.
Restarting my phone solved the problem.
Related
Some websites have lots of images, so lazyloading seems appropiate to reduce load times and data consumption. But what if you also need to support printing for that website?
I mean, you can try to detect the print event and then load the images, with something like this:
HTML
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
Note: this is a one by one pixels gif dummy image.
JavaScript
window.addEventListener('DOMContentLoaded', () => {
img = document.querySelector('img');
var isPrinting = window.matchMedia('print');
isPrinting.addListener((media) => {
if (media.matches) {
img.src = 'http://unsplash.it/500/300/?image=705';
}
})
});
Note: if you try this in a code playground, remove the DOMContentLoaded event (or simply fork these: JSFiddle | Codepen).
Note: I didn't event bother with the onbeforeprint and onafterprint for obvious reasons.
This will work fine if the image is cached, but then again that's precisely not the point. The image/s should all load and then appear in the printing screen.
Do you have any ideas? Has anyone successfully implemented a print-ready lazyloading plugin?
Update
I've tried redirecting the user after the print dialog is detected, to a flagged version of the website a.k.a website.com?print=true where lazyloading is deactivated and all images load normally.
This method is improved by applying the window.print() method in this flagged print-ready version of the page, opening a new print dialog once all images are finished loading, and showing a "wait for it" message in the meantime at the top of the page.
Important note: this method was tested in Chrome, it does not work in Firefox nor Edge (hence why this is not an answer, but a testimony).
It works in Chrome beacuse the print dialog closes when you redirect to another website (in this case same url but flagged). In Edge and Firefox the print dialog is an actual window and it does not close it, making it pretty unusable.
Based on your desired functionality, I'm not quite sure what you want to do is feasible. As a developer we don't really have control over a users browser. Here are my thoughts as to why this isn't fully possible.
Hooking the event to go and load your missing images won't let you guarantee images will make it from the server into your page. More specifically, the PDF generated for your print preview is going to get generated before your image(s) is done loading, the img.src = "..." is asynchronous. You'd run into similar issues with onbeforeprint as well, unfortunately. Sometimes it works, sometimes it does not (example, your fiddle worked when testing in safari, but did not in Chrome)
You cannot stall or stop the print call -- you can't force the browser to wait for your image to finish loading in the lazy loading context. (I read something about using alerts to achieve this once, but it seemed really hacky to me, was more of a deterrent to printing than stalling)
You cannot force img.src to get that data synchronously in a lazy-load context. There are some methods of doing this, but they are clever hacks -- referenced as pure evil and may not work in always. I found another link with a similar approach
So we have a problem, if the images are not loaded by the time print event is fired, we cannot force the browser to wait until they are done. Sure, we can hook and go get those images on print, but as above points out, we cannot wait for those resources to load before the print preview pops up.
Potential solution (inspired by links in point three as well as this link)
You could almost get away with doing a synchronous XMLHttpRequest. Syncrhonous XMLHTTPRequests will not let you change the responseType, they are always strings. However, you could convert the string value to an arrayBuffer encode it to a base-64 encoded string, and set the src to a dataURL (see the link that referenced clever hacks) -- however, when I tried this I got an error in the jsfiddle -- so it would be possible, if things were configured correctly, in theory. I'm hesitant to say yes you can, since I wasn't able to get the fiddle working with the following (but it's a route you could explore!).
var xhr = new XMLHttpRequest();
xhr.open("GET","http://unsplash.it/500/300/?image=705",false);
xhr.send(null);
if (request.status === 200) {
//we cannot change the resposne type in synchronous XMLHTTPRequests
//we can convert the string into a dataURL though
var arr = new Uint8Array(this.response);
// Convert the int array to a binary string
// We have to use apply() as we are converting an *array*
// and String.fromCharCode() takes one or more single values, not
// an array.
var raw = String.fromCharCode.apply(null,arr);
// This is supported in modern browsers
var b64=btoa(raw);
var dataURL="data:image/jpeg;base64,"+b64;
img.src = dataURL;
}
Work around to enhance the user experience
Something you could do is have some text that only displays in the print version of your page (via #print css media) that says "images are still loading, cancel your print request and try again" and when the images are finished loading, remove that "still waiting on resources try again message" from the DOM. Farther, you could wrap your main content inside an element that inverses the display to none when content is not loaded, so all you see is that message in the print preview dialog.
Going off of the code you posted this could look something like the following (see updated jsfiddle):
CSS
.printing-not-ready-message{
display:none;
}
#media print{
.printing-not-ready-message{
display:block;
}
.do-not-print-content{
display:none;
}
}
HTML
<div class="printing-not-ready-message">
Images are still loading please cancel your preview and try again shortly.
</div>
<div class="do-not-print-content">
<h1>Welcome to my Lazy Page</h1>
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
<p>Insert some comment about picture</p>
</div>
JavaScript
window.addEventListener('DOMContentLoaded', () => {
img = document.querySelector('img');
var isPrinting = window.matchMedia('print');
isPrinting.addListener((media) => {
if (media.matches) {
img.src = 'http://unsplash.it/500/300/?image=705';
//depending on how the lazy loading is done, the following might
//exist in some other call, should happen after all images are loaded.
//There is only 1 image in this example so this code can be called here.
img.onload = ()=>{
document.querySelector(".printing-not-ready-message").remove();
document.querySelector(".do-not-print-content").className=""
}
}
})
});
I'm the author of the vanilla-lazyload script and I've recently developed a feature that makes print of all images possible!
Tested cross browser using this repo code which is live here.
Take a look and let me know what you think!
I'm open to pull requests on GitHub of course.
I wrote a lazy loading jquery plugin that supports showing images on print using the window.onbeforeprint events and mediaQueryListeners.
https://github.com/msigley/Unveil-EX/
//declare custom onbeforeprint method
const customOnBeforePrint = () => {
const smoothScroll = (h) => {
let i = h || 0;
if (i < 200) {
setTimeout(() => {
window.scrollTo(window.scrollY, window.scrollY + i);
smoothScroll(i + 10);
}, 10);
}
};
let height = document.body.scrollHeight;
let newHeight;
while (true) {
smoothScroll(100);
if (newHeight === height) break;
height = newHeight;
}
};
//override the onbeforeprint method
window.onbeforeprint = customOnBeforePrint;
Copy&Paste that block into devtool's console and then try to click print button. That workaround is working for me.
For whoever is in the same boat as I was: when using the browser native loading="lazy", you can simply remove that attribute when printing is going to happen. Below is my jQuery implementation.
window.onbeforeprint = function () {
$('img').each(function () {
$(this).removeAttr('loading')
});
}
Chrome will then just load all images and they will show up when printing.
I'm currently working on a web application which has a page which displays a single chart (a .png image). On another part of this page there are a set of links which, when clicked, the entire page reloads and looks exactly the same as before except for the chart in the middle of the page.
What I want to do is when a link is clicked on a page just the chart on the page is changed. This will speed things up tremendously as the page is roughly 100kb large, and don't really want to reload the entire page just to display this.
I've been doing this via JavaScript, which works so far, using the following code
document.getElementById('chart').src = '/charts/10.png';
The problem is that when the user clicks on the link, it may take a couple of seconds before the chart changes. This makes the user think that their click hasn't done anything, or that the system is slow to respond.
What I want to happen is display a spinner / throbber / status indicator, in place of where the image is while it is loading, so when the user clicks the link they know at least the system has taken their input and is doing something about it.
I've tried a few suggestions, even using a psudo time out to show a spinner, and then flick back to the image.
A good suggestion I've had is to use the following
<img src="/charts/10.png" lowsrc="/spinner.gif"/>
Which would be ideal, except the spinner is significantly smaller than the chart which is being displayed.
Any other ideas?
I've used something like this to preload an image and then automatically call back to my javascript when the image is finished loading. You want to check complete before you setup the callback because the image may already be cached and it may not call your callback.
function PreloadImage(imgSrc, callback){
var objImagePreloader = new Image();
objImagePreloader.src = imgSrc;
if(objImagePreloader.complete){
callback();
objImagePreloader.onload=function(){};
}
else{
objImagePreloader.onload = function() {
callback();
// clear onLoad, IE behaves irratically with animated gifs otherwise
objImagePreloader.onload=function(){};
}
}
}
You could show a static image that gives the optical illusion of a spinny-wheel, like these.
Using the load() method of jQuery, it is easily possible to do something as soon as an image is loaded:
$('img.example').load(function() {
$('#spinner').fadeOut();
});
See: http://api.jquery.com/load-event/
Use the power of the setTimeout() function (More info) - this allows you set a timer to trigger a function call in the future, and calling it won't block execution of the current / other functions (async.).
Position a div containing the spinner above the chart image, with it's css display attribute set to none:
<div> <img src="spinner.gif" id="spinnerImg" style="display: none;" /></div>
The nbsp stop the div collapsing when the spinner is hidden. Without it, when you toggle display of the spinner, your layout will "twitch"
function chartOnClick() {
//How long to show the spinner for in ms (eg 3 seconds)
var spinnerShowTime = 3000
//Show the spinner
document.getElementById('spinnerImg').style.display = "";
//Change the chart src
document.getElementById('chart').src = '/charts/10.png';
//Set the timeout on the spinner
setTimeout("hideSpinner()", spinnerShowTime);
}
function hideSpinner() {
document.getElementById('spinnerImg').style.display = "none";
}
Use CSS to set the loading animation as a centered background-image for the image's container.
Then when loading the new large image, first set the src to a preloaded transparent 1 pixel gif.
e.g.
document.getElementById('mainimg').src = '/images/1pix.gif';
document.getElementById('mainimg').src = '/images/large_image.jpg';
While the large_image.jpg is loading, the background will show through the 1pix transparent gif.
Building on Ed's answer, I would prefer to see something like:
function PreLoadImage( srcURL, callback, errorCallback ) {
var thePic = new Image();
thePic.onload = function() {
callback();
thePic.onload = function(){};
}
thePic.onerror = function() {
errorCallback();
}
thePic.src = srcURL;
}
Your callback can display the image in its proper place and dispose/hide of a spinner, and the errorCallback prevents your page from "beachballing". All event driven, no timers or polling, plus you don't have to add the additional if statements to check if the image completed loading while you where setting up your events - since they're set up beforehand they'll trigger regardless of how quickly the images loads.
Some time ago I have written a jQuery plugin which handles displaying a spinner automatically http://denysonique.github.com/imgPreload/
Looking in to its source code should help you with detecting when to display the spinner and with displaying it in the centre of the loaded image.
I like #duddle's jquery method but find that load() isn't always called (such as when the image is retrieved from cache in IE). I use this version instead:
$('img.example').one('load', function() {
$('#spinner').remove();
}).each(function() {
if(this.complete) {
$(this).trigger('load');
}
});
This calls load at most one time and immediately if it's already completed loading.
put the spinner in a div the same size as the chart, you know the height and width so you can use relative positioning to center it correctly.
Aside from the lowsrc option, I've also used a background-image on the img's container.
Be aware that the callback function is also called if the image src doesn't exist (http 404 error). To avoid this you can check the width of the image, like:
if(this.width == 0) return false;
#iAn's solution looks good to me. The only thing I'd change is instead of using setTimeout, I'd try and hook into the images 'Load' event. This way, if the image takes longer than 3 seconds to download, you'll still get the spinner.
On the other hand, if it takes less time to download, you'll get the spinner for less than 3 seconds.
I would add some random digits to avoid the browser cache.
is anybody familiar with greyBox JavaScript plugin?
orangoo.com/labs/GreyBox/
it's for slideshows and stuff.. I can't get it to work in FF/Safari; it works great in IE, but FF/Safari won't play ball..
orensanz.org/photos.html
would very much appreciate some suggestions..
supposedly there's a google group (forum) for this thing (can't post url.. this thing limits how many urls u can include in a post, it's linked to from their home pg (url above.. oh brother..) but when you link to it you land on a pg that says they've been booted out b/c they violated google's terms of service....;-)
thank you..
It looks to me as if there's a race condition in some of that Javascript code. If the image isn't in cache, then this looks to me like it'll never make the image box visible:
if(gb_type == "image") {
if(img_holder.width != 0 && img_holder.height != 0) {
var width = img_holder.width;
var height = img_holder.height;
GB.width = width;
GB.height = height;
setupOuterGB();
if(GB.use_fx) {
AJS.setOpacity(frame, 0);
AJS.fx.fadeIn(frame);
}
}
}
else {
GB.width = frame.offsetWidth;
GB.height = frame.offsetHeight;
setupOuterGB();
}
In think that code should be called as the "load" handler for the image. Note that your page works fine in Firefox the second time you click on any particular image.
if(GB.show_loading) {
AJS.AEV(window, 'load', function(e) {
loaded();
});
}
else {
loaded();
}
Try putting these lines on either a timeout or replace the lower loaded() with AJS.AEV(window, 'load', function(e) {loaded();});
(I couldn't add comment, nothing happens when click on 'add comment'..)
yes I know I can use other lightboxes.. but what I do need is one in which slideshow lands in photo the user CLICKED.. at work I've been using this one, flowplayer.org/tools/demos/scrollable/easing.html, but when you tell it to start at a given photo (not photo 1) it SLIDES towards it.. I need one in which it just lands on specified photo without the sliding effect -- other than that this one would be perfect
a lot of slick JS lightboxes out there have 'next' button on top of photo itself and other stuff obstructing photo a bit, I don't want that.. ) oh man, I still can't get this thing to work AT ALL in Safari, whereas examples they have online (orangoo.com/labs/GreyBox/) work fine in Safari, I don't get this.. thank you for your help (btw: I tried many diff settings for setTimeout, all the way from 1000 milliseconds to about 30,000.. either way Safari won't touch it.. :-(
I'm presenting a simple animation using img.src replace and the <canvas> tag. At present it's only expected to work in FireFox (FF 3.5.3, Mac OS X 10.5.5), so cross-browser compatibility isn't (yet) an issue.
When the page is first loaded, or loaded into an new window or tab, all seems to work as expected, and the cache behavior on a simple reload does not seem to be an issue; however, if I try to force a reload with shift-reload, I get a problem. Even though the images have been pre-loaded, the preloaded images for the animation don't seem to be available to the browser which then tries to load each new img.src from the server.
Am I looking at a browser bug here, or is there something buggy in my code that I can't see? This is my first shot at implementing a js class, so there might be a lot here that I don't understand.
Any insight from the assembled wise here would be welcome. You can see what I'm talking about at:
http://neolography.com/staging/mrfm/spin-sim.html
Thanks,
Jon
When you shift reload you're telling the browser to reload - not from the cache.
So it shouldn't be a surprise that you're getting the images from the server.
Images can be preloaded in javascript with the following code:
img = new Image();
img.src = "your/image/path";
If you want the images loaded before you use them that might help.
I had a look at your code and you have the following in document.ready()
function countLoadedImages() {
loadedImgs++;
if (loadedImgs == images.length){
$("#loading-image").hide();
$("#controls").fadeIn(100);
}
}
animation = new simAnim("snap", "stripchart", 800, deriveFrameData(spindata));
the animation = new simAnim line is executed regardless if all 100 images are loaded or not...
One possibility to fix this would be to move that line inside the countLoadedImages function like so:
function countLoadedImages() {
loadedImgs++;
if (loadedImgs == images.length){
$("#loading-image").hide();
$("#controls").fadeIn(100);
animation = new simAnim("snap", "stripchart", 800, deriveFrameData(spindata));
}
}
this way that function will be executed once all the images have loaded
Thanks to ekhaled, who tried. I'm now satisfied that this is a browser bug:
Mozilla bug #504184
I have a stripped down example at http://neolography.com/staging/shift-reload/shift-reload-testcase.html which I will leave up. I encourage all to vote for this bug in the mozilla bug tracker so that it will get fixed.
j
There is a tree menu in my application and on click of the menu items, it loads a url in a iFrame. I like to set the focus in an element of the page loaded in the iFrame.
I'm using this code, and it works perfectly in all the browsers except IE:
var myIFrame = $("#iframeName");
myIFrame.focus();
myIFrame.contents().find('#inputName').focus();
I have tried all different options like using setTimeout, but no chance.
After the page loads, when I hit the tab key, it goes to the second input, which means it's been on the first input, but it doesn't show the cursor!
I am using ExtJS and the ManagedIFrame plugin.
Any help is appreciated.
You need to call the focus() method of the iframe's window object, not the iframe element. I'm no expert in either jQuery or ExtJS, so my example below uses neither.
function focusIframe(iframeEl) {
if (iframeEl.contentWindow) {
iframeEl.contentWindow.focus();
} else if (iframeEl.contentDocument && iframeEl.contentDocument.documentElement) {
// For old versions of Safari
iframeEl.contentDocument.documentElement.focus();
}
}
Is the iFrame visible onload, or shown later? The elements are created in different order which is the basis of the setTimeout approach. Did you try a high value wait time on a set timeout?
Try something like at least a half second to test...IE tends to do things in a different order, so a high timeout may be needed to get it not to fire until render/paint finishes:
$(function(){
setTimeout(function() {
var myIFrame = $("#iframeName");
myIFrame.focus();
myIFrame.contents().find('#inputName').focus();
}, 500);
});
Difficult to troubleshoot without a working example, but you might try hiding and showing the input as well, to force IE to redraw the element.
Something like:
var myIFrame = $("#iframeName");
myIFrame.focus();
myIFrame.contents().find('#inputName').hide();
var x = 1;
myIFrame.contents().find('#inputName').show().focus();
This might jolt IE into displaying the cursor.
I could get IE to focus an input field in an iframe with:
iframe.focus();
var input = iframe...
input.focus();
iframe.contentWindow.document.body.focus();
input.focus();