My web app includes an ActiveX control. However, when I run the app, I got error "object expected" error intermittently. It seems sometimes the control is not ready when I call its properties/methods. Is there a way that I can detect whether an object is ready using JS?
Thanks a lot.
If its not you own app, see if you can identify some harmless property or method and then design a wrapper method around the call that tests with try catch if it can access the object, and if yes, call next method in chain (maybe using a delegate to include arguments, and if not ready, use setTimeout to call the wrapper again in say 100 ms.
You might want to include a retry counter to bailout after a few tries so that it's not an infinite loop if the object is broken.
Example:
function TryCallObject(delegate, maxtries, timebetweencalls, failCallback, retrycount)
{
if(typeof retrycount == "undefined")
retrycount = 0;
if(typeof failCallback == "undefined")
failCallback null;
try {
//code to do something harmless to detect if objects is ready
delegate(); //If we get here, the object is alive
} catch(ex) {
if(retrycount >= maxtries)
{
if(failCallback != null)
failCallback();
return;
}
setTimeout(function () {
TryCallObject(delegate, maxtries, timebetweencalls, failCallback, retryCount + 1);
}, timebetweencalls);
}
}
And its called like this
TryCallObject(function() { /* your code here */ }, 5, 100);
or
TryCallObject(function() { /* your code here */ }, 5, 100, function() {alert("Failed to access ActiveX");});
If it is your own app, include a readystate event
http://msdn.microsoft.com/en-us/library/aa751970%28VS.85%29.aspx
The way we do this in FireBreath (http://firebreath.org) is to fire an event to javascript; it does this by providing a function name in a <param> tag, get a reference to the browser window IDispatch pointer, and do a PROPERTYGET for the function named in the param tag.
We then call that method when the plugin is ready to go. This has the advantage of working pretty much the same way in all browsers, since FireBreath plugins work both as ActiveX controls and NPAPI Plugins.
Related
What kind of handler/hook do I need to set from Greasemonkey script to capture small changes like adding new page elements (thinking of FB messages..)?
Can I change the style and innerhtml before the element is drawn?
You can override many native functions. If it was the element creation, you'd override document.createElement:
//Remember the old function refference
var old_createElement = document.createElement;
//Override the native function
document.createElement = function(tagName) {
//Our own script for the function
if(!confirm("Element "+tagName+" is being created. Allow?"))
throw new Error("User denied creation of a element.");
else
//And eventual call for the original function
return old_createElement(tagName);
}
Regarding the DOM elements, there seems to be no means of capturing the DOM parser element creation. (creation from HTML string)
Similarly, you can override AJAX methods and in fact I have done this on facebook to see how messages are sent - and I noticed they're sent with tons of other data.
Here's a part of my greasemonkey script for this purpose:
function addXMLRequestCallback(event, callback){
var oldSend, i;
if( XMLHttpRequest.callbacks!=null ) {
// we've already overridden send() so just add the callback
//XMLHttpRequest.callbacks.push( callback );
if(XMLHttpRequest.callbacks[event]!=null)
XMLHttpRequest.callbacks[event].push(callback);
} else {
// create a callback queue
XMLHttpRequest.callbacks = {send:[], readystatechange:[]};
if(XMLHttpRequest.callbacks[event]!=null)
XMLHttpRequest.callbacks[event].push(callback);
// store the native send()
oldSend = XMLHttpRequest.prototype.send;
// override the native send()
XMLHttpRequest.prototype.send = function() {
// process the callback queue
// the xhr instance is passed into each callback but seems pretty useless
// you can't tell what its destination is or call abort() without an error
// so only really good for logging that a request has happened
// I could be wrong, I hope so...
// EDIT: I suppose you could override the onreadystatechange handler though
for( i = 0; i < XMLHttpRequest.callbacks.send.length; i++ ) {
XMLHttpRequest.callbacks.send[i].apply( this, arguments );
}
/*if(typeof this.onreadystatechange == "function")
callbacks.readystatechange.push(this.onreadystatechange);*/
var old_onreadystatechange = this.onreadystatechange;
this.onreadystatechange = function(event) {
for( i = 0; i < XMLHttpRequest.callbacks.readystatechange.length; i++ ) {
try {
XMLHttpRequest.callbacks.readystatechange[i].apply( this, arguments );
}
catch(error) {
console.error(error);
}
}
if(typeof old_onreadystatechange == "function") {
old_onreadystatechange.apply(this, arguments)
}
}
// call the native send()
oldSend.apply(this, arguments);
}
}
}
//Usage
addXMLRequestCallback( "send", function(data) {
console.log(data);
});
addXMLRequestCallback( "onreadystatechange", ...);
I also often use the MutationObserver in userscripts. At allows to to watch over either properties or children and calls a callback for every added/removed node.
I'm not sure how good the performance is and how easy will it be to hook up the correct node.
If you had eventually succeded in capturing creation of facebook chat message containers and/or posts on wall, I'd really love to see how you did it.
For a long time, I'm thinking of adding Markdown on facebook. Many friends share sourcecode here but it's barely readable.
This question isn't exactly typescript related but without the context it would be unclear why I would even require such behavior. Should be relatively straight forward to understand whether you know Typescript or not.
I have a dialog class implementation in Typescript that looks something like this (only showing relevant methods and fields):
class BaseDialog{
...
public dialogEl: JQuery;
public AjaxLoadContent(route: string) {
if (this.dialogEl !== undefined)
this.dialogEl.load(route);
return this;
}
public HtmlLoadContent(html: string) {
if (this.dialogEl !== undefined)
this.dialogEl.empty().html(html);
return this;
}
public Show() {
if (this.dialogEl !== undefined)
this.dialogEl.dialog("open");
}
...
}
I'm returning this from AjaxLoadContent() and HtmlLoadContent() so that I can chain a call to Show() as follows:
var dialog = new BaseDialog();
dialog.AjaxLoadContent("/Account/Login").Show(); //Ajax call
dialog.HtmlLoadContent(someHtml).Show(); //Load from variable, no ajax call
I find this chaining syntax very clean and logical so I want to stick with it, however, in the ajax scenario, Show() gets called before ajax load() completes so the dialog opens, then there is a delay before the content appears. I can't provide a callback to load() since I'd like to explicitly chain Show() onto the call instead of calling it internally...therefore, I need some kind of synchronous mechanism.
I'm now looking into Frame.js to accomplish this "synchronous" style without hanging the browser with something like $.ajaxSetup({async: false;}). Here is the answer I was hoping would work: https://stackoverflow.com/a/10365952
However, the following code still has the delay:
public AjaxLoadContent(route: string) {
if (this.dialogEl !== undefined){
var that = this;
Frame(function (next) {
$.get(route, next);
});
Frame(function (next, response) {
that.dialogEl.html(response); //Breakpoint 1
});
Frame.init();
return this; //Breakpoint 2
}
}
However this doesn't seem to work as Breakpoint 2 gets hit first despite the explicit control flow I've defined. The Show() call happens immediately after return this (therefore loading a blank dialog), then finally that.jQueryDialog.html(response) gets called from the second Frame, loading the content after the dialog has already been shown (therefore still a delay).
How can I accomplish this synchronous behavior?
This is exactly (IMO) what JQueryDeferred is for. You can use that for all this without needing to add another dependency on Frame.js. The easiest way to do this would be to return a JQueryPromise from each Async method, like so:
///<reference path="./jquery.d.ts">
class BaseDialog{
public dialogEl: JQuery;
public AjaxLoadContent(route: string):JQueryPromise {
var deferred = $.Deferred();
if (this.dialogEl !== undefined)
this.dialogEl.load(route)
.done(() => deferred.resolve())
.fail(() => deferred.reject());
return deferred.promise();
}
public HtmlLoadContent(html: string):void {
if (this.dialogEl !== undefined) {
this.dialogEl.empty().html(html);
}
public Show():void {
if (this.dialogEl !== undefined)
this.dialogEl.dialog("open");
}
}
var dialog = new BaseDialog();
dialog.AjaxLoadContent("something")
.done(() => dialog.Show());
That's not quite as clean an interface, but the alternative is to do some awfully clever coding whereby your class throws each Deferred into a FIFO queue, and each subsequent method waits on the previous Deferred in the queue before it starts executing. Certainly possible, and if you're designing this API for significant external consumption, it might be worth doing. But if you're just planning to use it for some internal project, it sounds like too much work and maintenance to me. (Just my opinion, of course :-).
(Other problems with your proposed interface: (1) it doesn't have any way of handling errors, analagous to the JQueryDeferred.fail() handler; and (2) it doesn't have any way of doing any external processing in-between calls to your class. What if you wanted to do a transform on the content before you called the Show() method?)
"However this doesn't seem to work as Breakpoint 2 gets hit first despite the explicit control flow"
Actually the flow control is working exactly as you have written it. Only things inside the Frame functions will be controlled by Frame. You can not use return statements inside of callbacks and expect them to return the calling function.
Ken's answer is correct that the use of jQuery Deferred will accomplish the same goal as Frame does in your above example. Frame is designed for sequences much longer than the one you have created. Either will behave the same way, the major difference is syntax.
Honestly, I think the delay you are experiencing is the time it takes to make the AJAX call. Maybe I am not understanding your question, but the Frame part looks right. Here are a few notes:
public AjaxLoadContent(route: string) {
if (this.dialogEl !== undefined){
var that = this;
Frame(function (next) {
$.get(route, next); // great!
});
Frame(function (next, response) { // good use of passing variables!
that.dialogEl.html(response); // yep, will happen synchronously!
// return that; // unfortunately, this would only return 'that'
// to Frame, not to AjaxLoadContent.
// It's not possible to return the calling function
// from inside a callback.
next(); // the callback should be called here
// to complete the Frame sequence.
});
Frame.init();
return this; // notice that the return statement here is not in Frame?
}
}
I'm trying to load a script so I can use scripts on the page that is spawned by the bookmarklet. (view src: XHR followed by beautify.js followed by prettify.js)
I know what I am basically supposed to do (like this) but what's happening is I can't find a good way to detect when the functions I need are actually loaded.
var doWhenLoaded = function (name) {
if (typeof(eval(name)) === 'function') {
eval(name+'()');
} else {
setTimeout(
function () {
console.log("from timeout: "+new Date().getTime());
doWhenLoaded(name,call);
} , 50
);
}
}
I tried that but eval(name+'()'); throws an error.
I can't answer your question, but to test if a function is available use:
var doWhenLoaded = function (name) {
if (typeof window[name] == 'function') {
window[name]();
} else {
// set the timeout. Should have a limit, else it wil go on forever.
}
...
};
Edit
Updated to use window[name], but really should use a reference to the global object. But I guess it's ok to use window for a browser specific script.
The code above should not throw any errors. Since name is in the formal parameters, it's essentially a declared local variable. If name is undefined, then typeof name will return the string "undefined", which fails the test so name() is not evaluated.
I think I can force the scripts to get loaded synchronously before I end up calling them by simply writing the document rather than setting them into the dom.
I am working on a plugin that needs to receive calls from javascript. Specifically, it needs to be able to give a callback function to javascript, and the javascript needs to be able to call that function later with at least a string argument. The javascript looks something like this (ideally):
var callback = null;
var setCallback = function(cb) {
var callback = cb;
};
var input = document.getElementById('my_text_input_field');
input.onkeypress = function(ev) {
// Did the user press enter?
if (ev && ev.which == 13) {
callback(input.value);
return false;
}
};
I'm imagining my C code looks something like this, so far:
void SetCallback(void (*callback)(const char*)) {
NPVariant npCallback;
OBJECT_TO_NPVARIANT(callback, npCallback);
NPVariant args[] = { npCallback };
size_t nargs = 1;
NPVariant result;
// gFuncs is an NPNetscapeFuncs pointer
NPIdentifier method = gFuncs->getstringidentifier("setCallback");
// gJavaScriptAPI is an NPObject pointer
gFuncs->invoke(gInstance, gJavaScriptAPI, method, args, nargs, &result);
}
Is this a reasonable start? If so, what do I need to do in the callback function to handle calls to it? If not, what is the correct way to do something like this, or is it not possible in NPAPI?
Thank you in advance.
Basically what you need to do is provide a NPObject that implements InvokeDefault; you pass that back to the page in response to some Invoke or GetProperty call, and then javascript can call it as a function any time with whatever arguments you wish.
For more information about NPObjects in general, see http://npapi.com/tutorial3
FireBreath abstracts all of this so that 90% of the heavy lifting is done for you; if you haven't looked at it I highly recommend it.
I may be completely wrong about this, but in Internet Explorer, you use window.external. But of course MSIE is a different architecture from Netscape-based NPAPI, so I can't be sure.
Anyway, you might find this tip useful if you had to do this in MSIE.
I have a Javascript API, which should be usable with GWT and Flex. Using the FABridge it is really easy to call Javascript methods from AS3 and vice versa. But when I try to register a callback to an AS3 method in my Javascript API I get stuck. Here is a short code sample:
public function initApp():void {
if (ExternalInterface.available) {
ExternalInterface.addCallback("foobar", foobar);
}
}
public function foobar():void {
//the callback function
Alert.show("Callback from API works!");
}
private function btnCallbackClicked():void {
ExternalInterface.call("testAPICallbackFromJS", Application.application.foobar);
}
And the simple JS method:
function testAPICallbackFromGWT(callback){
$clinit_26(); //added by the GWT compiler
alert('callback to be launched 3 2 1');
callback();
}
But this version does not work, because I always receive an empty function in my JS code. It seems that the FABridge is cutting the rest.
Then I tried a different approach. I wrote a little JS method, which takes the name of the function and creates the callback from the JS side.
registerFlexCallback = function(registerMethod, callback, id) {
/*
workaround to create a callback for an AS method, which can be called by Javascript
* registerMethod - Javascript method which shall be called for registration with the created callback as parameter
* callback - AS method that shall be called by Javascript (available over the FABridge interface)
* id - ID of the flash object (use Application.application.id in AS)
*/
var swf = document.getElementById(id);
eval(registerMethod + "(swf." + callback + ");");
};
This one works well with the Internet Explorer, but with no other browser. For example in Firefox I get the following error message:
NPMethod called on non-NPObject wrapped JSObject!
Can somebody tell me, what this error is about (maybe some kind of security issue)? Or does anyone have a better idea how to create callbacks for my AS3 methods which can be called by JS?
This is because functions don't serialize across the FABridge. Meaning in your
ExternalInterface.call("testAPICallbackFromJS", Application.application.foobar);
the second parameter will always be null. What I do is add a wrapper method on the HTML page via eval that points at my embed and therefore the added callback. So you have to add an extra, while annoying step:
ExternalInterface.addCallback("foobar", foobar);
var callBack:String = "";
var functionName:String = UIDUtil.createUUID;
callBack = "function " + functionName + "( ){ " +
"document.getElementById('applicationName').foobar(arguments);"+
"}";
ExternalInterface.call("eval", callback);
ExternalInterface.call("testAPICallbackFromJS", functionName);
The NPObject error you're seeing I'm pretty sure is a security error ( based on where it comes from in the FF code ) probably preventing you from dynamically injecting methods that can be eval'ed without the JS interpreter getting in the way.
I haven't even tried to compile the above so, hopefully you get the gist.
I notice two things right away
firstly it appears your ExternalInterface will die if the ExternalInterface is not ready.
public function initApp():void {
if (ExternalInterface.available) {
ExternalInterface.addCallback("foobar", foobar);
}
}
I would add a timout and then try again so that it tries again until Externalinterface is ready.
Also I don't see the function "foobar" in your javascript code. I see callback passed in as a variable but without varifying that it is in fact 'foobar' this is hte kind of thing that can make testing a misserable event.
function testAPICallbackFromGWT(callback){
$clinit_26(); //added by the GWT compiler
alert('callback to be launched 3 2 1');
callback();
}
I would simplify your testing example so that there are less moving parts.
// e.g. run just flash to javascript only
ExternalInterface.call("alert", "hello out there");
if that works
// establish the call from flash
ExternalInterface.addCallback("hello_out_there", foobar);
// and in javascript
alert(typeof('hello_out_there')); // will be 'function' if exists or undefined if ExternalInterface did not work
This way you can get a handle bit for bit what is working and where it breaks down.
Pay atention to the timing, if you can tigger your flash from button actions and your javascript from links you can illiminate a number of loading issues as well. of course you'll need to solve an autoload version for your launch but for testing manually triggered events can simplify things significantly.
also because it's javascript the browser is relevant.
I've seen consistent results in Firefox and Internet explorer that break down in safari and sometimes IE is the odd browser out.
Sometimes Firefox is the only one that breaks.
you just have to test them all.