Still working on a huge ScriptUI project, I discovered a weird issue which appears to *only* affect 'binary compiled' scripts (JSXBIN export), not the original script!

When you repeatedly use addEventListener() with the same event type, you theorically have the possibility to attach several handlers to the same component and event, which can be really useful in a complex framework:

The result is that when you click on the group box, e1.text AND e2.text are updated.

But now, if I export the above code as a JSXBIN from the ESTK, the 2nd event handler sounds to be ignored! When I test the 'compiled' script and click on the group box, only e1.text is updated. (Tested in ID CS4 and CS5, Win32.)

By studying the JSXBIN code as precisely as possible, I didn't find anything wrong in the encryption. Each addEventListener() statement is properly encoded, with its own function handler, nothing is ignored. Hence I don't believe that the JSXBIN code is defective by itself, so I suppose that the ExtendScript/ScriptUI engine behaves differently when interpreting a JSXBIN... Does anyone have an explanation?

Not an explanation, but of course we know that in JSXBIN you can't use the .toSource() method on functions.

So the implication here is that perhaps the .toSource() is somehow implicated in event handlers and there's some kind of static workaround for it?

Perhaps you can get around this by eval() or doScript()-ing strings?

Thanks a lot, John, I'm convinced you're on the good track. Dirk Becker suggested me that this is an "engine scope" issue and Martinho da Gloria emailed me another solution —which also works— and joins Dirk's assumption.

Following is the result of the various tests I did from your various suggestions:

This test shows that if handler1 and handler2's bodies are removed from the binary, the script works. Note that the handlers are declared vars that refer to (anonymous) function expressions. (BTW, no need to use a non-main #targetengine.) This is not a definitive workaround, of course, because I also want to hide handlers code...

In the above test the entire code is binary-encoded, and the script works. What's the difference? It relies on function declarations rather than function expressions. As we know, function declarations and function expressions are not treated the same way by the interpreter. I suppose that function declarations are stored at a very persistent level... But I don't really understand what happens under the hood.

(Note that I also tried to use function expressions in global variables, but this gave the original result...)

Thanks to John, Dirk, and Martinho for the tracks you've cleared. As my library components cannot use neither the global scope nor direct function declarations my problem is not solved, but you have revealed the root of my troubles.

Thanks to you all guys, I finally found a simple and generic workaround that preserves the whole structure of my project.

Instead of:

var myHandler = function() { /* . . . */};

just append a redundant function name to the declaration:

var myHandler = function anyHandlerFuncName() { /* . . . */};

Then, other parts of the code don't need to be changed:

myWidget.addEventListener('click', myHandler);

// etc.

I just tested this in a complex 'module pattern' which has a deep object/function hierarchy —including some closures— and the JSXBIN now works like a charm:-)

The redundant name is arbitrary and, in fact, it is never used in the code. For whatever reason, this simple addition makes multiple event handlers more 'persistent'... Does it cause performance costs or memory leaks? I don't know. But since this fix specifically regards event listeners, I don't fear it's too harmful (?)

A possible conclusion for this topic is that we always should use named functions as ScriptUI event listeners.

Yeah, it's definitely a function expression -- apparently they have optional identifiers that can be used to recursively call the function. See chapter 13 of the spec on p. 71, quoted with some elision::

The production FunctionExpression : function ( FormalParameterList_opt ) { FunctionBody } is evaluated as follows:1. Create a new Function object as specified in 13.2 with parameters specified by FormalParameterList_opt and body specified by FunctionBody. Pass in the scope chain of the running execution context as the Scope.2. Return Result(2).

1. Create a new object as if by the expression new Object().2. Add Result(1) to the front of the scope chain.3. Create a new Function object as specified in 13.2 with parameters specified by FormalParameterList_opt and body specified by FunctionBody. Pass in the scope chain of the running execution context as the Scope.4. Create a property in the object Result(1). The property's name is Identifier, value is Result(3), and attributes are { DontDelete, ReadOnly }.5. Remove Result(1) from the front of the scope chain.6. Return Result(3).

NOTEThe Identifier in a FunctionExpression can be referenced from inside the FunctionExpression's FunctionBody to allow the function to call itself recursively. However, unlike in a FunctionDeclaration, the Identifier in aFunctionExpression cannot be referenced from and does not affect the scope enclosing the FunctionExpression.

Yeah, that's our perennial problem in Adobe scripting! How is ECMA-262+ECMA-357 implemented in ExtendScript? How does ScriptUI interact with ES and the DOM? How is the W3C Event model implemented in ScriptUI? How does the ES 'engine' system interact with JS scope? How does JSXBIN interact with all that stuff? Etc. Too many recurring questions...

Let me explain why I initially thought it was an engine issue: when the "main" engine quits everything inside including functions is purged, so I made it a habit to always use a more permanent, dedicated session for InDesign event handlers where the objects have a chance to survive. I'm not doing so much with UI therefor I missed on the "modal" nature of the dialog that also *should* keep its session alive while the window is open. I would anyway not invoke such a dialog straight out of a top level script but provide a menu instead, and then you again have the need for a permanent session.

I would not read so much into the difference between function declaration and function expression as the results are so interchangeable most of the time, instead for myself I will consider it just a little bug in garbage collection. The outcome is the same anyway.