Hmm... In Firefox, you can use explicitOriginalTarget
to pull the element that was clicked on. I expected toElement
to do the same for IE, but it does not appear to work... However, you can pull the newly-focused element from the document:
function showBlur(ev)
{
var target = ev.explicitOriginalTarget||document.activeElement;
document.getElementById("focused").value =
target ? target.id||target.tagName||target : '';
}
...
<button id="btn1" onblur="showBlur(event)">Button 1</button>
<button id="btn2" onblur="showBlur(event)">Button 2</button>
<button id="btn3" onblur="showBlur(event)">Button 3</button>
<input id="focused" type="text" disabled="disabled" />
Caveat: This technique does not work for focus changes caused by tabbing through fields with the keyboard, and does not work at all in Chrome or Safari. The big problem with using activeElement
(except in IE) is that it is not consistently updated until after the blur
event has been processed, and may have no valid value at all during processing! This can be mitigated with a variation on the technique Michiel ended up using:
function showBlur(ev)
{
// Use timeout to delay examination of activeElement until after blur/focus
// events have been processed.
setTimeout(function()
{
var target = document.activeElement;
document.getElementById("focused").value =
target ? target.id||target.tagName||target : '';
}, 1);
}
This should work in most modern browsers (tested in Chrome, IE, and Firefox), with the caveat that Chrome does not set focus on buttons that are clicked (vs. tabbed to).
One possible solution uses JavaScript on the client.
The client algorithm:
- Generate a random unique token.
- Submit the download request, and include the token in a GET/POST field.
- Show the "waiting" indicator.
- Start a timer, and every second or so, look for a cookie named "fileDownloadToken" (or whatever you decide).
- If the cookie exists, and its value matches the token, hide the "waiting" indicator.
The server algorithm:
- Look for the GET/POST field in the request.
- If it has a non-empty value, drop a cookie (e.g. "fileDownloadToken"), and set its value to the token's value.
Client source code (JavaScript):
function getCookie( name ) {
var parts = document.cookie.split(name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
function expireCookie( cName ) {
document.cookie =
encodeURIComponent(cName) + "=deleted; expires=" + new Date( 0 ).toUTCString();
}
function setCursor( docStyle, buttonStyle ) {
document.getElementById( "doc" ).style.cursor = docStyle;
document.getElementById( "button-id" ).style.cursor = buttonStyle;
}
function setFormToken() {
var downloadToken = new Date().getTime();
document.getElementById( "downloadToken" ).value = downloadToken;
return downloadToken;
}
var downloadTimer;
var attempts = 30;
// Prevents double-submits by waiting for a cookie from the server.
function blockResubmit() {
var downloadToken = setFormToken();
setCursor( "wait", "wait" );
downloadTimer = window.setInterval( function() {
var token = getCookie( "downloadToken" );
if( (token == downloadToken) || (attempts == 0) ) {
unblockSubmit();
}
attempts--;
}, 1000 );
}
function unblockSubmit() {
setCursor( "auto", "pointer" );
window.clearInterval( downloadTimer );
expireCookie( "downloadToken" );
attempts = 30;
}
Example server code (PHP):
$TOKEN = "downloadToken";
// Sets a cookie so that when the download begins the browser can
// unblock the submit button (thus helping to prevent multiple clicks).
// The false parameter allows the cookie to be exposed to JavaScript.
$this->setCookieToken( $TOKEN, $_GET[ $TOKEN ], false );
$result = $this->sendFile();
Where:
public function setCookieToken(
$cookieName, $cookieValue, $httpOnly = true, $secure = false ) {
// See: http://stackoverflow.com/a/1459794/59087
// See: http://shiflett.org/blog/2006/mar/server-name-versus-http-host
// See: http://stackoverflow.com/a/3290474/59087
setcookie(
$cookieName,
$cookieValue,
2147483647, // expires January 1, 2038
"/", // your path
$_SERVER["HTTP_HOST"], // your domain
$secure, // Use true over HTTPS
$httpOnly // Set true for $AUTH_COOKIE_NAME
);
}
Best Solution
Here is how would I do it in case I cannot use jQuery
And here is a jQuery solution