Why doesn't the cursor update in this JS code? - javascript

I am writing javascript code and I have come to the conclusion that changing the cursor on any/all element(s) of the html page is not affected immediately when executed before CPU-intensive code. Even when moving my mouse around, nothing changes while the code is running.
For example, this code only makes the cursor change AFTER the for loop is done:
$('*').css('cursor', 'wait'); for (let i=0; i<10000000000; i++) ;
And if I run the following, the user won't even see any change at all during the loop:
$('*').css('cursor', 'wait'); for (let i=0; i<10000000000; i++) ; $('*').css('cursor', '');
Any other css change (background color, element sizes, etc) works perfectly, but not the cursor...
Anyway to get around this problem ?
(Was tested on Chrome and Firefox)

can us:
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
html {
height: 100%;
}
body {
height: 100%;
}
</style>
</head>
<body>
<script>
document.body.style.cursor = 'wait'
getData()
function getData() {
for (let index = 0; index < 20; index++) {
console.log(index)
}
endWork()
}
function endWork() {
setTimeout(() => {
document.body.style.cursor = 'default'
alert('change cursor to default')
}, 3000);
}
</script>
</body>
</html>

Related

CSS3 Slide Show Fade Effect not working

http://jsfiddle.net/pdb4kb1a/2/
The code works just fine on JSFiddle, but I cant get it to work when I use it in a HTML/CSS file. Only the 50x200 image is displayed, no signs of the simple slideshow or fade effect. I work in Sublime text, could that create any problems?
var imgArray = [
'http://placehold.it/300x200',
'http://placehold.it/200x100',
'http://placehold.it/400x300'],
curIndex = 0;
imgDuration = 3000;
function slideShow() {
document.getElementById('slider').className += "fadeOut";
setTimeout(function() {
document.getElementById('slider').src = imgArray[curIndex];
document.getElementById('slider').className = "";
},1000);
curIndex++;
if (curIndex == imgArray.length) { curIndex = 0; }
setTimeout(slideShow, imgDuration);
}
slideShow();
#slider {
opacity:1;
transition: opacity 1s;
}
#slider.fadeOut {
opacity:0;
}
<body>
<img id="slider" src="http://placehold.it/50x200">
</body>
JSFiddle executes the javascript code in the window.onload event. You can change this if you click the JavaScript Button in the editor of JSFiddle.
If you change it to No wrap - in <head> you'll see that it doesn't work as well. You should see an error in your console, telling you the reason.
I'm assuming that you're including your script snippet in the head section of your HTML Document.
If you take your code as posted in your question, your slider isn't loaded yet, because the script is executed before your HTML document is fully loaded. You have to wrap the call to your slideShow function inside the onloadevent (or if you're using jQuery you'll probably use $(document).ready(function(){ ... }) instead.
This should do the trick then:
window.onload = function() {
slideShow();
}
Including the script at the bottom of your HTML document should work as well as an alternative.

Not cycling through img .src changes on 'click'

I have set up a piece of javascript that is meant to operate as a slideshow where you have to click right or left to go each way through an array of images. As it is, it only has 3 images and one button (the blue div) for going one way through the array.
I have scoured this code over and over and tried to separate the pieces of it but I could discern no pattern over what works. I have been stuck at this stage for months, and would therefore really appreciate some help.
<!DOCTYPE HTML>
<html>
<head>
<style>
#clicker { width: 200px; height:200px; background: blue; }
#pic { width: 300px; height: 150px; }
</style>
</head>
<body>
<div id="clicker"></div>
<img id="pic" src="models_web.jpg" alt="Icon" />
<script type="text/javascript">
var imgs = ["models_web.jpg","reflex_2.jpg","blue_web.jpg"];
var i = 0;
var addl = document.getELementById("clicker");
function clickrotate() {
document.getElementById("pic").src = imgs[i];
i++
if (i === 2) {i = 0};
}
addl.addEventListener( "click", clickrotate, false ) ;
</script>
</body>
</html>
You have a typo in your script.
var addl = document.getELementById("clicker");
change to var addl = document.getElementById("clicker");
Another thing, your counter increment is wrong. It will reset after viewing the second image, because you check i === 2 after incrementing it.
If you check the console in the developer tools in any modern browser, you will see what's wrong. It will save you the headaches next time.

IE freezes GIF animation when DOM insert

My code has an animated GIF (loading image)
I get the html page in a variable "data" from Ajax call.
$("#content").html(data); // takes about 5 seconds and the GIF animation freezes since IE is single threaded.
Is there a way to write the data line by line with a setTimeout / setInterval function so that the thread is released for a brief moment so that the animation continues?
Fiddle URL:
http://jsfiddle.net/deepakssn/Kp2bM/
Alternate solution I tried:
<style>
#loading {
background: url(loading.gif) no-repeat center center #fff;
display: block;
position: fixed;
height: 500px;
width: 500px;
}
</style>
<script src="../scripts/jquery.js"></script>
<script>
$(window).load(function () {
function writeData(data) {
var yourLines = data.split("\n");
for (var i = 0, j = yourLines.length; i < j; i++) {
var x = setTimeout(function() {
$("#content").append(yourLines[i]);
console.log("Line No :"+[i]+" "+Date.now());
}, 5000);
}
}
function ajaxLoad() {
$.ajax({
url: "test.txt"
}).done(function (data) {
console.log("success"+Date.now());
writeData(data);
//$("#content").html(data);
console.log("loaded data"+Date.now());
});
}
ajaxLoad();
});
</script>
<div id="loading"></div>
<div id="content"></div>
I ran into this problem while adding a 'loading' indicator for one of my projects. I used this which solved the problem for me. Since it's not an image, it doesn't freeze.

jQuery error() function not working in IE

I want to display two images that I have no idea when they will be generated. So I want to use the jquery error function to keep checking if the images exist, and display each. Following code works on every browser except IE. Why does it not work on IE, really appreciate your help.
<style type="text/css">
DIV#loader {
width: 500px;
height: 500px;
overflow: hidden;
}
DIV#loader.loading {
background: url(spinner.gif) no-repeat center center;
}
</style>
<script type="text/javascript">
$(document).ready(function() {
var image_names = new Array(2);
image_names[0] = 'a.jpg';
image_names[1] = 'b.jpg';
var divs = document.getElementsByTagName("div");
for ( var i = 0; i < divs.length; i++) {
showImage(image_names[i], divs[i]);
}
});
function showImage(src, div) {
var img = new Image();
$(img).load(function() {
$(this).hide();
$(div).removeClass('loading').append(this);
$(this).fadeIn();
}).error(function() {
setTimeout(function() {
$(img).attr('src', src);
}, 2000);
}).attr('src', src);
}
</script>
This is the HTML body
<body>
<h1>Image Loading</h1>
<div id="loader" class="loading"></div>
<div id="loader" class="loading"></div>
</body>
It seems like IE does not know the image is generated if it does not exist when the page first loads
It's the $(document).ready({}) part; throws an error in ie for me. Changing it to $(function(){}); seems to work for me at least in IE.
Caching caused the problem. Changed the src to:
$(img).attr('src', src + "?" + (new Date().getTime()));

Wait cursor over entire html page

Is it possible to set the cursor to 'wait' on the entire html page in a simple way? The idea is to show the user that something is going on while an ajax call is being completed. The code below shows a simplified version of what I tried and also demonstrate the problems I run into:
if an element (#id1) has a cursor style set it will ignore the one set on body (obviously)
some elements have a default cursor style (a) and will not show the wait cursor on hover
the body element has a certain height depending on the content and if the page is short, the cursor will not show below the footer
The test:
<html>
<head>
<style type="text/css">
#id1 {
background-color: #06f;
cursor: pointer;
}
#id2 {
background-color: #f60;
}
</style>
</head>
<body>
<div id="id1">cursor: pointer</div>
<div id="id2">no cursor</div>
Do something
</body>
</html>
Later edit...
It worked in firefox and IE with:
div#mask { display: none; cursor: wait; z-index: 9999;
position: absolute; top: 0; left: 0; height: 100%;
width: 100%; background-color: #fff; opacity: 0; filter: alpha(opacity = 0);}
<a href="#" onclick="document.getElementById('mask').style.display = 'block'; return false">
Do something</a>
The problem with (or feature of) this solution is that it will prevent clicks because of the overlapping div (thanks Kibbee)
Later later edit...
A simpler solution from Dorward:
.wait, .wait * { cursor: wait !important; }
and then
Do something
This solution only shows the wait cursor but allows clicks.
If you use this slightly modified version of the CSS you posted from Dorward,
html.wait, html.wait * { cursor: wait !important; }
you can then add some really simple jQuery to work for all ajax calls:
$(document).ready(function () {
$(document).ajaxStart(function () { $("html").addClass("wait"); });
$(document).ajaxStop(function () { $("html").removeClass("wait"); });
});
or, for older jQuery versions (before 1.9):
$(document).ready(function () {
$("html").ajaxStart(function () { $(this).addClass("wait"); });
$("html").ajaxStop(function () { $(this).removeClass("wait"); });
});
I understand you may not have control over this, but you might instead go for a "masking" div that covers the entire body with a z-index higher than 1. The center part of the div could contain a loading message if you like.
Then, you can set the cursor to wait on the div and don't have to worry about links as they are "under" your masking div. Here's some example CSS for the "masking div":
body { height: 100%; }
div#mask { cursor: wait; z-index: 999; height: 100%; width: 100%; }
This seems to work in firefox
<style>
*{ cursor: inherit;}
body{ cursor: wait;}
</style>
The * part ensures that the cursor doesn't change when you hover over a link. Although links will still be clickable.
I have been struggling with this problem for hours today.
Basically everything was working just fine in FireFox but (of course) not in IE.
In IE the wait cursor was showing AFTER the time consuming function was executed.
I finally found the trick on this site:
http://www.codingforums.com/archive/index.php/t-37185.html
Code:
//...
document.body.style.cursor = 'wait';
setTimeout(this.SomeLongFunction, 1);
//setTimeout syntax when calling a function with parameters
//setTimeout(function() {MyClass.SomeLongFunction(someParam);}, 1);
//no () after function name this is a function ref not a function call
setTimeout(this.SetDefaultCursor, 1);
...
function SetDefaultCursor() {document.body.style.cursor = 'default';}
function SomeLongFunction(someParam) {...}
My code runs in a JavaScript class hence the this and MyClass (MyClass is a singleton).
I had the same problems when trying to display a div as described on this page. In IE it was showing after the function had been executed. So I guess this trick would solve that problem too.
Thanks a zillion time to glenngv the author of the post. You really made my day!!!
Easiest way I know is using JQuery like this:
$('*').css('cursor','wait');
css: .waiting * { cursor: 'wait' }
jQuery: $('body').toggleClass('waiting');
Why don't you just use one of those fancy loading graphics (eg: http://ajaxload.info/)? The waiting cursor is for the browser itself - so whenever it appears it has something to do with the browser and not with the page.
To set the cursor from JavaScript for the whole window, use:
document.documentElement.style.cursor = 'wait';
From CSS:
html { cursor: wait; }
Add further logic as needed.
Try the css:
html.waiting {
cursor: wait;
}
It seems that if the property body is used as apposed to html it doesn't show the wait cursor over the whole page. Furthermore if you use a css class you can easily control when it actually shows it.
Here is a more elaborate solution that does not require external CSS:
function changeCursor(elem, cursor, decendents) {
if (!elem) elem=$('body');
// remove all classes starting with changeCursor-
elem.removeClass (function (index, css) {
return (css.match (/(^|\s)changeCursor-\S+/g) || []).join(' ');
});
if (!cursor) return;
if (typeof decendents==='undefined' || decendents===null) decendents=true;
let cname;
if (decendents) {
cname='changeCursor-Dec-'+cursor;
if ($('style:contains("'+cname+'")').length < 1) $('<style>').text('.'+cname+' , .'+cname+' * { cursor: '+cursor+' !important; }').appendTo('head');
} else {
cname='changeCursor-'+cursor;
if ($('style:contains("'+cname+'")').length < 1) $('<style>').text('.'+cname+' { cursor: '+cursor+' !important; }').appendTo('head');
}
elem.addClass(cname);
}
with this you can do:
changeCursor(, 'wait'); // wait cursor on all decendents of body
changeCursor($('#id'), 'wait', false); // wait cursor on elem with id only
changeCursor(); // remove changed cursor from body
I used a adaptation of Eric Wendelin's solution. It will show a transparent, animated overlay wait-div over the whole body, the click will be blocked by the wait-div while visible:
css:
div#waitMask {
z-index: 999;
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 100%;
cursor: wait;
background-color: #000;
opacity: 0;
transition-duration: 0.5s;
-webkit-transition-duration: 0.5s;
}
js:
// to show it
$("#waitMask").show();
$("#waitMask").css("opacity"); // must read it first
$("#waitMask").css("opacity", "0.8");
...
// to hide it
$("#waitMask").css("opacity", "0");
setTimeout(function() {
$("#waitMask").hide();
}, 500) // wait for animation to end
html:
<body>
<div id="waitMask" style="display:none;"> </div>
... rest of html ...
My Two pence:
Step 1:
Declare an array. This will be used to store the original cursors that were assigned:
var vArrOriginalCursors = new Array(2);
Step 2:
Implement the function cursorModifyEntirePage
function CursorModifyEntirePage(CursorType){
var elements = document.body.getElementsByTagName('*');
alert("These are the elements found:" + elements.length);
let lclCntr = 0;
vArrOriginalCursors.length = elements.length;
for(lclCntr = 0; lclCntr < elements.length; lclCntr++){
vArrOriginalCursors[lclCntr] = elements[lclCntr].style.cursor;
elements[lclCntr].style.cursor = CursorType;
}
}
What it does:
Gets all the elements on the page. Stores the original cursors assigned to them in the array declared in step 1. Modifies the cursors to the desired cursor as passed by parameter CursorType
Step 3:
Restore the cursors on the page
function CursorRestoreEntirePage(){
let lclCntr = 0;
var elements = document.body.getElementsByTagName('*');
for(lclCntr = 0; lclCntr < elements.length; lclCntr++){
elements[lclCntr].style.cursor = vArrOriginalCursors[lclCntr];
}
}
I have run this in an application and it works fine.
Only caveat is that I have not tested it when you are dynamically adding the elements.
BlockUI is the answer for everything. Give it a try.
http://www.malsup.com/jquery/block/
This pure JavaScript seems to work pretty well ... tested on FireFox, Chrome, and Edge browsers.
I'm not sure about the performance of this if you had an overabundance of elements on your page and a slow computer ... try it and see.
Set cursor for all elements to wait:
Object.values(document.querySelectorAll('*')).forEach(element => element.style.cursor = "wait");
Set cursor for all elements back to default:
Object.values(document.querySelectorAll('*')).forEach(element => element.style.cursor = "default");
An alternative (and perhaps a bit more readable) version would be to create a setCursor function as follows:
function setCursor(cursor)
{
var x = document.querySelectorAll("*");
for (var i = 0; i < x.length; i++)
{
x[i].style.cursor = cursor;
}
}
and then call
setCursor("wait");
and
setCursor("default");
to set the wait cursor and default cursor respectively.
Lots of good answers already, but none of them mentions the <dialog> element.
Using this element we can create a solution similar to the masking <div>.
Here we use showModal() to "hide" elements, and we use ::backdrop to set the cursor style to wait on the entire page:
function showWaitDialog() {
document.getElementById('id_dialog').showModal();
}
#id_dialog, #id_dialog::backdrop {
cursor: wait;
}
<button onclick="showWaitDialog()">click me</button>
<dialog id="id_dialog">busy...</dialog>
The dialog is hidden by default, and can be shown using either the show() method, or the showModal() method, which prevents clicking outside the dialog.
The dialog can be forced to close using the close() method, if necessary.
However, if your button links to another page, for example, then the dialog will disappear automatically as soon as the new page is loaded.
Note that the dialog can also be closed at any time by hitting the Esc key.
CSS can be used to style the dialog however you like.
The example uses the html onclick attribute, just for simplicity. Obviously, addEventListener() could also be used.
Late to the party but simply give the Html tag an id by targeting
document.documentElement
and in the CSS place at the top
html#wait * {
cursor: wait !important;
}
and simply remove it when you want to stop this cursor.

Categories

Resources