Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Object detect once instead of every time 5

Status
Not open for further replies.

ESquared

Programmer
Dec 23, 2003
6,129
US
This is in a browser. I want to change the cursor while I do some processing. So I found the following code:

Code:
function cursor_wait() {
  document.body.style.cursor = 'wait';
}

function cursor_clear() {
  document.body.style.cursor = 'default';
}
The author then amended this saying to use the following for compatibility:

Code:
var cursor = 
     document.layers ? document.cursor :
     document.all ? document.all.cursor :
     document.getElementById ? document.getElementById('cursor') : null;
Now, I've been thinking about an idea for a while, but I don't see it used very often. I thought I'd take the chance to try to implement it. Instead of doing the object detect each and every time, why not do it once? Here's what I came up with:

Code:
var getCursor = function(){
   if(document.layers) {return function(){return document.cursor;};}
   if(document.all) {return function(){return document.all.cursor;};}
   if(document.getElementById) {return function(){return document.getElementById('cursor');};}
   return function(){return null;};
}();

function cursorWait() {
  var cursor = getCursor();
  cursor = 'wait';
}

function cursorClear() {
  var cursor = getCursor();
  cursor = 'default';
}
I wanted to do

[tt] getCursor() = 'wait';[/tt]

but that failed as did

[tt] (getCursor()) = 'wait';[/tt]

So anyway, does anyone have any ideas for me? I have studied up on javascript a bit but I am actually fairly inexperienced so I would love a critique or some ideas.
 
document.getElementById will always return true

so i would do something like
Code:
var getCursor = function(){
	if(document.layers) {
		getCursor = function(){	
			return document.cursor;
		};
	}
	if(document.all) {
		return function(){
			return document.all.cursor;
		};
	}
	return document.getElementById('cursor');}
}

thats the idea
 
I'm not sure why you're trying to assign a string to a function call. Most of what you have is either for obsolete browsers or doesn't make any sense.

Try this:
Code:
function cursor_wait()
{
document.getElementsByTagName('body')[0].style.cursor = 'wait';
}

function cursor_clear()
{
document.getElementsByTagName('body')[0].style.cursor = 'default';
}

Lee
 
erm sorry that was very bad example code
Code:
var getCursor = function(){
    if(document.layers) {
        getCursor = function(){
		alert(getCursor);    
            return document.cursor;
        };
    }
    if(document.all) {
       getCursor = function(){
            return document.all.cursor;
        };
    }
    getCursor = function(){
           return document.all.cursor;
     };
    return getCursor;
}
 
Code:
I'm not sure why you're trying to assign a string to a function call.  Most of what you have is either for obsolete browsers or doesn't make any sense.
I wasn't trying to assign a string to a function call. I was trying to assign a string to the object returned from a function call (thus why the try with parentheses around it). Only I see that cursor is in fact a property. Oops. So thanks for the updated function. What does the array element [0] dereference do?

And because of what you told me about the code I picked up being obsolete, half my question is dead. But if you DID have to do a 3-level object detect, would you think it reasonable to use the object detect only once in assigning the function, so that each time it is called it doesn't have to do it again?

P.S. You can do unusual things to functions when you put them in parentheses, so the next dot operates on the return value of the function instead of on the function itself:

[tt]alert( (new Date()).getYear() );[/tt]

I don't think what I was attempting was so strange.

 
[1] The problem seems to be stemmed from the confusion on the functional purpose and its underlying object structure of the lines said achieving "compatibility". That line seems to suggest oddly that "cursor" is actually some kind of div (layer in some legacy?)

In any case the getCursor so constructed is obviously not quite right. Here is a demo on how it would work with some re-purposing.
[tt]
<html>
<head>
<script language="javascript">
var getCursor = function(){
[green]if(document.layers) {return document.cursor;}[/green]
if(document.all) {return document.all.cursor;}
if(document.getElementById) {return document.getElementById('cursor');}
return null;
};
function cursorWait() {
var cursor = getCursor();
cursor[blue].style.cursor[/blue] = 'wait';
}

function cursorClear() {
var cursor = getCursor();
cursor[blue].style.cursor[/blue] = 'default';
}
</script>
</head>
<body>
<button onclick="cursorWait()">cursorWait</button><br />
<button onclick="cursorClear()">cursorClear</button><br />
<div id="cursor">div id cursor</div>
</body>
</html>
[/tt]
[2] The proliferation of the use of "cursor" is unfortunate. In any case, I intend to demonstrate the construction of getCursor() and its proper syntax on returning object and how it is called.
 
document.layers is for the old Netscape browsers before version 6. document.all is for the old Internet Explorer browsers, before version 5. All newer browsers have getElementByXXXX/getElementsByXXXX and I recommend using that unless you SPECIFICALLY have to support one of the old broswers.

Since getElementsByTagName returns an array of elements, even if there's only one, you have to access that as an array. There should only be ONE <body> tag on a page, so it's the zeroth element in the array (reminds me of Asimov's Robotic Laws).

ESquared, your code

Code:
getCursor() = 'wait';

or

Code:
(getCursor()) = 'wait';

attempted to assign a literal string to a function call, not pass a parameter or assign something to a return value from a function call. I'm not aware of any programming language that would use that particular concept, which is FAR different from

Code:
alert( (new Date()).getYear() );

that instantiates a new Date object for the immediate time and then gets the year from that object.

Lee
 
getElementsByTagName returns an array of elements
Duh. I know this! Silly me.

So you've all helped me out with the actual cursor code I needed. Thank you. I wasn't aware that it was a style property. Obviously I have to pay more attention when I'm looking for help on the web.

But so far no one has addressed the "object detect only once" side of the question. Any thoughts?

trollacious,

Applying the style "cursor:wait" to the body doesn't work for buttons and presumably other inputs in the page. I think I'm going to find the code I saw once to gray out the entire page with an alpha on a div which can be given a cursor style, and put a message window in front. Unless you have a better idea...
 
Let me show you what I am talking about with "object detect only once."

Taking tsuji's code above and adding only a few parts in bold below, getCursor is turned into a function that does NOT object detect each time it is used. It only object detects at the first invocation. I tested this and it works fine.

Code:
<html>
<head>
<script language="javascript">
var getCursor = function(){
    if(document.layers) [b]return function()[/b]{return document.cursor;}
    if(document.all) [b]return function()[/b]{return document.all.cursor;}
    if(document.getElementById) [b]return function()[/b]{return document.getElementById('cursor');}
    return null;
}[b]()[/b];
function cursorWait() {
    var cursor = getCursor();
    cursor.style.cursor = 'wait';
}

function cursorClear() {
    var cursor = getCursor();
    cursor.style.cursor = 'default';
}
</script>
</head>
<body>
<button onclick="cursorWait()">cursorWait</button><br />
<button onclick="cursorClear()">cursorClear</button><br />
<div id="cursor">div id cursor</div>
</body>
</html>
 
That's a VERY convoluted way of creating the function and functionality you want.

Lee

 
It only object detects at the first invocation.

If you're worried about it only doing the object detection once, why not store a reference to the object in a variable after the page has loaded? Then you never have to "find" it again. Any variable declared outside a function has global scope. Also, it's very poor programming practice to name a variable the same as property or method names.
Code:
<html>
<head>
<script language="javascript">

[!]var theCursor;
window.onload = function () {
   theCursor = document.getElementById("cursor");
};[/!]

function cursorWait() {
   [!]theCursor[/!].style.cursor = 'wait';
}

function cursorClear() {
   [!]theCursor[/!].style.cursor = 'default';
}
</script>
</head>
<body>
<button onclick="cursorWait()">cursorWait</button><br />
<button onclick="cursorClear()">cursorClear</button><br />
<div id="cursor">div id cursor</div>
</body>
</html>

-kaht

Lisa, if you don't like your job you don't strike. You just go in every day and do it really half-assed. That's the American way. - Homer Simpson
 
trollacious said:
That's a VERY convoluted way of creating the function and functionality you want.
What's so convoluted about it? If you're not familiar with it it can seem a little hard to understand at first. But in a language like javascript where functions are first-class objects it makes perfect sense.

It's even very easy to write. First write your function as normal. Then for each return statement, add one level of indirection by making it into a function which returns the value. Then execute the anonymous function with () at the end, and its return value (the function which returns a value) will be assigned to the variable. Elegant, easy, and very very cool. This kind of stuff is really fantastic and I love the power and flexibility of javascript's function orientation.

I may be "new" to javascript, but I have many years of programming experience. I know it can be hard to separate ignorance of a specific subject from stupidity in general so I can see how my idea seemed very weird to start with.

kaht,

You are missing the point. I picked a bad example. Forget the cursor.

Look through your own code until you find the funkiest and most annoying object detect you have that also runs many many times in the use of your page. With a tiny bit of easy to apply misdirection (which seems complicated and convoluted at first until you learn exactly what's going on) you can write your code so that you only object detect once when the page loads, and after that you are running exactly the right function for the browser that is loaded. Since the browser can't change during that instance of the program, you're good!

I didn't know getCursor was an existent object. Of course I would choose another name.

If you're worried about it only doing the object detection once, why not store a reference to the object in a variable after the page has loaded?
It's not always that simple. Try doing some event handling. It's not just a different object, but completely different functions, which accept different parameters. The technique I am trying to draw out can handle that too. Like I said, forget cursors.
 
I don't see we need to controvert as the point(s) have been illustrated, less frequented territory of a language (re-)visted and everybody has a chance to sharpen their know-how.
 
Yes, I truly appreciate the help everyone gave me in this thread. I gave stars to everyone.
 
Sorry, your question was very misleading. You posted a question pertaining to object detection in which you were wishing to detect the existence of document.layers, document.all, document.getElementById. However, in your example you were also detecting the existence of a <div> object in the code named cursor, which I thought was the main purpose of the discussion - hence my example that was completely missing your point.

Just out of curiosity, was this question a proof-of-concept? This seems like a very clunky solution if you have many objects on your page that you wish to reference - as a different function is required for each HTML object you'll be referencing (getCursor, getBlah, getFoo, getBar, etc). You could make use of eval to make it more dynamic - but that's just another can of worms.

-kaht

Lisa, if you don't like your job you don't strike. You just go in every day and do it really half-assed. That's the American way. - Homer Simpson
 
kaht,

Yes, I picked a bad example! Thank you for your time and effort to try to help me.

I don't think it's clunky at all. (I do think it could be adapted to special circumstances without having to have a global-level function for each thing you plan to use.)

This has little to do with simply referencing HTML objects.

If you are doing object detects in your code, you are already doing something "clunky." This does add some complexity and is unusual, but if you write these once and put them in your object library, then you can start using standardized names, trusting that your once-written object-detect code is working. I think it's a worthy goal to only run the object-detect code ONCE. If you wanted, you could even make it so it doesn't run at page load but only the first time the end function is actually used, and each time after that only the optimized code is run.

Look at the addEvent() recoding contest and the winner of that contest, code here:

Code:
function addEvent( obj, type, fn ) { 
  if ( obj.attachEvent ) { 
    obj['e'+type+fn] = fn; 
    obj[type+fn] = function(){obj['e'+type+fn]( window.event );} 
    obj.attachEvent( 'on'+type, obj[type+fn] ); 
  } else 
    obj.addEventListener( type, fn, false ); 
} 
function removeEvent( obj, type, fn ) { 
  if ( obj.detachEvent ) { 
    obj.detachEvent( 'on'+type, obj[type+fn] ); 
    obj[type+fn] = null; 
  } else 
    obj.removeEventListener( type, fn, false ); 
}
Dean Edwards offered a probably superior non-object-detecting version of this, but let's forget about that for a moment.

So here you are doing object attaching and such. What if you have some process that runs in your page frequently, attaching and detaching events? (I have cases where I need to do this such as making the close button of an in-page popup form work as if it was a close button on a regular windows dialog.) Then you're detecting objects each time.

The addEvent function above uses two object detects. Why not fix it so on the first run, it morphs into just the version necessary for the current environment and stops object detecting?
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top