I am attempting to use Dart's package:js to create an interop library for JScrollPane, which is wrapped with jQuery.
Here's what I have so far:
#JS()
library jscrollpane;
import 'dart:html';
import 'package:js/js.dart';
#JS()
#anonymous
abstract class JScrollPaneSettings {
external factory JScrollPaneSettings({bool showArrows});
external bool get showArrows;
external set showArrows(bool value);
}
#JS()
class JScrollPane {
external JScrollPane(Element element, JScrollPaneSettings settings);
}
And here's the error:
Not a valid JS object
STACKTRACE:
#0 JsNative.callConstructor (dart:js:1461)
#1 JScrollPane.JScrollPane (package:portal/base/views/scrollbar/jscrollpane.dart_js_interop_patch.dart:13:30)
And here's the JS library - http://jscrollpane.kelvinluck.com/script/jquery.jscrollpane.js
Element is from dart:html and is not annoted with #anonymous, you should use the dynamic keyword instead.
#JS()
class JScrollPane {
external JScrollPane(dynamic element, JScrollPaneSettings settings);
}
UPDATE
Since it is a jQuery plugin, I don't think you can directly access to the JScrollPane, I have never wrap a jQuery plugin, but if you take the example code of the plugin:
$('.scroll-pane').jScrollPane();
You can try to wrap the $ function
#JS('\$')
external jQuery(query);
#JS()
#anonymous
class JScrollPaneElement {
external jScrollPane();
}
void main() {
JScrollPaneElement scrollPane = jQuery('.scroll-pane') as JScrollPaneElement;
scrollPane.jScrollPane();
}
Related
In my vaadin application I need to implement a fixed header, that changes size depending on the scroll position of the UI.
While there are geters for scroll position in Vaadin 8, there seems to be no functionallity implemented to listen for scroll events. So I tried to implement a JavaScript connector, that just informs the server-side UI, that the user has scrolled, so the server-side UI can then notify the Header as a scrollListener.
So far thats what I planned, but I just can't find out, how to implement my connector in a way that it.
is active after the site got requested by a Client.
is able to call my server-side UI.onScrollEvent() method.
Does anyone know, how the described behavior could be implemented?
Thank you for your help in advance.
After I ran into a few issues with implementaton of a custom widget to achieve, I went for a different approach, using extensions in a vaadin-sense. Here is the truncated code for what I did.
(Vaadin requires the client-side connector code shown later in this post to be in a Widget package. I'm not entirely sure if the server-side component has to be in one too, but for conformity reasons with the usual widget-skeleton I put it into one)
So in the package for the widget:
package my.company.project.scrollUI;
import com.vaadin.server.AbstractExtension;
import com.vaadin.ui.UI;
import my.company.project.scrollUI.client.scrollUI.ScrollUIServerRpc;
public class ScrollUI extends AbstractExtension {
private ScrollUIServerRpc rpc = new ScrollUIServerRpc() {
#Override
public void onScroll() {
//do whatever you need for your implementation
...
}
};
public ScrollUI() {
registerRpc(rpc);
}
public void extend(UI ui) {
super.extend(ui);
}
}
as usual the .gwt.xml file in the package folder, nothing special here:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.5.1//EN" "http://google-web-toolkit.googlecode.com/svn/tags/2.5.1/distro-source/core/src/gwt-module.dtd">
<module>
<inherits name="com.vaadin.DefaultWidgetSet" />
</module>
In the package for the client-side code to be compiled to JavaScript:
package my.company.project.scrollUI.client.scrollUI;
import com.vaadin.shared.communication.ServerRpc;
public Interface ScrollUIServerRpc extends ServerRpc {
public void onScroll();
}
And finally the connector for the extension:
package my.company.project.scrollUI.client.scrollUI;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ServerConnector;
import com.vaadin.client.communication.RpcProxy;
import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.shared.ui.Connect;
#Connect(ScrollUI.class)
public class ScrollUIConnector extends AbstractExtensionConnector {
ScrollUIServerRpc rpc = RpcProxy.create(ScrollUIServerRpc.class, this);
#Override
protected void extend(ServerConnector target) {
final Widget ui = ((ComponentConnector) target).getWidget();
ui.addDomHandler(new ScrollHandler() {
#Override
public void onScroll(ScrollEvent event) {
rpc.onScroll();
}
}, ScrollEvent.getType());
}
}
Now don't forget to compile the Widgetset and everything is good to go to be used for your actual UI like all other vaadin extensions:
public class MyUI extends com.vaadin.ui.UI {
#Override
protected void init(VaadinRequest vaadinRequest) {
ScrollUI scrollUI = new ScrollUI();
scrollUI.extend(this);
//everything else that needs to be done
...
}
//everything else that Needs to be done
...
}
I hope this was helpfull for anyone with a similar issue.
I have done this once few years ago by extending the layout component that wrapped the part of UI where I needed this. In GWT there is gwtproject.org/javadoc/latest/com/google/gwt/event/dom/client/… which can be used in DOM handler. So yes, GWT provides suitable client side event. I then used RPC call to server side, where I triggered the corresponding server side event, which I could listen in other parts of the app. The code is not public, but there is LazyLayout add-on that has similar type of implementation, which you could check as reference for your implementation.
https://github.com/alump/LazyLayouts/blob/master/lazylayouts-addon/src/main/java/org/vaadin/alump/lazylayouts/client/LazyVerticalLayoutConnector.java
Dart Code
import 'dart:html' as html;
import 'dart:js' as js;
import 'package:js/js.dart';
void main() {
var data = new AddLocationData(locationName: "Location1", locationPath: "ThisFolder");
var func = () => data;
html.window.console.log(func);
html.window.console.log(func());
}
#JS("")
#anonymous
class AddLocationData {
external String get locationName;
external String get locationPath;
external factory AddLocationData({String locationName, String locationPath});
}
You would assume that func will be a js function but its not. Its type/name is main_closure. See the screenshot
So the first two lines were printed from Dart code then I used Chrome Inspect Element window and right clicked on main_closure' and selected "Store as global variable" which then printedtemp1` and then I used it to display some information about the generated code.
So it is clear Dart returned an object and not a js function and so is the reason of asking this question.
So I want temp1 to be a function instead of temp1.call$0 so that I can get the data by calling temp1() and not temp1.call$0().
See js package doc:
Passing functions to JavaScript.
If you are passing a Dart function to a JavaScript API, you must wrap it using allowInterop or allowInteropCaptureThis.
The dart version of contentWindow does not have a print method.
If printing directly from dart is not possible, how could I use regular javascript to print an iframe using js interop?
What dart:js this should work:
import 'dart:js';
...
final iframe = querySelector('iframe') as IFrameElement;
(new JsObject.fromBrowserObject(iframe)['contentWindow']['print'] as JsFunction).apply(<dynamic>[]);
With package:js
#JS()
library maps;
#JS('document.querySelector')
external JsWindow query(String selector);
#JS("Window")
class JsWindow {
external JsWindow get contentWindow;
external void print();
}
query('iframe').contentWindow.print();
I've been playing around a bit with the new js interop of dart. So far everything was very straight-forward. But one thing I'm not sure about is how to deal with js stuff like this:
MathJax.Hub.Config({
showProcessingMessages: false,
showMathMenu: false
.. many other different options
});
I can translate the MathJax.Hub.Config part:
#JS('MathJax') external MathJaxClass get MathJax;
class MathJaxClass {
external HubClass get Hub;
}
#JS('MathJax.Hub')
class HubClass {
external void Config(options);
}
But now I would like to have the options argument of Config function to be a Dart Object. I'm not sure how to do this. The only way, I can get something working is with a Map:
MathJax.Hub.Config(new JsObject.jsify({
'showProcessingMessages': false,
'showMathMenu': false
}));
But this is surely not ideal. Any ideas?
The syntax is as follows:
#anonymous
#JS()
class Config {
external bool get showProcessingMessages;
external bool get showMathMenu;
external factory Config({bool showProcessingMessages, bool showMathMenu});
}
Here the Config name is not matching any javascript name, so you can name it whatever you want. You can then call it like this:
MathJax.Hub.Config(new Config(
showProcessingMessages: false,
showMathMenu: false
));
The object passed to the js function, will be a regular javascript object:
Since a recent update the #anonymous annotation is used to create JS objects from Dart classes instead of a factory constructor.
#JS()
#anonymous
class Config {
external bool get showProcessingMessages;
external set showProcessingMessages(bool value);
external bool get showMathMenu;
external set showMathMenu(bool value);
}
MathJax.Hub.Config(new Config()
..showProcessingMessages= false
..showMathMenu = false
}));
import "dart:html";
class ParentClass {
}
import "ParentClass";
class ChildClass extends ParentClass {
int main() {
Element e = querySelector()
}
}
Element & querySelector in ChildClass display as issues (Undefined Element & querySelector)
Is it not possible to import packages from ParentClass?
An import's scope is only the importing library.
If you import dart:html in the ParentClass library file and import the ParentClass library in another file, then the other file does not see the dart:html declarations.
There is two ways to handle that:
Preferably, just import dart:html in the other library too.
Export dart:html from the ParentClass library: add export "dart:html"; next to import "dart:html";. That way the declarations of dart:html will be available to any library importing ParentClass.