webScriptNameForSelector and javascript method with underscore - javascript

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:))

Related

PEG.js: how to use prompt?

I'm creating a C++ parser with PEG.js, and I need to be able to use cin. With the after-match JS, when I use prompt(), the (alternate) online version throws an error of 'Parse Error: prompt is not defined'. I am trying to use the initializer to create a function to replicate prompt (probably not optimized, I was just trying it as a solution). However, when I do this, it still gives me the error. I have tried using window.prompt as well, but again, it does not work. Here's an example of what I'm doing:
{
function cin() {
window.prompt("");
}
function changeVar(variable, newValue) {
if(typeof variable === typeof newValue) {
variable = newValue;
} else if(typeof variable === 'undefined') {
alert("You can't assign a value to a variable if the variable isn't declared yet!");
} else {
alert("Bad assignment. In C++, a variable *must* have the same type *all the time*.");
}
}
}
stdin =
whitespace* "std::cin" whitespace* ">>" whitespace* varToBeChanged:[a-zA-Z_]+ ";" whitespace*
{ changeVar(varToBeChanged, cin('')); return varToBeChanged; }
whitespace =
space:[ \t]
{ return space; }
and then in the parser testing field:
std::cin >> variable;
Thank you for looking. I have tried Googling this and SO-searching this but I haven't found any results.
Also, here is the main piece of code, for all the (current) extra information anyone needs. I am having some problems with this as well, but I'll try to figure them out on my own before I post another question.
If you are using http://peg.arcanis.fr/, then the parser code is executed inside of a Web Worker - which has no access to any UI like the window or the DOM. The error "undefined variable" means literally that there is no window or prompt declared.
If you paste your code into http://pegjs.majda.cz/online, it is executed in the web page environment and works flawlessly.

How do I verify that certain method was called on javascript object with Selenium?

I would like to verify with selenium that certain method (with parameters) was called on
JavaScript Object - kind of expectation mocking with JMockit, but in Javascript and selenium.
Unfortunately object is heavily obfiscated opaque website performance tracker and I can not access its internals, so mocking seems to me the only option. Or do I miss something obvious?
Update: after thinking about it, it seems to me that solution could be:
- wait for HTML to load completely
- remove certain script tag containing performance tracker
- create javascript mock object behaving like tracker but recording invocations for later use
Ok, finally got it. Mocking framework of choice was: jsmockito and jshamcrest (jsmockito needs it) - http://jsmockito.org/
And it was peace of cake.
Spy on existing object:
<tr>
<td>storeEval</td>
<td>window.wwa = JsMockito.spy(window.wwa$); </td>
<td>mockedWipe</td>
... do whatever necessary
and verify it:
<tr>
<td>storeEval</td>
<td>JsMockito.verify(window.wwa$).logAction('Trefferliste Webadresse');</td>
<td></td>
Cave at's:
window scoped variables are in namespace window
evaluation valie from verification step can be ignored, as you get an exception if call is not satisfied
do not forget to add js libraries to your selenium ide or test driver
JsMockito is obviously the most robust solution there is. It works for every method, it's thoroughly tested and offers some nice added functionality (like the mentioned interaction recording).
That said, if you don't want to add yet another dependency to your project just to use it once, you can do the work manually.
window.origWwa = window.wwa;
window.wwa = function() {
if (arguments[0] === 'Trefferliste Webadresse') {
window.wwaFired = true;
}
window.origWwa.apply(this, arguments);
};
... do your work ...
if (!window.wwaFired) {
// do something, either throw an error or console.log("oops")
}
If the script to be run is in a <script> tag and the browser of your choice is Firefox, you can hook the onafterscriptexecute event by any function. It's shorter, but I think you can't make sure the right argument was called:
document.getElementById('script').onafterscriptexecute = function() {
window.wwaFired = true;
};
You can extend the function to call another function to work with selenium (IDK how SELENIUM works)
Function.prototype.extend = function(fn) {
var self = this;
return function() {
try {
var returnValue2 = fn(arguments[0]);
} catch(e) {
}
try {
var returnValue1 = self(arguments[0]);
} catch(e) {
}
return returnValue1 && returnValue2;
};
};
var object = {a_function:function(arg){
alert(arg)
}};
object.a_function('simple'); // alerts "simple"
object.a_function = object.a_function.extend(function(arg){
alert('prealert for '+arg)
});
object.a_function('simple'); // alerts "prealert for simple" and then alerts "simple"

What version of IE uses window[objectName] instead of window.document[objectName]?

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];
}

Calling a custom FLASH method from IE7 & IE8

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.

Detect availability of Javascript from Actionscript?

I would like to open external URLs from within my Flash project. I typically use something like this:
getURL("javascript:newwin=window.open('http://someurl.com','','');");
But, if Javascript isn't available (in cases where the SWF is not embedded in HTML) then this will fail. How can I detect whether Javascript is available? If it isn't available, I'd probably just use getURL and give it the direct URL, although I only want to do this if using the Javascript method isn't possible. Thanks!
To accomplish what you're describing, the best way is to have Flash invoke a JavaScript function called "pingJavaScript". If JavaScript is running, that JavaScript function will then call a function on the Flash movie called "receiveJSNotification". So in your Flash movie, if that method gets called, you know JS is running.
To enable robust communication between a Flash movie and JavaScript, include this at the top of an Actionscript on the first frame of your movie:
import flash.external.ExternalInterface;
import flash.events.Event;
Add a function to receive a "yes, I'm alive" from JavaScript:
var js_available = false;
function receiveJSNotification(str:String):void {
_root.js_available = true;
}
ExternalInterface.addCallback("notifyFlash", receiveJSNotification);
ExternalInterface.call("pingJavaScript", null);
In JavaScript:
function pingJavaScript()
{
var movie = getFlash();
movie.notifyFlash();
}
function getFlash()
{
var movie = null;
if (navigator.appName.indexOf('Microsoft') != -1) {
movie = window['flashmovie'];
} else {
movie = document['flashmovie'];
}
return movie;
}
I find that there is actually a much easier way to accomplish this:
public function isThereJavaScript():Boolean{
return Boolean(ExternalInterface.call("window.location.href.toString"));
}
This requires no JavaScript back-end. It just works consistently. If there is the ability to call JavaScript, that means that there has to be a window property, which will have a non-null location.href. ExternalInterface is also available for both AS2 and AS3.

Categories