Wait cursor over entire html page - javascript

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.

Related

Is there a way to create a button and a click event on this js function?

I've been trying for more than a day to make three implementations in this code, but still without success.
1° I need to create a button inside this page.
I've already tried to create a very normal button through html and css, but the fireworks page covers and hides the button element.
All elements displayed on the page are purely created within the JS file.
Here are the html and css
HTML
<canvas id="fireworksidButton" href="#" class="myButton">Click here</canvas>
<canvas id="firework"></canvas>
<canvas id="city"></canvas>
CSS
html {
height: 100%;
}
body {
margin: 0;
height: 100%;
}
canvas {
position: absolute;
top: 0;
left: 0;
}
#app {
position: absolute;
top: 0;
left: 0;
}
.myButton {
background-color:#44c767;
border-radius:28px;
border:1px solid #18ab29;
display:inline-block;
cursor:pointer;
color:#ffffff;
font-family:Arial;
font-size:28px;
padding:16px 31px;
text-decoration:none;
text-shadow:0px 1px 0px #2f6627;
}
.myButton:hover {
background-color:#5cbf2a;
}
.myButton:active {
position:relative;
top:1px;
}
2° I need to remove the Loop generated by the function.
I've already tried disabling this render action, but unfortunately it didn't work.
Here is the part of the script that renders the loop action.
let _pre = OrbitCalculator.pre_render();
(function loop(count) {
if (render_end) {
render_end = false;
_pre = OrbitCalculator.pre_render();
loop(0);
return;
}
if (count === MAX_AMOUNT_OF_FIREWORKS) {
count--;
} else {
fireworks.push(_pre[count]);
}
setTimeout(() => loop(++count), INTERVAL);
})(0);
3° I need to create a click event so that when the button is clicked, the function will be executed.
I´d like wrappe the function that triggers the Loop with the code below if it make sense.
function fireworksTrigger(){
document.querySelector('#fireworksidButton').addEventListener("click", async () => {
});
To make the function run, there is a dependence of the following library:
We can find the library inserted in the compiler´s settings.
[Library]https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.3.3/pixi.min.js
Here is the whole code running on the compiler. 599 Lines of code. That´s why i didn`t post the whole script here.
[Fireworks]https://codepen.io/paulodoporto/pen/Jjverod
What should I do please? Any Light?
Thank you so much in advance!
First i dont think that putting the button inside the canvas element is the best way to do it, you might just want to do <button class='myButton'>Click here<button>. To make the button not be covered by the canvas, i would suggest that you change the z-index like freedomn-m said. A higher z-index means that its placed higher when rendering, so make sure that the button has a higher z-index than the canvas. Alternatively, you can just put the button html after the canvas and that should automatically make the button on thop, since its rendered after.
I'm not 100% sure what your trying do do here but it looks like your using recursion so i would just use async and then sleep like this
const sleep = ms => new Promise(res => setTimeout(res, ms));
(async () => {
/*whatever u wanna do*/
await sleep(2);
})();
You should just be able to put whatever function u wanna call inside the addeventlistener('click',//whatever') but this might not work unless you call the function fireworksTrigger in a main/setup run before the main loop starts
Hope this helps

Run a javascript function from HTML events

I'm working on a project that animate on page scroll.
This is the element I want to animate.
<h1 style="position: relative; top: 0; left: 0;"
onscroll="animateAfterPosition(200)"
data-animate-left="50px" data-animate-top="50px"
data-animate-time="0.2s">Animation on scroll</h1>
This is my JavaScript
function animateAfterPosition(scroll) {
console.log(scroll);
function(){
if (window.scrollY <= scroll) {
this.classList.add('animateAfterPosition');
} else {
this.classList.remove('animateAfterPosition');
}}
And this is my CSS
.animateAfterPosition {
transition: attr(data-animate-time);
left: attr(data-animate-left);
top: attr(data-animate-top);}
I need to run the function animateAfterPosition from the html. I expected to run the function with onscroll event, but it doesn't work. So how can I do this?
Edit
I found that css attr() is only working with the content: property and I managed to do it with JavaScript
You need to add selector to toggle class the animation. And your current css doesn't have enough height to make scrolling window. Here's an simple snippet to run your function onload, update onscroll and toggling class.
var dataAnimate = document.querySelector('[data-animate]');
function animateAfterPosition(scroll) {
dataAnimate.classList.toggle('active', window.scrollY <= scroll);
}
window.addEventListener("scroll", function() {
return animateAfterPosition(200);
});
.animateAfterPosition {
transition: attr(data-animate-time);
left: attr(data-animate-left);
top: attr(data-animate-top);
}
[data-animate] {
height: 1000px;
}
<body onload="animateAfterPosition(200)">
<h1 style="position: relative; top: 0; left: 0;"data-animate-left="50px" data-animate-top="50px" data-animate-time="0.2s" data-animate>Animation on scroll</h1>
</body>
Fiddle: https://jsfiddle.net/rafonzoo/phmg0u46/
A minimalistic solution
You can configure it using the first 4 variables in the function. I recommend adding the indicator class to the body itself and then use a selector like body.beyond-that-point h1. This way, it's possible to make several tags behave differently as the scrolling happens.
You can test it here
This version uses a fancier effect but the logic behind is the same.
https://deneskellner.com/stackoverflow-examples/62623588/index.html
<!doctype html>
<html>
<style>
body.beyond-that-point {background:silver;}
div.text {padding:75vh 0px;text-align:center;}
</style>
<body>
<div class="text">
Scroll me down and the background will change
</div>
<script>
setTimeout(function() {
var amount = 100; // how many pixels before the miracle happens
var beyondClass = 'beyond-that-point'; // this class will be added
var targetSelector = 'body'; // which element to add the class to
var checkMS = 20; // check scroll position every N milliseconds
var eClass = document.querySelector(targetSelector).classList;
setInterval(function() {
var y = window.scrollY;
var c = beyondClass;
var isBeyond = !!(y>=amount)?1:0;
if(isBeyond==1) if(!eClass.contains(c)) eClass.add(c);
if(isBeyond==0) if( eClass.contains(c)) eClass.remove(c);
},checkMS);
},1);
</script>
</body>
</html>
Note: there are better ways to check DOM readiness but for simplicity I used setTimeout here. Feel free to change it.

What is missing within my javascript for a disappearing navbar?

I want to avoid jQuery so I can get a better feel for Javascript. For now I have a Codepen set up that displays a large majority of my first project. I know the code is probably sloppy and I am a beginner. I simply want to get the JS working with my navbar completely disappearing onScroll then I will optimize it from there. Thanks!
I have searched youtube, google, SO but everyone seems to use jQuery.
https://codepen.io/dev20tx/pen/wbKyJq
The CSS:
.nav {
border-bottom: 1px solid #EAEAEB;
text-align: right;
height: 70px;
line-height: 70px;
position: fixed;
top: 0;
left: 0;
width: 100%;
background-color: white;
opacity: 0.8;
z-index: 2;
}
And the Javascript:
window.onscroll = function() {navFunction()};
function navFunction() {
if (document.body.scrollTop > 50 ||
document.documentElement.scrollTop > 50) {
document.queryselector(".nav").className = "test";
} else {
document.queryselector(".nav").className = "";
}
}
Disappearing navbar.
I've updated the codepen at https://codepen.io/anon/pen/rgOdXy
Following is the updated JavaScript code, first problem was that you was attaching event listener to window, instead of the element which is to be scrolled and second mistake was the spelling mistake of querySelector method
function navFunction(e) {
if (e.target.scrollTop > 50 || document.documentElement.scrollTop > 50) {
document.querySelector(".nav").className = "nav test";
} else {
document.querySelector(".nav").className = "nav";
}
}
document.querySelector(".container").addEventListener("scroll",navFunction);
Allright, so, few things.
First, queryselector should be querySelector (with a capital S). Also note that setting the .nav's className to "test" or "" will remove the "nav" class from that element.
Second, you should make sure you attach the onscroll event after the page has loaded.
Lastly, you're attaching the onscroll event to the window, but you actually want to attach it to the .container element, as that's the element you're scrolling.
I'm not just throwing the entire solution in your lap, as you seem to want to play around yourself a little bit. If you do want a more elaborate answer, don't hesitate to ask.

Scroll event background change

I am trying to add a scroll event which will change the background of a div which also acts as the window background (it has 100% width and height). This is as far as I get. I am not so good at jquery. I have seen tutorials with click event listeners. but applying the same concept , like, returning scroll event as false, gets me nowhere. also I saw a tutorial on SO where the person suggest use of array. but I get pretty confused using arrays (mostly due to syntax).
I know about plugins like waypoints.js and skrollr.js which can be used but I need to change around 50-60 (for the illusion of a video being played when scrolled) ... but it wont be feasible.
here is the code im using:-
*
{
border: 2px solid black;
}
#frame
{
background: url('1.jpg') no-repeat;
height: 1000px;
width: 100%;
}
</style>
<script>
$(function(){
for ( i=0; i = $.scrolltop; i++)
{
$("#frame").attr('src', ''+i+'.jpg');
}
});
</script>
<body>
<div id="frame"></div>
</body>
Inside your for loop, you are setting the src attribute of #frame but it is a div not an img.
So, instead of this:
$("#frame").attr('src', ''+i+'.jpg');
Try this:
$("#frame").css('background-image', 'url(' + i + '.jpg)');
To bind a scroll event to a target element with jQuery:
$('#target').scroll(function() {
//do stuff here
});
To bind a scroll event to the window with jQuery:
$(window).scroll(function () {
//do stuff here
});
Here is the documentation for jQuery .scroll().
UPDATE:
If I understand right, here is a working demo on jsFiddle of what you want to achieve.
CSS:
html, body {
min-height: 1200px; /* for testing the scroll bar */
}
div#frame {
display: block;
position: fixed; /* Set this to fixed to lock that element on the position */
width: 300px;
height: 300px;
z-index: -1; /* Keep the bg frame at the bottom of other elements. */
}
Javascript:
$(document).ready(function() {
switchImage();
});
$(window).scroll(function () {
switchImage();
});
//using images from dummyimages.com for demonstration (300px by 300px)
var images = ["http://dummyimage.com/300x300/000000/fff",
"http://dummyimage.com/300x300/ffcc00/000",
"http://dummyimage.com/300x300/ff0000/000",
"http://dummyimage.com/300x300/ff00cc/000",
"http://dummyimage.com/300x300/ccff00/000"
];
//Gets a valid index from the image array using the scroll-y value as a factor.
function switchImage()
{
var sTop = $(window).scrollTop();
var index = sTop > 0 ? $(document).height() / sTop : 0;
index = Math.round(index) % images.length;
//console.log(index);
$("#frame").css('background-image', 'url(' + images[index] + ')');
}
HTML:
<div id="frame"></div>
Further Suggestions:
I suggest you change the background-image of the body, instead of the div. But, if you have to use a div for this; then you better add a resize event-istener to the window and set/update the height of that div with every resize. The reason is; height:100% does not work as expected in any browser.
I've done this before myself and if I were you I wouldn't use the image as a background, instead use a normal "img" tag prepend it to the top of your page use some css to ensure it stays in the back under all of the other elements. This way you could manipulate the size of the image to fit screen width better. I ran into a lot of issues trying to get the background to size correctly.
Html markup:
<body>
<img src="1.jpg" id="img" />
</body>
Script code:
$(function(){
var topPage = 0, count = 0;
$(window).scroll( function() {
topPage = $(document).scrollTop();
if(topPage > 200) {
// function goes here
$('img').attr('src', ++count +'.jpg');
}
});
});
I'm not totally sure if this is what you're trying to do but basically, when the window is scrolled, you assign the value of the distance to the top of the page, then you can run an if statement to see if you are a certain point. After that just simply change run the function you would like to run.
If you want to supply a range you want the image to change from do something like this, so what will happen is this will allow you to run a function only between the specificied range between 200 and 400 which is the distance from the top of the page.
$(function(){
var topPage = 0, count = 0;
$(window).scroll( function() {
topPage = $(document).scrollTop();
if(topPage > 200 && topPage < 400) {
// function goes here
$('#img').attr('src', ++count +'.jpg');
}
});
});

Temporarily disable all onclick events and bind them back

How to disable all onclick events on a page, bind my custom function, and after the execution enable all the previous events?
I'm building a bookmarklet, which should work on any already loaded page and I'm using jQuery to handle my custom logic (the page is jquerified after it is loaded). Note, that I don't have any control which events and when are being bound.
Currently the best stable solution i found is to unbind the events, bind by custom function preventing the default action and then, reload the page. This works, however I want to avoid the reload. A partial workaround would be to reload the page and scroll to the previous position (how to achieve this effect?). Some possible solution would use iframes, but I'd prefer to avoid this.
it's easier to lay a div-element over all... something like
CSS
.noclick {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 9999; /* or maybe higher */
background-color: transparent;
}
jQuery
jQuery(document).ready(function() {
jQuery('body').append('<div class="noclick" />');
});
A nice way I've seen it done, and done it myself is to use a modal 'mask' overlay.
The grayed out transparent mask that covers the entire page, except for the element you're interacting with, eg. modal popup window.
One more way is to use the jQuery BlockUI plugin.
You can reassign the onclick to another property and than override it.
Example with one element
var btn = document.getElementById("button");
btn._onclick = btn.onclick;
btn.onclick = function(){ return false; };
and when you want to transfer it back to the original event
var btn = document.getElementById("button");
if (btn._onclick) {
btn.onclick = btn._onclick;
btn._onclick = null;
}
It depends on whether your onclick event is dependent on the element being clicked (i.e. whether it needs to know which element was clicked):
If it's independent, then you can just add an event handler to the body element or other parent (because the parent event gets called first, then the child, which is what you want):
$('body').click(function() { /* your code here */});
It it is dependent on the the element, then you can access the previous onclick event code that has been registered in the 'click' property of element which is being clicked, so something like this (probably being a little more specific with the selectors):
$('body *').each(function() {
var previousClick = this.click;
this.click = null; // remove previous
$(this).click(function() { /* your code here */});
$(this).click(function() { previousClick();}); // run the code that was already there.
})
Some modification algorhythm's answer.
The idea is to "cover" the link by a transparent element. You can use a pseudo element (e.g. :after).
To prevent "tab key" set tabindex:
<a href="..." tabindex="-1">
Mark link with a class "disabled" on click:
$('a').on('click', function(){ $(this).addClass('disabled') })
Add css:
a.disabled:after {
position: absolute;
content: "";
display: block;
background: white;
opacity: 0.5; // optional
z-index: 999;
left: 0;
top: 0;
bottom: 0;
right: 0;
}
$('a').on('click', function(){ $(this).addClass('disabled') });
a.disabled:after {
position: absolute;
content: "";
display: block;
background: white;
opacity: 0.5; // optional
z-index: 999;
left: 0;
top: 0;
bottom: 0;
right: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a hreh="#" tabindex="-1">The Link</a>

Categories

Resources