GWT-JSNI passing a JavaScriptObject in an external JS library - javascript

I'm desesperatly trying to create an Anno object in a JSNI method but I have a strange problem : the code in the jsni method doesn't work but if I do the same in my browser console, it works fine.
Java Part
I'm using a JSONArray in wich I add some JSONObject (with all the elements, according to Anno doc). Here's my JSNI method :
// I'm using the getJavaScriptObject() on my JSONArray
private static native void launch( JavaScriptObject steps )/*-{
var anno = new $wnd.Anno(steps);
anno.chainIndex().show();
}-*/;
Browser Part
Just to be clear, the method is called on a onShow event, so all the ressources are loaded and rendered. So when the element is displayed and the function called, I have this error in my console :
Couldn't find Anno.target 'h1'. --- anno.js:265
NB : In Anno.js, h1 is the dafault value of target.
But my steps value is right and when I do the same commands in the console it works :
var testAnno = new Anno([{
content: "namespinnerFrequencyA",
position: "center-right",
target: ".dataAuto0"
},{
content: "chooseFrequencyB",
position: "top",
target: ".dataAuto1"}]);
testAnno.show();
I don't understand why it works in one case and not in the other. I've also tried to use JSON.stringify then JSON.parse but it doesn't work either.
EDIT :
I figured something out. While debugging anno.js I figured something : when I initialized Anno in the console, the local scope look like this (bigger image here ) :
But when I use the jsni method, the local scope is absolutely different, my parameter is stored as an actual array instead of being processed normally (bigger image here ) :

The problem is that GWT code runs in an iframe (for sandboxing/isolation) and Anno only supports array types from the same browsing context.
See http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/ and http://web.mit.edu/jwalden/www/isArray.html for descriptions of the problem.
ECMAScript 5.1 added an Array.isArray() function that solves that issue and has wide browser support (back up to IE9): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
And jQuery has one too, which makes it incomprehensible (to me) that Anno doesn't use it instead of using the broken if arg.__proto__ is Array.prototype (unless it's by design). So first things first: file an issue on Anno.
As a workaround, it should be possible to use $wnd.Array.apply($wnd.Array, steps) to copy your array into an array from the top window.

It seems to me that the error message says it cant find the target dom element and not that it cant find the target property. Is the element there when your code is fired? make sure it is and get back to me.

Related

Selenium - Universal Way to Convert "WebElement" to Javascript or JQuery Object

I have a a simple WebElement and I want to perform a series(one or more) of JS/JQuery type actions on my object.
Most of the time this is easy, I simply get the ID of the object, pass that into the "ExecuteScript" function, and viola works great:
RemoteWebDriver driver = ...;
var element = driver.FindElementByXPath("..."); //Or any other type of lookup
driver.ExecuteScript(#"$('#" + element.GetAttribute("id") + "')."DoSomeStuff...;");
20% this doesn't work at all because the item doesn't have an ID. Of course there are many ways to lookup items in Selenium and many ways to lookup items in jQuery or Javascript, but they don't always map, and while it may be possible to construct a query in jQuery that can lookup a Selenium object, that methodology cannot be the same for every object type.
Searching around it seems most people use the "id" method(Examples: 1, 2, 3). You can do this the opposite way. Another idea would be to give each element a unique ID in selenium before accessing it in jQuery, but it doesn't look like that would work because to set it you need to using Javascript or jQuery.
I've yet to find a way to do this Universally for every element, how can this be done?
You can, and always have been able to, pass element references back and forth in JavaScript via ExecuteScript. Whether those raw DOM elements can be converted to be used by JQuery is a matter upon which I am not qualified to speak. Nevertheless, the code for referencing a WebDriver-found element in your JavaScript code would be something like this:
// Assume element holds a reference to an already-found
// IWebElement, found using the standard WebDriver FindElement
// methods, and that driver is a properly-instantiated
// IWebDriver object.
// N.B., doing proper casting here, since it's idiomatic in
// the WebDriver library to code to the interface, not the concrete
// implementation.
IJavaScriptExecutor executor = driver as IJavaScriptExecutor;
executor.ExecuteScript("alert(arguments[0].tagName);", element);
The above code will throw up an alert (and block your Selenium code), showing the element's tagName JavaScript property. You can use this technique to use the element just as you would in JavaScript in the page.

Keeping an instance of fabric.Image in a variable

First post here, because I cannot find any answer. I'm working on FabricJS, and I'm trying, for the need of my application, to build objects containing an instance of fabric.Image, and more specifically an instance obtained through the methode fabric.Image.fromURL() (see here for more info)
Until now it seems to work, but if I console.log my object containing the instance of the image, I got an object of type "klass", which seems to have some image-related properties, but not all of them (no position, no source, no rotations, etc).
And when I'm trying to use fabric.Image methods on this object, I got errors concerning non-existing functions.
My question is the following : is this fact known ? Is there any mean to keep an instance of a fabric.Image anywhere else than in a canvas ?
I think my code is not very relevant to post here, but if needed I will sweep up my code to make it concise and show precisely what I want.
Thanks,
Cheitan
EDIT : I tried several other things. The most promising way to do what I want was to instantiate the image object from an URL, but instead of adding it to the canvas through the callback of the function, assigning it to an attribute of my custom object. Something like that :
var that = this;
fabric.Image.fromURL('img/myImg.png', function(img){
that._image = img;
});
But this is not working either, I got the following error from fabric.min.js :
Uncaught TypeError: obj.setupState is not a function
I found several posts on this site or others concerning this error message but none of them are related to what I'm doing, it's more like JSON parsing and rebuilding fabric forms from it. Am I in a wrong way ?

Howto: generic test to see if widgets call this.inherited succesfully?

I maintain a custom library consisting of many dijit widgets at the company I work at.
Many of the defects/bugs I have had to deal with were the result of this.inherited(arguments) calls missing from overriden methods such as destroy startup and postCreate.
Some of these go unnoticed easily and are not always discovered until much later.
I suspect I can use dojo\aspect.after to hook onto the 'base' implementation, but I am not sure how to acquire a handle to the _widgetBase method itself.
Merely using .after on the method of my own widget would be pointless, since that wouldn't check whether this.inherited(..) was inded called.
How can I write a generic test function that can be passed any dijit/_WidgetBase instance and checks whether the _widgetBase's methods mentioned above are called from the widget when the same method is called on the subclassing widget itself?
Bottom-line is how do I acquire a reference to the base-implementation of the functions mentioned above?
After reading through dojo's documentation, declare.js code, debugging, googling, debugging and hacking I end up with this piece of code to acquire a handle to a base method of the last inherited class/mix-in, but I am not entirely happy with the hackiness involved in calling getInherited:
Edit 2 I substituted the second param of getInherited with an empty array. While I actually get a reference to the method of the baseclass using aspect doesn't work. It appears this approach is a bust.
require(['dijit/registry','dojo/_base/declare','mycompany/widgets/widgetToTest'],
function(registry,declare,widgetToTest)
{
var widget = registry.byId('widgetToTestId');
var baseStartup = getBaseMethod(widget,'startup');
function getBaseMethod(widget,methodName){
return widget.getInherited(methodName,[]);
}
//This is the method body I want to use .after on to see if it was called, it returns the last overriden class in the array of inherited classes. (a mixin in this case, good enough for me!)
alert(baseStartup);
});
I have given up trying to use dojo/aspect.
I have instead opted to modify the code of our custom base widget to incorporate snippets such as the one below. They are automatically removed when creating a release-build in which console-calls and their content are removed:
console.log(
function(){
(this._debugInfo = this._debugInfo|| {}).postCreate=true;
}.call(this)
);
A simple method in boilerplate code I added near the unittests is available so that I can call it on all mycompany.widgets.basewidget instances in their respective unittests.

why can my firefox extension javascript not access opener windows and not see window.name

I am writing a javascript extension and having some problems I cannot figure out.
My extension is very simple, it doesn't add any GUI elements to the firefox browser. What it does watch the mouse move around in whatever document loads in the firefox browser, and when the mouse pauses over a "term" (word, phrase, acronym) in a text-node, it creates and displays a tiny, borderless popup window that looks similar to a tooltip just above the term by calling:
var cw = window.open("chrome://meanings/content/clarify.html", "clarify", attr);
As I read the documentation, cw.name should be "clarify" (from the 2nd argument). When I read the name back with the following, it does contains the string "clarify" as it should:
var cwname = cw.name; // variable cwname does contain "clarify"
However, running tests indicates that when the code in the instance of the extension reads:
var myname0 = window.name;
var myname1 = window.top.name;
var myname2 = window.document.defaultView.name;
var myname3 = window.document.defaultView.top.name;
... none of those variables contain the name of the window - or any other string value.
I don't get it. I also tried adding the following lines after window.open() is executed:
cw.name = "clarify";
cw.content.name = "clarify";
That doesn't change anything. Those properties can be read with code like the following and this reports the values just set (to the extension code that just set them):
var test_cwname0 = cw.name;
var test_cwname1 = cw.content.name;
The code prints these variables to the error and browser consoles, which is how I know.
Another similar and possibly related problem. The window.opener property doesn't work either - that variable is always null which is obviously wrong, since those windows were created by window.open().
BTW, calling functions to move the windows created by window.open() with cw.moveTo() work properly, so there is some degree of connection between the two windows.
Something strange is going on, and I don't understand it.
Any ideas?
Unfortunately for you the window.open method does not assign its second parameter to the new window's properties - as per the mdn documentation for .open(), the second param is only used as the name you can use in a anchor's target attribute so they open their links in the new window. The reference returned by the method is your only "link" to that new window you can use in js.
The window.opener property should still be working though, regardless. You have to be careful, though about same-domain security restrictions and whatnot (described in the specs page). Thus (from your original script) cw.opener should return the current window object. From a script in the new window window.opener.cw would thusly reference its own window object.
To control when windows are closed it's entirely possible then to have the opener window control all that - it does after all have the references to any child windows and can close them with cw.close() and the like.

What could be causing this [object HTMLTableCellElement] tooltip on Firefox?

On Firefox, when hovering the mouse over a certain table in my webpage a strange [object HTMLTableCellElement] tooltip appears:
What needs to happen for this to occur? I am having a hard time narrowing what part of my code is the culprit because I don't even know what to look for.
Edit, solved the problem:
This table belongs to a Dojo Dijit template. I accidentaly gave one of the template's nodes the dojo-attach-point "title", causing Dojo to, during the rendering of the Widget, do a
this.title = the_node_with_the_bad_attach_point
The node is then converted to a string and that is where the "[object HTMLTableElement]" comes from.
Probably this:
cell.title = cell;
which can be described as a failed attempt to store the reference to the cell inside its own title property (which holds the string that is shown inside the tooltip on mouse-over).
Live demo: http://jsfiddle.net/VwYRP/
Object references - when coerced to strings - usually look like so: '[object Constructor]', where Constructor is the constructor function which the browser uses to instantiate that object.
Install Firebug and inspect the element. Do you see a title in the text? Check the DOM attributes. Maybe you can spot it there? Or maybe some JavaScript does not work properly. You'll get that message if you do an alert(document.createElement('th'));.

Categories