In a case where WebKit (Safari 3) works perfectly, I get either a
silent failure (property extensions of 'Element.prototype' are
successfully made, but 'addEventListener' is still the native one and
not the extended one intended by the code) or (for example when trying
to extend 'HTMLDivElement.prototype) an explicit exception ("Illegal
operation on WrappedNative prototype object").
Given this code at line 469 of https://us.etrade.com/javascript/et1/src/core/dom/Element.js
if( defined( self.HTMLElement )
&&
( !
HTMLElement.prototype.hasOwnProperty( "addEventListener" ) &&
!
HTMLDivElement.prototype.hasOwnProperty( "addEventListener" ) ) ) {
Element.prep( Element.prototype );
}
If I add a blanket pass to the conditional above like so:
if( true || defined . . .
Then what happens is that the 'addEventListener' method acts like (and
possibly is) the original one, resulting in a loss of the intended
object context. The JavaScript framework intends that the new
'addEventListener' method (wrapped in 'Element.js'; url above) take
an object-context argument, but that is lost, resulting in the object
context being the dom element.
That causes an error since the expected methods are not on that
object:
FF 3 (but same on FF 2):
Welcome to “Venkman”, the JavaScript debugger. Please read the FAQ
at <http://www.hacksrus.com/~ginda/venkman/faq/venkman-faq.html>.
Visit the Venkman homepage <http://www.mozilla.org/projects/venkman/>
for more information.
You are running Venkman version 0.9.87.4.
Use “/help <command-name>” for help on specific commands.
Visit <x-jsd:help> for a searchable command reference.
Commands start with a forward-slash ('/') character. Any text that
DOES NOT start with a forward-slash will be evaluated as JavaScript.
For example, to execute the“step” command, type “/step”. To evaluate
“1 + 1”, just type “1 + 1”.
Recorded local startup 119, global 5805809.
Error ``this.emitEvent is not a function'' [x-] in file ``https://
lxdev6m0.etrade.com:14755/javascript/et1/src/lib/model/messenger/
request/mechanism/ScriptInclude.js'', line 135, character 0.
Stopped for error handler.
#0: function anonymous(p_eEvent=Event:{0}) in <https://
lxdev6m0.etrade.com:14755/javascript/et1/src/lib/model/messenger/
request/mechanism/ScriptInclude.js> line 135
133: eventLoad : function( p_eEvent ) {
134: // Let the application know that a response has been received
from the server:
135: this.emitEvent( p_eEvent );
136: },
137:
Continuing from error handler.
Unfortunately, allowing custom js objects to listen to dom events with
methods (not plain functions) is very critical. The only way
currently to get this on FF (and on IE) is to wrap the dom objects on
an individual basis. Apparently, using the prototype property here is
not possible. But as mentioned above, it works fine on WebKit (Safari
3).
When I try an alternative approach, by moving down the prototype chain
to 'HTMLDivElement' (which is a much less preferable alternative than
just extending 'Element'), doing this:
Element.prep( HTMLDivElement.prototype );
I get this error (same on FF 3 and 2):
Exception ``[Exception... "Illegal operation on WrappedNative
prototype object" nsresult: "0x8057000c
(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)" location: "JS frame ::
https://lxdev6m0.etrade.com:14755/javascript/et1/src/core/dom/Element.js
:: anonymous :: line 430" data: no]'' thrown from function
anonymous(p_oElement=XPC_WN_ModsAllowed_NoCall_Proto_JSClass:{69}) in
<https://lxdev6m0.etrade.com:14755/javascript/et1/src/core/dom/
Element.js> line 430.
Stopped for thrown exception.
#0: function
anonymous(p_oElement=XPC_WN_ModsAllowed_NoCall_Proto_JSClass:{69}) in
<https://lxdev6m0.etrade.com:14755/javascript/et1/src/core/dom/
Element.js> line 430
428: // If not an Element/HTMLElement prototype, and 'nodeType' !
= 1, return here:
429: if( !( oE === self.Element.prototype ) &&
430: ( oE.nodeType != 1 ) ) { // 'self' is used as an
optimization.
431: oE.bPreppedByEt1 = true;
A complete example of this code in context may be found at:
https://us.etrade.com/javascript/et1/dev_tools/test/harness/lazy_loader_inline_script/index-src.html
In sum: Is this a bug in Firefox? It seems so. Requesting feedback
on that point: If this is a bug, I'll report it.
Last but not least: Does anyone know of any workarounds?
Thank you in advance,
- cb
a) "extend the 'addEventListener' prototype of the 'Element' object "
in the first paragraph above should read instead, "extend the
'addEventListener' method of 'Element' object's prototype"
= Clarification =
The framework operation performed on 'addEventListener' is technically
a wrap, but has the effect of extending its functionality:
oE.addEventListener = function( p_sEventName,
p_fnHandler, p_oContext, p_bCapture ) {
var fnHandler = Et1.getHandler( p_fnHandler,
p_oContext );
this.plainAddEventListener( p_sEventName,
fnHandler, p_bCapture );
return fnHandler;
};
In the code snippet above (from https://us.etrade.com/javascript/et1/src/core/dom/Element.js
), 'this.plainAddEventListener' is a cached version of the original,
native event listener.
Node.prototype.aaaa=1;
document.body.aaaa; //gives 1
BTW, I think this is off-topic to this group "js-engine",
you may want to try on Web-Dev group or a DOM group
Thanks for the message. I get properties added to 'Element.prototype'
fine -- except for 'addEventListener'.
The problem is that asymmetry. Since 'Element.prototype' is exposed
in the js-engine, it should work like any other object.
That's why I posted here in js-engine. However, possibly there is a
bug in the exposure of 'Element.prototype' in the DOM implementation.
Then it would be best to post in the DOM group.
If this is actually a browser bug, it would not be a WebDev issue.
Well, let's see what we can figure out by playing with JavaScript a
little. I'm using FF3. Answers may vary.
document.body.__proto__ === HTMLBodyElement.prototype
===> true
document.body.__proto__.__proto__ === HTMLElement.prototype
===> true
document.body.__proto__.__proto__.__proto__ === Element.prototype
===> true
document.body.__proto__.__proto__.__proto__.__proto__ ===
Node.prototype
===> true
So far so good. Now, where does an element inherit the
addEventListener method from?
document.body.hasOwnProperty("addEventListener")
===> false
HTMLBodyElement.prototype.hasOwnProperty("addEventListener")
===> true
Hmm. It looks like Gecko reflects interface methods on *every*
prototype that implements them. This is bad news for anyone who wants
to hook this method. Not all addEventListener methods are inherited
from one central place. Instead, there is one per DOM element class.
> The problem is that asymmetry. Since 'Element.prototype' is exposed
> in the js-engine, it should work like any other object.
Maybe you're right; the currently existing standards don't specify
this.
-j