3

(My users mainly use Chrome and Firefox.)

When a long running action begins, I want to indicate that something is going in by setting the mouse cursor to progress. I want to display this progress on all visible elements - the body as well as buttons, draggables, resizables and whatever else UI elements are available. Of course I also want to reset the mouse cursor for all elements afterwards. So I have to know which is the default style of each element (cursor-pointer, draggable-move, resizable-...).

My approaches:

If I just set the progress cursor for "body", the cursor for buttons and draggables still remains the old one, which can confuse the user:

$("body").css("cursor", "progress");

// do long running stuff

$("body").css("cursor", "default");

If I set the cursor for all elements, I have another problem, since I don't know which elements had which cursor. So buttons, draggables, resizables and so on will loose their cursor afterwards:

$("*").css("cursor", "progress");

// do long running stuff

$("*").css("cursor", "default");

The only working approach I found is:

$("body").css("cursor", "progress");
$("button").css("cursor", "progress");
$(".ui-dialog-titlebar").css("cursor", "progress");
$(".ui-resizable-n").css("cursor", "progress");
$(".ui-resizable-s").css("cursor", "progress");
$(".ui-resizable-w").css("cursor", "progress");
$(".ui-resizable-e").css("cursor", "progress");

// do long running stuff

$("body").css("cursor", "default");
$("button").css("cursor", "pointer");
$(".ui-dialog-titlebar").css("cursor", "move");
$(".ui-resizable-n").css("cursor", "n-resize");
$(".ui-resizable-s").css("cursor", "s-resize");
$(".ui-resizable-w").css("cursor", "w-resize");
$(".ui-resizable-e").css("cursor", "e-resize");

Is there a more elegant / generic approach to do that? Also I'm not sure if I forget to reset a particular JQuery style to its default. I would like to solve this problem for all my pages without thinking about it again.


With "long running action" I mean $.ajax / $.post calls., like this:

// my new magic mouse cursor method which should do what I want
showProgressCursor(true);

$.post(window.location.href, {action: 'reprovide'}, function(data) {
    // should reset all cursor CSS to their correct defaults
    showProgressCursor(false);
});
Wolkenarchitekt
  • 20,170
  • 29
  • 111
  • 174
  • is your "long running stuff" done synchronously or asynchronously? Because if synchronously, then the UI thread won't get to update until everything is done. Keep in mind browser JS is single threaded. – jwl May 23 '13 at 17:19
  • The UI thread will notice when the process is finished. I'm using $.post/$.ajax calls. I'm setting the progress cursor before each call and inside the callbacks I'm resetting it to each default. – Wolkenarchitekt May 23 '13 at 17:31
  • Before you set the cursor types to progress, can you get the current value and store it, then set it back to that stored value once the long-running-process is over? – Zack May 23 '13 at 17:38
  • @ZackT. Hmmm, maybe... If there is a way to save the cursor CSS for *all* elements with non-default cursors into an object in one batch. But I have no idea how to do that. And I would really like to get rid of setting single styles and find a generic approach! For example I also forgot nw-resize, ne-resize, ... - don't know what else I forgot... – Wolkenarchitekt May 23 '13 at 17:50
  • I don't think there would be any built in function to get the current css cursor for every element with non-default cursor. You would have to write it. – Zack May 23 '13 at 17:53
  • I also think you could just remove the css cursor property from the elements and it would change back to the default. – Zack May 23 '13 at 17:55
  • I'm looking at this page, not sure if anything there is useful for you http://www.javascripter.net/faq/stylesc.htm – Zack May 23 '13 at 17:57
  • Also, this post might be helpful if all you want to do is prevent the user from taking action while the ajax call is processing http://stackoverflow.com/questions/192900/wait-cursor-over-entire-html-page – Zack May 23 '13 at 17:59
  • 1
    Or this post seems a little simpler to implement http://stackoverflow.com/questions/10305392/simplest-way-to-set-cursor-to-wait-then-have-all-elements-revert-back – Zack May 23 '13 at 18:00
  • Thanks, Zack! That comment lead me to the solution. This body.wait approach seems to work and the code is elegant. This question is more or less a duplicate of http://stackoverflow.com/questions/10305392/simplest-way-to-set-cursor-to-wait-then-have-all-elements-revert-back. – Wolkenarchitekt May 23 '13 at 18:08

1 Answers1

2

See this fiddle for a way to do this: http://jsfiddle.net/sptDP/

It involves adding a class to your body (or wherever you want) coupled with a CSS universal selector for its descendants. And you should take most of the inevitable ensuing comments regarding how evil universal selectors are with a grain of salt (http://www.kendoui.com/blogs/teamblog/posts/12-09-28/css_tip_star_selector_not_that_bad.aspx).

body.loading, body.loading * {
    cursor:progress !important;
}

FWIW - I would tend to agree with some posters from that other linked thread that a loader GIF or something is better than messing with the cursor. But ultimately you would know your app better than us :)

BjornJohnson
  • 332
  • 1
  • 8