i've developed a c# Library, registered as COM component. Now i need to import the ActiveX created into a html page with Javascript to use the ActiveX function. All is fine except for Callback, probably i lack in knowledge in Javascript but i'm still not able to use properly Callback. I've searched many example but some are too much deep for my objective and other one can't clear the point, so here the question.
I will explain myself:
Thi is the Event in the ActiveX component
public delegate void ButtonEvent(object sender, SignEventArgs e);
public event ButtonEvent ButtonSignOk;
This is the snippet of my Javascript
try {
var Lib = new ActiveXObject("AGI.GraphometricLib");
Lib.Initializer();
Lib.addEventListener('ButtonSignOk', OnOkHandler, false);
} catch (ex) {
alert("Error: " + ex.message);
}
function OnOkHandler(arg1, arg2){
alert("Pressed!");
}
Obviously the addEventListener return an error.
Error: Object doesn't support property or method 'addEventListener'
How can i properly setup a javascript callback for that event defined in the ActiveX ?
Event handlers for ActiveX objects can be written with the following syntax:
function Lib::ButtonSignOk(sender, e) {
alert("Pressed!");
}
However, there is a catch. The nature of Javascript is that
function declarations are evaluated before anything else in the file
this function declaration is interpreted as adding an event handler to the object referred to by Lib, which doesn't exist at the beginning of the file.
The solution is to force the function declaration to be evaluated after the variable initialization, e.g.:
var Lib = new ActiveXObject("AGI.GraphometricLib");
Lib.Initializer();
(function() {
function Lib::ButtonSignOk(sender, e) {
alert('Pressed!');
}
})();
See here for a full writeup, and here for a library I've written that makes this a little easier.
Related
I'm creating an extension in chrome for the first time (I'm not a web, or javascript developer). I'm adding onto a codebase that is in an older version of javascript that I've never used (Once I'm at a computer with that codebase, I'll tag which version it is, but I can't remember).
I have a class called DownloadManager, and inside of it I am calling chrome.downloads.onChanged, and within it, I call another function inside of the class, but it can't recognize the class (I think that's the issue).
// Class named DownloadManager
function DownloadManager(someData) {
this._myData = someData;
// function that does a thing, and tests run successfully
this.doAThing = function(someData) {
// Code in here that we assume works, and there's no issues.
}
if(chrome.downloads) {
chrome.downloads.onChanged.addListener(function(delta) {
// Error here
this.doAThing(delta.data);
}
}
}
The error I'm getting is on the this.doAThing(this._myData); line. The error is Error in event handler for downloads.onChanged: TypeError: Cannot read property 'doAThing' of null at <URL>.
I'm assuming it's a scoping issue, and this. doesn't mean anything there, and it can't access doAThing there. I'm certain that the argument taken in is of the same type as the function declared above.
I'll add more data when I'm back in that environment.
Inside your event handler for chrome.downloads.onChanged the this keyword now has a different context than this inside the DownloadManager. It might make sense that since you defined the event handler within the downloadManager that you could share the variable, but that just happens to be a coincidence of "where the code was defined vs where the code is invoked from".
You could probably get away with assigning this to a variable in the main scope:
function DownloadManager(someData) {
this.doAThing = function(someData) {
// Code in here that we assume works, and there's no issues.
}
window.myScope = this;
if(chrome.downloads) {
chrome.downloads.onChanged.addListener(function(delta) {
// Error here
window.myScope.doAThing(delta.data);
}
}
}
I got some JS Code that gets inside a random Anonymous js function.
I want that code (for example alert('hello') ) to dump/alert
the entire script block/object which it was injected into.
kinda like document.body.innerHTML but for the anonymous function block
result should be like :
Function()({ somecode; MyAlert(...) } )()
or
Try { some code; mycode; } catch(e) { }
Mind your terms. "(browser) script block" literally means script element's code by the spec.
Use "javascript block" or "javascript object" to mean a block or an object.
Do not create confusing new terms; do read and research.
Blocks are not objects; they are language statements.
Just like you cannot "get the code/variables of current line", you cannot "get the code/variables of current block", try block or not.
Stepping back, for now you can use Function.caller to get the function calling your code:
var mycode = function me(){ if ( me.caller ) alert( me.caller.toString() ); };
(function(){ var some = 'code'; mycode(); })();
// Alert "function(){ var some = 'code'; mycode(); }", even when it is anonymous
Note that you get the whole function's code, not the function block's code which excludes parameters and function name.
Function.caller may be removed in future, like arguments.caller. (Both are troubles. What if a cross origin function on the call stack contains private api key code? How should js engines inline your code?)
When the time comes, or when caller is null (when it is global code), you may still be able to get textual stacktrace (new Error().stack) and current script element (document.currentScript), but their capabilities are pretty limited.
You can get a script element's code - if any - with its textContent or innerHTML property.
Your question sounds like an XY Problem. You want to do something that no modern language is meant to do, but never say for what purpose.
Try to describe your real problem.
Functions have a toString() method. (Yes functions have methods!)
var fn = function() { alert('hello') };
fn.toString() // "function() { alert('hello') };"
So you can alert it:
alert(fn.toString());
You can log it to the js console:
console.log(fn.toString());
Or even write it to the page.
document.getElementById('someID').innerHTML = fn.toString();
However, this won't work for every function in the universe.
[].push.toString()
"function push() { [native code] }"
Some functions are not implemented with javascript, but in the compiled code of the browser or JS engine. For these environment provided functions, you will get this above less helpful output.
If you're not in strict mode you can go up the stack from something which was referenceable (i.e. a named function expression) using (non-standard) .caller
function getFunctionReference(callback) {
var ref = getFunctionReference.caller;
if (callback) callback(ref);
return ref;
}
Now you can do things like
(function () {
getFunctionReference(alert);
}());
// alerts the .toString of the IIFE
This only works for functions, you can't do this on top level code.
The best way to explore your code is actually with the Console, and you can use the debugger; statement or breakpoints to follow exactly what is happening and when.
As a flash developer, i try to have the same flexibility as AS3 provide with mootools.
I try to do a simple thing, create an event handler function that be protected.
I hate to write inline function so i writte something like this:
//CLASS DEFINITION AS USUAL
initializeEvent:function (){
if (this.options.slider) this.options.slider.addEvents ({
mousedown:function (e){
this.sliderDownHandler();
//throw an error because sliderDownHandler is set to protected
}
});
},
update:function (){
this.fireEvent('update');
}.protect(),
sliderDownHandler:function (e){
this.update();
console.log ('yeah it down')
}.protect();
Without the .protect() the handler work as expected.
It's possible to reach this goal with the .protected() ?
Many thank!
sure you can. you have a binding error, not a problem with protected
mousedown:function (e){
this.sliderDownHandler();
//throw an error because sliderDownHandler is set to protected
}
no. it is throwing an error because this will be bound to this.options.slider, which fired the event - which I guess is an element that has no sliderDownHandler method. the exception you get on a protected method is quite unique and is no mistaking it - try it by calling it externally on instance.sliderDownHandler()
re-write as one of these:
var self = this;
...
mousedown:function (e){
self.sliderDownHandler();
}
// or, bind the event to the class instance method...
mousedown: this.sliderDownloadHandler.bind(this)
I have a VB.net class registered for COM interop which I'm instantiating within an HTML page using the following code:
<script type="text/javascript">
var MyClass = new ActiveXObject("Namespace.TestClass");
</script>
I can call methods on it just fine, but suppose I want to set a javascript function as a property, like so:
MyClass.TestFunction = function () { alert("It worked!"); }
How would I set my vb.net code up to be able to fire that function? This is how MSXML works in javascript for XMLHttpRequest objects, you can set
XHR.onreadystatechange = function () {}
I'm looking for a similar implementation in my class.
You have to expose a COM event, and assign the JavaScript method to that event. This way, when you invoke the event in your code, the JavaScript method will be called.
Example -
C# Code
[ComVisible(false)]
public delegate void OperationCompleted(string message); //No need to expose this delegate
public event OperationCompleted OnOperationCompleted;
if(OnOperationCompleted != null)
OnOperationCompleted("Hello World!");
JavaScript
comObject.OnOperationCompleted = function(message) { alert(message); }
Note: I have done this before. And I guess there was some COM related error. To resolve it I had to attach some attribute somewhere in the code (I don't remember it exactly right now). But you'll be able to figure it out or google it.
After trying for a while, we managed to figure out a solution that worked pretty well. Since we're setting a javascript function to the property, all the properties and methods on that function are made available to the VB.net, including the javascript standard methods, call and apply:
(function () { alert("Hello"); }).call();
The solution was to just invoke the call method in the VB.net code and it seems to work pretty well.
The HtmlObject provides all the necessary functionality to register managed event handlers for script and DOM events, but what if the class you need to listen to doesn't exist as a DOM element, but a scripting variable (referenced via ScriptObject) instead?
A javascript object doesn't support the concept of attached events. However it may support the concept of a property holding a reference to function that if assigned will be called at a certain point.
I take you have such an object?
If so you use the ScriptObject SetProperty method using the name of the property that should hold a reference to a function and a delegate to Managed method matches the signature that the Javascript object will call.
Caveat the following is untested at this point but should put you on the right path.
//Javascript in web page.
var myObj = new Thing();
function Thing()
{
this.doStuff = function()
{
if (this.onstuff) this.onstuff("Hello World");
}
}
// C# code in a Silverlight app.
class SomeClass
{
private ScriptObject myObject;
public SomeClass(ScriptObject theObject)
{
myObject = theObject;
myObject.SetProperty("onstuff", (Action<string>)onstuff);
}
function void onstuff(string message)
{
//Do something with message
}
}
As stated by AnthonyWJones, Silverlight can't attached to JavaScript events. The right thing to do in this situation is to do the following:
Enable scripting access in Silverlight:
Mark the class with the
ScriptableType attribute, or mark
the specific methods with
ScriptableMember
Call
HtmlPage.RegisterScriptableObject in
the constructor.
Once everything is set up in the Silverlight code, here's what you do in JavaScript:
Obtain a reference to the JavaScript
object and register an event handler
Use document.getElementById to get
the Silverlight control
Call .Content.. in the
JavaScript event handler. For
example,
silverlight.Content.Page.UpdateText(text).
So basically, all event handling is performed in JavaScript, but the JavaScript event handlers can be used to call functions in Silverlight.