IE and the Opacity

D

Defacta

Hi!

This works fine with Firefox and Safari but with IE, IE tells me
Object required, here is the code:

var max = 100;
var min = 0;
var opacite=min;
up=true;
var IsIE=!!document.all;
var ThePic=document.getElementById("fact-content");

function fadePic(){
if (opacite<max && up){opacite+=3;}
if (opacite>min && !up){opacite-=3;}
if (opacite>=max){up=false;}
if (opacite<=min){up=true;}

IsIE?ThePic.filters[0].opacity=opacite:document.getElementById("fact-
content").style.opacity=opacite/100;
document.getElementById('fact-content').value=opacite+"%"
}
setInterval(function(){fadePic();},50)


function Opacificateur(Obj,quantite) {
Obj.style.opacity = quantite/10;
Obj.style.filter = 'alpha(opacity=' + quantite*10 + ')';
}

The IE error is for that line:
IsIE?ThePic.filters[0].opacity=opacite:document.getElementById("fact-
content").style.opacity=opacite/100;

What can I do ?

Thanks,
Vincent.

PS: fact-content is not image but a div like this:

<div id="fact-content" style="filter:alpha(opacity=100);-moz-opacity:
1; ">
Hello world !
</div>
 
D

David Golightly

This works fine with Firefox and Safari but with IE, IE tells me
Object required, here is the code:

var max = 100;
var min = 0;
var opacite=min;

Try to rework this using no global variables, instead attaching all
variables as properties of a single global object (in JavaScript
parlance, a "namespace". A misnomer, but still useful). You'll thank
yourself if, next year, you're re-writing or extending this code and
need to know where everything comes from.


Use "var" to declare all variables.
var IsIE=!!document.all;

You don't want to do this browser sniffing. It's highly error-prone.
There are better ways. See below.
var ThePic=document.getElementById("fact-content");

You also don't want DOM element references lurking around in global
variables. See: http://www.jibbering.com/faq/faq_notes/closures.html
function fadePic(){
if (opacite<max && up){opacite+=3;}
if (opacite>min && !up){opacite-=3;}
if (opacite>=max){up=false;}
if (opacite<=min){up=true;}

IsIE?ThePic.filters[0].opacity=opacite:document.getElementById("fact-
content").style.opacity=opacite/100;
document.getElementById('fact-content').value=opacite+"%"}

Try:

if (ThePic.filters) {
ThePic.style.filter = 'alpha(opacity='+opacite+')';
} else {
ThePic.style.opacity = opacite/100;
}

The "filters" collection is a nonstandard HTMLElement attribute, so it
will tell you if the element in question supports filtering.
Otherwise, you shouldn't need to bother with setting the value through
the "filters" collection. Google "Peter Michaux Lazy Function
Definition" to figure out how to run this test only once (so it
doesn't slow down an animation, for example).
setInterval(function(){fadePic();},50)

More concisely, without the closure:

window.setInterval(fadePic, 50);
function Opacificateur(Obj,quantite) {
Obj.style.opacity = quantite/10;
Obj.style.filter = 'alpha(opacity=' + quantite*10 + ')';

}

Did you try this by itself? Why the duplicate code?
The IE error is for that line:
IsIE?ThePic.filters[0].opacity=opacite:document.getElementById("fact-
content").style.opacity=opacite/100;
PS: fact-content is not image but a div like this:

<div id="fact-content" style="filter:alpha(opacity=100);-moz-opacity:
1; ">

You shouldn't ever need to use the proprietary style "-moz-opacity";
Mozilla automatically translates "opacity" into that for you.

-David
 
D

David Mark

Hi!

This works fine with Firefox and Safari but with IE, IE tells me
Object required, here is the code:
[snip]

Search this group for a recent post about feature testing opacity
support.
 
T

Thomas 'PointedEars' Lahn

David said:
Try to rework this using no global variables, instead attaching all
variables as properties of a single global object

The term "global object" here is misleading, as there is already a built-in
Global Object. "Globally available object" is more feasible, which
describes what you apparently meant: a globally available identifier that
serves as a reference to an object.
(in JavaScript parlance, a "namespace".

Maybe in *your* parlance, and other clueless library lemmings out there.
A misnomer,

Indeed it is.
but still useful).

It isn't. The concept of namespaces was introduced into the language not
before ECMAScript Edition 4, which is currently only a working draft, and
has only one implementation ready for production use (for fitting values
of "ready"): JScript .NET, (AFAIK) server-side (IIS-)only.
You also don't want DOM element references lurking around in global
variables.

Why not? Sometimes there is no better way to avoid looking up a DOM object
reference repeatedly.

Non sequitur. Closures are created by *local* execution contexts.
function fadePic(){
if (opacite<max && up){opacite+=3;}
if (opacite>min && !up){opacite-=3;}
if (opacite>=max){up=false;}
if (opacite<=min){up=true;}

IsIE?ThePic.filters[0].opacity=opacite:document.getElementById("fact-
content").style.opacity=opacite/100;
document.getElementById('fact-content').value=opacite+"%"}

Try:

if (ThePic.filters) {
ThePic.style.filter = 'alpha(opacity='+opacite+')';

Wrong. The MSDN Library explains how to do it properly:

http://msdn2.microsoft.com/en-us/library/ms532847.aspx
} else {
ThePic.style.opacity = opacite/100;
}

The "filters" collection is a nonstandard HTMLElement attribute,

Utter nonsense. The HTMLElement interface is part of the W3C DOM Level 2
HTML *Web standard*.

`filters' is a proprietary *property* of HTML element objects in the MSHTML
DOM. It *is* a reference to a collection, though.
More concisely, without the closure:

window.setInterval(fadePic, 50);

Which can change the meaning of `this' within `fadePic' significantly.

Obviously you have little to no clue what you are talking about.
Did you try this by itself? Why the duplicate code?

It is a simple, yet error-prone way to satisfy at least two DOMs (all DOMs
that implement the CSSStyleDeclaration interface for the `style' property,
and the MSHTML DOM). It is error-prone because `Obj.style' refers to an
host object that does not need to support the addition of properties.
You shouldn't ever need to use the proprietary style "-moz-opacity";
Mozilla automatically translates "opacity" into that for you.

It only does so since about 2005-02-20 12:55:08 PDT.

https://bugzilla.mozilla.org/show_bug.cgi?id=281907


PointedEers
 
T

Thomas 'PointedEars' Lahn

Thomas said:
David said:
IsIE?ThePic.filters[0].opacity=opacite:document.getElementById("fact-
content").style.opacity=opacite/100;
document.getElementById('fact-content').value=opacite+"%"}
Try:

if (ThePic.filters) {
ThePic.style.filter = 'alpha(opacity='+opacite+')';

Wrong. The MSDN Library explains how to do it properly:

http://msdn2.microsoft.com/en-us/library/ms532847.aspx

Ignore that, my bad. As also described in the MSDN Library, it is indeed
"correct" if the `style' attribute of the corresponding element does not
include a `filter' declaration yet (which would be good because that style
property is proprietary and including it in the first place would make the
CSS not Valid). Sorry, I confused that with scripting already declared filters.


PointedEars
 
D

David Golightly

Which can change the meaning of `this' within `fadePic' significantly.

Obviously you have little to no clue what you are talking about.

How does that work, exactly? In what way is the value of "this"
changed within "fadePic", and to what does it now refer (in each
case)? Could you please explain this mechanism to me? I would very
much like to get it right.

-David
 
T

Thomas 'PointedEars' Lahn


I don't think there is a closure here: `fadePic' is not resolved before
the function argument is called. Not every function expression creates
a closure.

http://en.wikipedia.org/wiki/Closure_(computer_science)
How does that work, exactly? In what way is the value of "this"
changed within "fadePic", and to what does it now refer (in each
case)? Could you please explain this mechanism to me? I would very
much like to get it right.

Why, you could simply test it.

`this' in a method refers to the calling object.

I was referring to `fadePic' as an example, hence the "can". It will
probably not change anything here because `fadePic' is probably called
as a method of the same object in the scope chain.

But if you use for example

var o = {
fadePic: function()
{
window.alert(this);
}
};

// and then

window.setTimeout(o.fadePic, 50) // [1]

// instead of

window.setTimeout(function() { o.fadePic(); }, 50)

that changes the meaning of `this' in the method o.fadePic is a reference
to. In the former case it would probably refer to the object setTimeout()
is called as a method of; in the latter case it would refer to the same
object as `o'.

My point being was/is that these two approaches are not generally
equivalent, and that avoiding (supposed) closures is not always the best
approach.


PointedEars
___________
[1] It is the same with setInterval() or any other call, but setTimeout()
serves better as a similar example to the OP's code.
 
D

David Golightly

I don't think there is a closure here: `fadePic' is not resolved before
the function argument is called. Not every function expression creates
a closure.

http://en.wikipedia.org/wiki/Closure_(computer_science)

According to the Wikipedia article, "a closure is a function that is
evaluated in an environment containing one or more bound variables.
When called, the function can access these variables." In this
instance, the anonymous function being passed to window.setTimeout as:

function doStuff() {
var o = {};
window.setTimeout(function () { fadePic(); }, 50);
}

has access to the variable "o" which is local to the containing
function "doStuff", hence, a closure. However, in the OP's example
(which is itself presumably wrapped in a function he neglected to
copy, or should be), none of those variables are used, except
"fadePic" itself. Since a closure is not needed here, I recommend not
using it; fadePic is itself a function that is not a property of any
object but the Global object, so the value of "this" is unchanged,
regardless of whether it is called within an anonymous function or
called directly.
Why, you could simply test it.

`this' in a method refers to the calling object.

I was referring to `fadePic' as an example, hence the "can". It will
probably not change anything here because `fadePic' is probably called
as a method of the same object in the scope chain.

In this example, we can drop the word "probably". Since "fadePic" is
not being called as a property of a local object, its "this" value
points to the Global object anyway.
But if you use for example

var o = {
fadePic: function()
{
window.alert(this);
}
};

// and then

window.setTimeout(o.fadePic, 50) // [1]

// instead of

window.setTimeout(function() { o.fadePic(); }, 50)

that changes the meaning of `this' in the method o.fadePic is a reference
to. In the former case it would probably refer to the object setTimeout()
is called as a method of; in the latter case it would refer to the same
object as `o'.

My point being was/is that these two approaches are not generally
equivalent, and that avoiding (supposed) closures is not always the best
approach.

That's a valid distinction, but understanding it is central to
effective JavaScript. What's necessary in the latter case -
preserving the object "o" within the scope chain, so that its property
"fadePic" may be called at a later time - is not necessary in the
former case. However, the latter example brings problems of its own,
as I've seen lots of beginners try:

function Foo() {}

Foo.prototype.doBar = function () { /* stuff here */ };
Foo.prototype.delayedBar = function () { window.setTimeout(function ()
{ this.doBar() }, 50); };

var foo = new Foo();
foo.delayedBar();

which gives a syntax error, since the Global object has no method
"doBar". Likewise,

Foo.prototype.delayedBar = function () { window.setTimeout(this.doBar,
50); };

will pass in a function, but as you say, its "this" will refer to the
Global object, not the object that inherits from Foo.prototype. The
(most likely) intended behavior, not immediately obvious to beginners,
is:

Foo.prototype.delayedBar = function () { var foo = this;
window.setTimeout(function () { foo.doBar() }, 50); };

I would, in general, discourage use of closures unless they're needed
for a specific, premeditated purpose; a recurring setInterval call
will preserve the scoped local variables in memory long after the
original function has returned and there is no longer a need for
them. When they are needed, it's a good idea to attempt to limit the
scope to prevent or at least minimize unintended memory leaks.

To sum up, it seems the best rule of thumb is to simply learn the
rules, and decide which technique to use based on what's needed in a
particular context.

-David
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,999
Messages
2,570,246
Members
46,840
Latest member
BrendanG78

Latest Threads

Top