The Cache: Technology Expert's Forum
 
*
Welcome, Guest. Please login or register. September 19, 2019, 02:23:04 PM

Login with username, password and session length


Pages: [1]
  Print  
Author Topic: Disabling Web Page Controls with CSS & Javascript  (Read 5019 times)
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« on: November 30, 2008, 06:00:45 PM »

Here's a little nugget from Perk's bag of tricks.

Personally, I like to see my web pages mimic normal applications as much as possible. I think that Windows, Apple, Gnome, KDE etc etc have done a fine job of training people, so why reinvent the wheel? To this end, it's always bugged me that you can't myObj.disable() or disable(anObj) from HTML. Here is a way to emulate that behavior.

The trick relies on a couple important features of Javascript and CSS:
  • The ability to create a new DIV on the fly
  • The ability to find a target object's top/left/height/width coordinates
  • The ability to use z-index to put a new div "in front" of an existing div
  • When one div is on top of another, you can't click anything that's behind it
  • The ability for a PNG(24) to do alpha blending as a background image.

Here is an example, from one of my retail sites, before the "Confirm and Purchase" button is pressed and after. Note the buttons (munged to protect the innocent):





As mentioned above, I have a simple little function that you pass an existing element on a webpage, and a mask graphic. (there's actually 2 mask graphics, but I'll cover that in a bit).

Here is the actual function (and two other little functions it requires):
Code:
function disable(targetID, maskURLNew, maskURLOld)
{
// If a string was passed as targetID, then find the node.
// If it's not a string, assume it is a passed node.
if (typeof(targetID) == 'string') var target = document.getElementById(targetID);
else var target = targetID;

// Get a handle to the main document body
var bodies = document.getElementsByTagName('BODY');
var base = bodies[0];

// Get the position and dimensions of the target element
var top = getElementTop(target);
var left = getElementLeft(target);
var height = target.offsetHeight;
var width = target.offsetWidth;

// Use maskURLOld if the browser is IE6 or less
var bImage = maskURLNew;
var bVer = navigator.appVersion;
ver = bVer.match(/MSIE ([0-9])/);
if (ver != null)
{
if (ver[1] != undefined)
{
vNum = (ver[1] - 0);
if (vNum <= 6) bImage = maskURLOld;
}
}

// Create the new div and attribute it accordingly
var newDiv = document.createElement('DIV');
newDiv.style.position = 'absolute';
newDiv.style.zIndex = '1000000';
newDiv.style.top = top + 'px';
newDiv.style.left = left + 'px';
newDiv.style.height = height + 'px';
newDiv.style.width = width + 'px';
newDiv.style.backgroundImage = 'url("' + bImage + '")';
newDiv.style.backgroundRepeat = 'repeat';
newDiv.innerHTML = '&nbsp;';

// Add the div to the main body and we're done
base.appendChild(newDiv);
}
function getElementLeft(obj)
{
    var curleft = 0;
    if(obj.offsetParent)
    {
        while(true)
        {
                curleft += obj.offsetLeft;
                if(!obj.offsetParent) { break; }
                obj = obj.offsetParent;
        }
    } else if(obj.x) { curleft += obj.x; }
    return curleft;
}
function getElementTop(obj)
{
    var curtop = 0;
    if(obj.offsetParent)
    {
        while(true)
        {
                curtop += obj.offsetTop;
                if(!obj.offsetParent) { break; }
                obj = obj.offsetParent;
        }
    } else if(obj.y) { curtop += obj.y; }
    return curtop;
}

Here is the actual code that makes the above two graphics happen (lightly munged, but not functionally)
Code:
function executeTransaction()
{
disable('buttonChangeBilling', '/graphics/whiteMask.png', '/graphics/whiteMask.gif');
disable('buttonChangeDelivery', '/graphics/whiteMask.png', '/graphics/whiteMask.gif');
disable('buttonChangeFOP', '/graphics/whiteMask.png', '/graphics/whiteMask.gif');
disable('cpirReceiptButtons', '/graphics/whiteMask.png', '/graphics/whiteMask.gif');
disable('cpirButtonLogout', '/graphics/whiteMask.png', '/graphics/whiteMask.gif');
disable('cartUpdateButton', '/graphics/blackMask.png', '/graphics/blackMask.gif');
...
}

Here are the links to each of the 4 graphics in this example:

whiteMask.png


whiteMask.gif
  <-- it's really right there

blackMask.png


blackMask.gif



Reading the code should be relatively self explanatory. The trick does not work as nicely on IE6 or less, because it won't do an alpha blend. So the second graphic passed is a 2x2 GIF with 1 white dot and 3 transparent dots. So in IE6 it looks mottled, but is still clearly no longer available. Note also how I've supplied different masks for the cart portion - a black one - because the trick only works correctly if you mask with the same color as the background you're on top of.

The PNG graphics are simply a Photoshop graphic, all white/black/whatever with the opacity set to about 50% (to taste, of course). Then saved as a PNG(24) not a PNG(8 ). There is a *tiny* amount of overhead repeating the graphic all over your new DIV, so the bigger the background image the better. Since the GIF is barely used and I'm lazy, I just made it tiny. It people are still using IE6 then they can deal with a slightly slower effect LOL.

Here is an example of it in IE6 with a GIF style transparency:



Note also that in most cases, I selected the button to disable. But I am also able to disable divs the same way, like the div that contains my radio button divs, or the div at the top that has the caption and button to log out.

I am certain that this has problems somewhere as it has only been ground out with Safari, FF/Mac, IE7, IE6 and FF3 for Windows, but that's a reasonable enough starting place.

Enjoy!

/p
« Last Edit: November 30, 2008, 06:11:16 PM by perkiset » Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
vsloathe
vim ftw!
Global Moderator
Lifer
*****
Offline Offline

Posts: 1669



View Profile
« Reply #1 on: December 02, 2008, 06:55:51 AM »

Pretty sweet meat Perks.

I am going to have to give this method a whirl on a couple apps I have in mind.
Logged

hai
jairez
Expert
****
Offline Offline

Posts: 164


JTFC


View Profile
« Reply #2 on: December 02, 2008, 08:10:57 AM »

Nice, Perk!  I too have a place I believe this will come in handy.  Typically I'll adjust the "visibility" of a div to either visible or hidden (I know ... old school), or with text I'll modify the font-weight to give the impression of "enabled or disabled," but to do this as an object is MUCH better.

Much grass!
Logged

Spontaneity has it's time and place.  [Sluggo, 1990-ish]
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #3 on: December 02, 2008, 08:39:46 AM »

Thanks, both!

...I'll adjust the "visibility" of a div to either visible or hidden (I know ... old school)

...not old school at all. My problem with all of it is that there really isn't a nice, standard way to do it, therefore we all confuse surfers by offering different, non-standard "disabled" indicators in all of our apps. Hope it works nicely for you!
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
nutballs
Administrator
Lifer
*****
Offline Offline

Posts: 5627


Back in my day we had 9 planets


View Profile
« Reply #4 on: December 02, 2008, 09:23:25 AM »

i have used the png overlay method as well. but positioning has always been an issue. i will try out this dealio next time I actually do any frontend work... which might be never. lol
Logged

I could eat a bowl of Alphabet Soup and shit a better argument than that.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #5 on: December 02, 2008, 11:00:08 AM »

Positioning is always the issue.

The getElementTop and getElementLeft do a damn fine job of getting the absolute position on an element, the offsetHeight and Width are reliable for sizing. The issue most of the time (IMO) is that people put a div like this that they want absolutely positioned inside/below other divs that have messed with the positioning ie., there are some absolutes ore relatives "above" <the new to-be-positioned-node> and as such, applying a top and left is no longer reliable.

So the hot tip: use these getElementLeft and Top functions, then put divs you want to position right off the BODY tag so that they adhere to the true absolute position of the browser window, not the interpreted position sub-CSS.

The PNG overlay method is hot. I use it for creating a modal appearance for popups - essentially create a div that covers the entire webpage and viewportal (whichever is larger) then background-imaging it with a tiled, transparent png ... then z-index my popup on top of that. Works like a charm. The only thing that pisses me off is IE-6's lack of alpha blending, so I always have to supply the old transparent GIF method as well.
« Last Edit: December 02, 2008, 11:02:08 AM by perkiset » Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
Pages: [1]
  Print  
 
Jump to:  

Perkiset's Place Home   Best of The Cache   phpMyIDE: MySQL Stored Procedures, Functions & Triggers
Politics @ Perkiset's   Pinkhat's Perspective   
cache
mart
coder
programmers
ajax
php
javascript
Powered by MySQL Powered by PHP Powered by SMF 1.1.2 | SMF © 2006-2007, Simple Machines LLC
Seo4Smf v0.2 © Webmaster's Talks


Valid XHTML 1.0! Valid CSS!