简体   繁体   English

JSNI脚本失败,但在Chrome Devtools控制台中运行时脚本成功

[英]JSNI script fails, but script succeeds when ran in Chrome Devtools console

I am workin on utilizing an external javascript library called cytoscape.js through JSNI using test data. 我正在努力通过JSNI使用测试数据来利用名为cytoscape.js的外部JavaScript库。 When I run the script how I want to through JSNI in my java class, it fails to produce the graph. 当我按我的Java类的要求运行脚本时,它无法生成图形。 However, when I run it through the Chrome Devtools console, it works correctly. 但是,当我通过Chrome Devtools控制台运行它时,它可以正常工作。

All of the values pass to the cytoscape.js library seemingly correctly. 所有的值看似正确地传递到cytoscape.js库。 Currently, the JSNI code fails a test performed by the Javascript library that the console code is able to pass. 当前,JSNI代码未通过控制台库能够通过的Javascript库执行的测试。

Here is the JSNI code I am using: 这是我正在使用的JSNI代码:

public static native void cytoscape() /*-{
        var cy = $wnd.cy = $wnd.cytoscape({container: $wnd.document.getElementById('cy'),
            elements: $wnd.glyElements, 
            style: [ { selector: 'node', style: { 'background-color': '#666', 'label': 'data(id)' } }, 
                { selector: 'edge', style: { 'width': 3, 'line-color': '#ccc', 'target-arrow-color': '#ccc', 'target-arrow-shape': 'triangle' } } ],
            layout: { name: 'grid', rows: 1 } });
    }-*/;

The "$wnd." “ $ wnd”。 is used to get the correct scope. 用于获取正确的范围。

Here is the console code: 这是控制台代码:

var cy = window.cy = cytoscape({ 
            container: document.getElementById('cy'),
            elements: glyElements, 
            style: [ { selector: 'node', style: { 'background-color': '#666', 'label': 'data(id)' } }, { selector: 'edge', style: { 'width': 3, 'line-color': '#ccc', 'target-arrow-color': '#ccc', 'target-arrow-shape': 'triangle' } } ], 
            layout: { name: 'grid', rows: 1 } 
        });

The elements I am using in both cases are stored in a .js file and I have made sure they are accessible in both cases. 我在两种情况下使用的元素都存储在.js文件中,并且我确保在两种情况下都可以访问它们。 Like I mentioned, Devtools debug shows me the correct values are passed into the cytoscape.js library. 就像我提到的那样,Devtools调试向我展示了正确的值已传递到cytoscape.js库中。

The JSNI code fails this return statement in the cytoscape.js library: JSNI代码使cytoscape.js库中的以下return语句失败:

var plainObject = function plainObject(obj) {
    return obj != null && _typeof(obj) === typeofobj && !array(obj) && obj.constructor === Object;
  };

If I comment out "&& obj.constructor === Object;" 如果我注释掉“ && obj.constructor ===对象;” on line 145 of cytoscape.js, the code runs correctly with my JSNI script. 在cytoscape.js的第145行上,代码使用我的JSNI脚本正确运行。 This leads me to believe the cytoscape object is being created differently through JSNI than the console. 这使我相信通过JSNI和控制台创建cytoscape对象的方式有所不同。 Still, Dev tools lists the console and JSNI method as providing identical objects. 尽管如此,Dev工具仍将控制台和JSNI方法列为提供相同的对象。 How can I update my JSNI code to make it compliant with this check? 如何更新我的JSNI代码以使其符合此检查要求?

Ideally, JSNI should be usable in this case. 理想情况下,在这种情况下,JSNI应该可用。 I am not sure why passing the values in through JSNI causes this if statement to fail when running it through console passes the if statement. 我不确定为什么通过JSNI传递值会导致此if语句在通过控制台运行时失败,而通过if语句。

The problem is that Object isn't quite the same as Object, and checking instanceof almost certainly does a lot more than cytoscape's author thinks it does - isn't JS grand? 问题在于Object与Object不完全相同,检查instanceof几乎可以肯定比cytoscape的作者所认为的要多得多-JS难道不是吗?

The cytoscape.js project's instanceof Object test is not just a test for "is this thing a plain Object rather than an instance of some other type", but actually tests "is this thing an instance of the Object class in my window instance, and not from any other iframe/window". cytoscape.js项目的instanceof Object测试不仅是针对“这是一个普通的Object,还是其他类型的实例”的测试,而是实际上测试“这是我的 Window实例中Object类的实例,并且而不是来自其他任何iframe /窗口”。

GWT's default linker evaluates your code in an iframe to prevent accidentally leaking global variables and confusing JS loaded into the same page, or letting other JS on the same page overwrite or otherwise mess with GWT's code. GWT的默认链接器会在iframe中评估您的代码,以防止意外泄漏全局变量并使加载到同一页面的JS混乱,或使同一页面上的其他JS覆盖或以其他方式干扰GWT的代码。

There are a few ways to fix this, aside from trying to correct cytoscape's code to something a bit less rigid and inflexible. 除了尝试将cytoscape的代码更正为不太僵化和不灵活的方式以外,还有几种方法可以解决此问题。

  • Create instances of Object from the outer page: To do this, you have to directly create objects, rather than using the {...} syntax, which defaults to whatever window you happen to be executing in. Something like this: 从外部页面创建Object的实例:为此,您必须直接创建对象,而不是使用{...}语法,该语法默认为您恰巧在其中执行的任何窗口。
       public static native void cytoscape() /*-{
           var obj = new $wnd.Object();
           obj.container = $wnd.document.getElementById('cy');//can also be simply $doc.getElementById('cy')
           obj.elements = $wnd.glyElements;
           // Note that you may have to repeat this for each of these nested objects, depending
           // on how picky the library is being on otherwise identically structured code...
           obj.style = [ { selector: 'node', style: { 'background-color': '#666', 'label': 'data(id)' } }, 
                   { selector: 'edge', style: { 'width': 3, 'line-color': '#ccc', 'target-arrow-color': '#ccc',
   'target-arrow-shape': 'triangle' } } ];
           obj.layout = { name: 'grid', rows: 1 };
           var cy = $wnd.cy = $wnd.cytoscape(obj);
       }-*/; 
  • Load cytoscape.js into the same iframe as your GWT code executes in. Note that it might not actually work there, and this cause other issues, but you can try this using ScriptInjector to insert the script content into your GWT app instead of referencing it in your .html page directly. 在执行GWT代码的情况下,将cytoscape.js加载到同一iframe中。请注意,它可能在那里实际上不起作用,这会导致其他问题,但是您可以尝试使用ScriptInjector将脚本内容插入GWT应用程序中,而不用引用它直接在您的.html页面中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM