I am trying to use a Javascript callback to a Flex application embedded in my page. Looking through some examples, I've seen this code used to get a reference to the Flex application:
// Get the reference:
function thisFlexApp(appName) {
if(navigator.appName.indexOf ('Microsoft') != -1) {
return window[appName];
}
else {
return window.document[appName];
}
}
// Use it:
var someVariable = thisFlexApp('NameOfFlexApp').callbackMethod();
I used that method, but using IE9 I got errors indicating the "thisFlexApp" call didn't work. Turns out that window.document[appName] worked in IE9, but window[appName] didn't. Since I don't expect my government clients to be using IE9 yet, I'm wondering what version of IE this method would actually work on? Is there another test that would be better to use instead of the one above which just assumes all versions of IE work a certain way? Thanks in advance.
Don't check the browser version, check the browser's capabilities. You can just check if window[appName] exists, and if it does, use it.
function thisFlexApp(appName) {
if(window[appName]) {
return window[appName];
}
else {
return window.document[appName];
}
}
Or even shorter:
function thisFlexApp(appName) {
return window[appName] || window.document[appName];
}
Related
I am logging my errors on a web page that's running javascript, and I see that the following code:
JSON.stringify(
Object.getOwnPropertyDescriptors(Node.prototype)
);
fails with:
undefined is not a function
What could be the explanation for that? I am under the assumption this happens when the page was loaded not on a normal browser but by using WebView.
I opened an Android Emulator and verified this page on a normal browser and using a WebView Test app - it worked fine.
What else can I do to debug it? This error is raised quite often.
Edit
I added further logging and I checked the following:
Object.getOwnPropertyDescriptor(Node.prototype, "childNodes");
Object.getOwnPropertyDescriptor(Node.prototype, "parentNode");
Object.getOwnPropertyDescriptor(Node.prototype, "hasChildNodes");
And only for hasChildNodes a value is returned.
It would appear that on some of the browser/webview brands or versions your code runs on, either JSON.stringify or (more likely) Object.getOwnPropertyDescriptors is not defined (the former was added in ES5, the latter much more recently in ES2017).
What else can I do to debug it?
Add tests and log the user agent string:
if (!JSON.stringify) {
/* ...log that `JSON.stringify` isn't supported, w/`navigator.userAgent`...*/
} else if (!Object.getOwnPropertyDescriptors) {
/* ...log that `Object.getOwnPropertyDescriptors` isn't supported, w/`navigator.userAgent`...*/
} else {
/* ...log `JSON.stringify(Object.getOwnPropertyDescriptors(Node.prototype))` ... */
}
In a comment you've asked:
So do you know of a way in which I could get the getter function childNodes of the Node.prototype in whichever browser? In all my tests (mobile emulators and browsers) it is always an "own" property of the Node.prototype.
If you're seeing undefined for Object.getOwnPropertyDescriptor(Node.prototype, "childNodes") in some unusual implementation, you may have to loop using Object.getPrototypeOf to find where it is in the inheritance chain:
function getDescriptor(obj, name) {
let descr;
while (obj && !(descr = Object.getOwnPropertyDescriptor(obj, name))) {
obj = Object.getPrototypeOf(obj);
}
return descr;
}
Then you'd use const childNodesDescriptor = getDescriptor(Node.prototype, "childNodes"); or similar.
But beware that host-provided objects like Node.prototype are also allowed to break some (but not all) rules. You may have to allow for the possibility there are implementations where you just can't get that getter.
I have a page that renders just fine. On the page is a control and I wanted to set the visibility to hidden. I can get a handle on the object just fine but then when I went to use what I thought were pretty typical methods such as:
.setVisible(false);
or
.css("visibility", "hidden");
I got the object doesn't support method error.
Now to solve my visibility problem there was a containing div for the control so I just set the div to hidden.
$('#footer_statecode').hide();
My question however for the future is how would I discover the methods supported by an object.
My google searches came close such as this SO post but in these example the person had a specific method they were looking for. I am interested in seeing everything available....and it doesn't have to be via an alert(); I'd be just fine using some capability in the different browsers Developer tools (F12).
Thank you once again for sharing your knowledge.
You can use this. It won't include built-in JavaScript methods (ex Array.prototype.push)
var methods = [];
for (var prop in object) {
if (typeof object[prop] === "function") {
methods.push(prop);
}
}
You can find it like this:
function getMethods(prop)
{
var res = [];
for(var prop in x) {
if(typeof x[prop] == 'function') {
res.push(prop);
}
}
return res;
}
You can also look at the Object.prototype.hasOwnProperty()
I am using a WebView in my application and it the page I am loading has some existing javascript function calls that were used in a windows environment and should now be used in a mac application. My issue is that the current javascript (ported from a windows app where the following works) function calls objective C like this:
function callObjectiveC
{
window.external.MY_ObjectiveCFunction();
}
I have been trying to use:
+ (NSString *)webScriptNameForSelector:(SEL)sel
{
if (sel == #selector(MyObjectiveCFunction))
{
return #"My_ObjectiveCFunction";
}
}
based on: https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/WebKit/Protocols/WebScripting_Protocol/Reference/Reference.html but to no avail. Is there a way to do this? I can call the objective C method whatever I want I just need to be able to map that to what is in the existing javascript.
Thanks,
c.
Figured out a solution:
- (id)invokeUndefinedMethodFromWebScript:(NSString *)name withArguments:(NSArray *)args
{
NSLog(#"invoke undefined method: %#", name);
if([name isEqualToString:#"My_ObjectiveCFunction"])
{
return NSSelectorFromString(#"My_ObjectiveCFuntion");
}
return nil;
}
you just shouldn't use underscore characters. That is basically the only valid solution unfortunately.
see here at the apple docs
I don't think using invokeUndefinedMethodFromWebScript: is a good idea here
Missing colon.
if (sel == #selector(MyObjectiveCFunction:))
I am trying to call a custom method of an embedded flash like so:
var flash =
navigation_get_flash_movie_object('main');
if (flash) {
flash.continentOut(id); }
Which works great in Chrome ans Safari, but fails utterly in IE7 & IE8. The browsers throws an error that the object doesn't have such a method.
I am using the example from http://www.permadi.com/tutorial/flashjscommand/, and now that I've tested it, it also fails at it's testing page as well http://www.permadi.com/tutorial/flashGetObject/
Does anyone have a better way to invoke custom functions in a Flash object from Javascript?
Check out the ExternalInterface API Docs. They use this method:
function thisMovie(movieName) {
if (navigator.appName.indexOf("Microsoft") != -1) {
return window[movieName];
} else {
return document[movieName];
}
}
So you would do this:
var flash = thisMovie('main'); if (flash) { flash.continentOut(id); }
(I'm assuming of course that you're using ExternalInterface.addCallback() to define continentOut)
Here's another option:
function thisMovie(movieName) {
return document[movieName] || window[movieName];
}
Personally, this seems better because it doesn't use browser sniffing and would be future-compatible, but that's just me.
I've got this code throwing an error from an iframe:
function parentIframeResize()
{
var height = getParam('height');
// This works as our parent's parent is on our domain..
parent.parent.resizeIframe(height);
}
Not concerned about the error at all. The problem is it stops other scripts from running. Firefox, chrome or any decent browser just keeps running the rest of the scripts.
I need to suppress the error or make sure parent.parent exists before running the code.
In php I would write something like if(!empty(parent.parent) { //do stuff with parent.parent } to check if the object exists.
Yes, nested iframes is ugly O_o
Try,
if (parent.parent && parent.parent.resizeIframe) {
// parent.parent exists and supports resizeIframe
parent.parent.resizeIframe(height);
}
That should work and stop the errors.
You could wrap it up in a try/catch block:
function parentIframeResize() {
try {
var height = getParam('height');
parent.parent.resizeIframe(height);
} catch(err) {
// do something to recover from the problem, or nothing to suppress it
}
}