You are delving into the depths of how Class works, so this is going to get
a little complicated.
All methods of classes are wrapped in a function that then calls the
function in question. So if you pass an object to Class that has a
*foo* method,
Class returns a constructor that when invoked returns an object that has a *
foo* method that calls the original one.
var fooBase = {
foo: function(){ alert('foo'); }
};
var Foo = new Class(fooBase);
var myFoo = new Foo();
myFoo.foo(); //alerts "foo"
When we call the *foo* method on our instance, we're really calling the
wrapper that the Class constructor put around the *foo* method on our
fooBase object. This wrapper therefore knows when *foo* is being called, and
before it calls the original *foo* it defines *this.parent*. It doesn't look
like this, but here's a very simple illustration:
instanceOfFoo.foo = function(){
this.someVar = 'blah';
this.originalFooMethod();
delete this.someVar;
};
So only while our original method is being run is *this.parent* defined (and
only if there is a parent method on the prototype).
If you think about it, that's the only way this could work, because *
this.parent *has to point at different things depending on which method is
calling it. *this* is our instance, and the *parent* property of our
instance changes depending on the method. Removing it after a method is
called is the only way to allow the next method to call it.
So, let's look at your code:
showMask: function() {
var fn = function() {
this.parent();
}.bind(this);
this.element.tween('opacity', this.options.opacity).get('tween').chain(
fn);
},
Your method calls *element.tween*, which starts an effect. After the effect
it calls your function, which references *this.parent*. But this
asynchronous method call is going to occur *after* the *showMask* method
exits, which means that *this.parent *has been deleted, right?
So, how do you extend a class and add this kind of effect? The only
mechanism to do this is to rename the original methods:
var Foo.Extended = new Class({
Extends: Foo,
initialize: function(){
this._foo = this.foo;
this.foo = this._newFoo;
},
_newFoo: function(){
(function(){
this.parent();
}).delay(1000, this);
}
});
var myFoo = new Foo.Extended();
myFoo.foo(); //waits 1 second, alert's "foo"
This is hacky and in general a bad practice.
If you look at the showMask method in Spinner, which completely overwrites
the method from Mask (it does not call this.parent), you can see how it does
this fading in. Note that I *could* have done this method renaming from the
example above, but that method renaming is more brittle than I prefer. I've
only used the technique on a very few occasions.
On Tue, Jan 5, 2010 at 11:55 AM, Rolf -nl <[email protected]> wrote:
> I've extended more's Mask so I can apply an opacity tween effect to
> the mask... (and still have all the benefits of Mask, else I could use
> DWalsh's Overlay...)
>
> Earlier I tried a simple way to extend Mask, just changing the
> showMask and hideMask methods:
> http://mootools.net/shell/A65x7/
>
> But then I get the error: The method "parent" cannot be called.
> Q1. Why can't I call the this.parent() methods showMask and hideMask?
>
>
> Then I extended it in another way (needed to use it, so, went for the
> easy way out):
> http://mootools.net/shell/PMpZM/
>
> In the original Mask show (and hide) methods it says:
> this.showMask.apply(this, arguments);
>
> Q2: When are these methods (show/hide) getting any arguments?
>
>
>