Bladeren bron

Update V7 Docs community articles (#10637)

tags/7.7.14
KatriHaapalinna 6 jaren geleden
bovenliggende
commit
e8469aed4a
30 gewijzigde bestanden met toevoegingen van 3246 en 83 verwijderingen
  1. 206
    0
      documentation/articles/AccessControlForViews.asciidoc
  2. 2
    2
      documentation/articles/ConfiguringGridColumnWidths.asciidoc
  3. 146
    0
      documentation/articles/CreatingABookmarkableApplicationWithBackButtonSupport.asciidoc
  4. 98
    0
      documentation/articles/CreatingAComponentExtension.asciidoc
  5. 146
    0
      documentation/articles/CreatingASimpleComponent.asciidoc
  6. 249
    0
      documentation/articles/CreatingASimpleComponentContainer.asciidoc
  7. 201
    0
      documentation/articles/CreatingAThemeUsingSass.asciidoc
  8. 178
    0
      documentation/articles/CreatingAUIExtension.asciidoc
  9. 191
    0
      documentation/articles/CustomizingComponentThemeWithSass.asciidoc
  10. 120
    0
      documentation/articles/CustomizingTheStartupPageInAnApplication.asciidoc
  11. 140
    0
      documentation/articles/ExposingServerSideAPIToJavaScript.asciidoc
  12. 2
    2
      documentation/articles/FormattingDataInGrid.asciidoc
  13. 116
    0
      documentation/articles/IntegratingAJavaScriptComponent.asciidoc
  14. 96
    0
      documentation/articles/IntegratingAJavaScriptLibraryAsAnExtension.asciidoc
  15. 62
    59
      documentation/articles/MigratingFromVaadin6ToVaadin7.asciidoc
  16. 3
    3
      documentation/articles/MigratingFromVaadin7.0ToVaadin7.1.asciidoc
  17. 193
    0
      documentation/articles/OptimizingTheWidgetSet.asciidoc
  18. 145
    0
      documentation/articles/SendingEventsFromTheClientToTheServerUsingRPC.asciidoc
  19. 2
    2
      documentation/articles/ShowingExtraDataForGridRows.asciidoc
  20. 10
    9
      documentation/articles/SimplifiedRPCusingJavaScript.asciidoc
  21. 61
    0
      documentation/articles/UsingAJavaScriptLibraryOrAStyleSheetInAnAddOn.asciidoc
  22. 59
    0
      documentation/articles/UsingBeanValidationToValidateInput.asciidoc
  23. 2
    1
      documentation/articles/UsingGridWithInlineData.asciidoc
  24. 118
    0
      documentation/articles/UsingParametersWithViews.asciidoc
  25. 114
    0
      documentation/articles/UsingRPCFromJavaScript.asciidoc
  26. 154
    0
      documentation/articles/UsingRPCToSendEventsToTheClient.asciidoc
  27. 1
    1
      documentation/articles/Vaadin7HierarchicalContainerAndTreeComponentExampleWithLiferayOrganizationService.asciidoc
  28. 226
    0
      documentation/articles/ViewChangeConfirmations.asciidoc
  29. 178
    0
      documentation/articles/WidgetStylingUsingOnlyCSS.asciidoc
  30. 27
    4
      documentation/articles/contents.asciidoc

+ 206
- 0
documentation/articles/AccessControlForViews.asciidoc Bestand weergeven

@@ -0,0 +1,206 @@
---
title: Access Control For Views
order: 46
layout: page
---
[[access-control-for-views]]
Access control for views
------------------------
The Navigator API provides a simple mechanism to allow or disallow
navigating to a View. Before a View is shown, each ViewChangeListener
that is registered with the Navigator is given the opportunity to veto
the View change.
One can also make the View itself trigger a navigation to another View
in navigateTo(), but let's take a look at the more flexible
beforeViewChange() and afterViewChange(), that exists specifically for
this purpose.
First, let's continue from previous examples and create a MessageView
for secret messages:
[source,java]
....
import com.vaadin.navigator.View;
import com.vaadin.ui.Label;
public class SecretView extends MessageView implements View {
public static final String NAME = "secret";
public SecretView() {
setCaption("Private messages");
((Layout) getContent()).addComponent(new Label("Some private stuff."));
}
}
....
As you can see, there is absolutely nothing special going on here, we
just customize the View enough to be able to distinguish from the
regular MessageView.
Next, we'll register this new View with the Navigator, exactly as
before. At this point our SecretView is not secret at all, but let's fix
that by adding a ViewChangeListener to the Navigator:
[source,java]
....
navigator.addViewChangeListener(new ViewChangeListener() {
@Override
public boolean beforeViewChange(ViewChangeEvent event) {
if (event.getNewView() instanceof SecretView &&
((NavigationtestUI)UI.getCurrent()).getLoggedInUser() == null) {
Notification.show("Permission denied", Type.ERROR_MESSAGE);
return false;
} else {
return true;
}
}
@Override
public void afterViewChange(ViewChangeEvent event) {
}
});
....
So if we're on our way to the SecretView, but not logged in
(getLoggedInUser() == null), the View change is cancelled. Quite simple
rules in our case, but you could check anything - most probably you'll
want to call a helper method that checks the user for permission.
Let's go ahead and add some links to the MainView again, so that we
don't have to muck with the address-bar to try it out:
[source,java]
....
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.server.ExternalResource;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Link;
import com.vaadin.ui.Panel;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
public class MainView extends Panel implements View {
public static final String NAME = "";
public MainView() {
VerticalLayout layout = new VerticalLayout();
Link lnk = new Link("Count", new ExternalResource("#!" + CountView.NAME));
layout.addComponent(lnk);
lnk = new Link("Message: Hello", new ExternalResource("#!"
+ MessageView.NAME + "/Hello"));
layout.addComponent(lnk);
lnk = new Link("Message: Bye", new ExternalResource("#!"
+ MessageView.NAME + "/Bye/Goodbye"));
layout.addComponent(lnk);
lnk = new Link("Private message: Secret", new ExternalResource("#!"
+ SecretView.NAME + "/Secret"));
layout.addComponent(lnk);
lnk = new Link("Private message: Topsecret", new ExternalResource("#!"
+ SecretView.NAME + "/Topsecret"));
layout.addComponent(lnk);
// login/logout toggle so we can test this
Button logInOut = new Button("Toggle login",
new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
Object user = ((NavigationtestUI)UI.getCurrent()).getLoggedInUser();
((NavigationtestUI)UI.getCurrent()).setLoggedInUser(
user == null ? "Smee" : null);
}
});
layout.addComponent(logInOut);
setContent(layout);
}
@Override
public void enter(ViewChangeEvent event) {
}
}
....
Instead of just showing a notification and leaving the user wondering,
we should obviously allow the user to log in and continue. We'll do just
that in the separate tutorial about Handling login, but for now we just
add a button that toggles our logged in/out state.
Meanwhile, here is the the full source for the UI so far:
[source,java]
....
import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Notification.Type;
import com.vaadin.ui.UI;
public class NavigationtestUI extends UI {
Navigator navigator;
String loggedInUser;
@Override
public void init(VaadinRequest request) {
// Create Navigator, make it control the ViewDisplay
navigator = new Navigator(this, this);
// Add some Views
navigator.addView(MainView.NAME, new MainView()); // no fragment
// #!count will be a new instance each time we navigate to it, counts:
navigator.addView(CountView.NAME, CountView.class);
// #!message adds a label with whatever it receives as a parameter
navigator.addView(MessageView.NAME, new MessageView());
// #!secret works as #!message, but you need to be logged in
navigator.addView(SecretView.NAME, new SecretView());
// we'll handle permissions with a listener here, you could also do
// that in the View itself.
navigator.addViewChangeListener(new ViewChangeListener() {
@Override
public boolean beforeViewChange(ViewChangeEvent event) {
if (event.getNewView() instanceof SecretView
&& ((NavigationtestUI)UI.getCurrent()).getLoggedInUser() == null) {
Notification.show("Permission denied", Type.ERROR_MESSAGE);
return false;
} else {
return true;
}
}
@Override
public void afterViewChange(ViewChangeEvent event) {
System.out.println("After view change");
}
});
}
public String getLoggedInUser(){
return loggedInUser;
}
public void setLoggedInUser(String user){
loggedInUser = user;
}
}
....

+ 2
- 2
documentation/articles/ConfiguringGridColumnWidths.asciidoc Bestand weergeven

@@ -9,8 +9,8 @@ layout: page

To try out how the widths of Grid columns work in different situations,
we'll use the same base implementation as in the
link:UsingGridWithAContainer.asciidoc[Using Grid with a Container]
example.
<<UsingGridWithAContainer#using-grid-with-a-container,
Using Grid with a Container>> example.

Grid does by default check the widths of all cells on the first pageful
of data and allocate column widths based on that. If there's room to

+ 146
- 0
documentation/articles/CreatingABookmarkableApplicationWithBackButtonSupport.asciidoc Bestand weergeven

@@ -0,0 +1,146 @@
---
title: Creating A Bookmarkable Application With Back Button Support
order: 55
layout: page
---
[[creating-a-bookmarkable-application-with-back-button-support]]
Creating a bookmarkable application with back button support
------------------------------------------------------------
Vaadin 7 comes with a new set of APIs to aid creation of navigation
within your application. The main concepts are *Navigator* and *View*,
and using these you can easily create an application that supports the
standard browser methods for navigation; bookmarking, history, back- and
forward navigation using browser buttons. This is (usually) done using
browser "fragments" (the stuff after the #-character in the URI).
At the same time, the API provides a natural way of partitioning your
application into views - something most applications did previously
anyway, but previously without framework 'guidance'.
Let's start by making a View that counts the times it has been created.
This is a simple example, but will later shed some light on when Views
are created, but let's not worry about that just yet:
[source,java]
....
import com.vaadin.navigator.View;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
public class CountView extends Panel implements View {
public static final String NAME = "count";
private static int count = 1;
public CountView() {
setContent(new Label("Created: " + count++));
}
public void enter(ViewChangeEvent event) {
}
}
....
We'll extend Panel as a convenient base, and add a Label to that in the
constructor, updating the static count. The _enter()_ -method comes from
View, and is called when our View is activated, but we'll do nothing
about that in our simplistic View.
Note the _static final NAME_: we'll use it instead of a 'magic' string
when we register the View with the Navigator later. Feel free to use any
method you like to keep track of your View-names (e.g Enum, simpleName
of the View's class, and so on…)
In order to do any navigating, we'll need at least two views, so let's
create a main view that has a link to the counting view we just created.
[source,java]
....
import com.vaadin.navigator.View;
import com.vaadin.server.ExternalResource;
import com.vaadin.ui.Link;
import com.vaadin.ui.Panel;
public class MainView extends Panel implements View {
public static final String NAME = "";
public MainView() {
Link lnk = new Link("Count", new ExternalResource("#!"
+ CountView.NAME));
setContent(lnk);
}
public void enter(ViewChangeEvent event) {
}
}
....
Note the empty string used as _NAME_. This is because we want this to be
our main ("home") View, displayed before any navigation is done.
In this example we use a Link and let the browser do the navigating. We
could just as easily use a Button and tell the Navigator where we want
to go when the button's ClickListener is invoked. Note that we're using
_CountView.NAME_, and what we're actually doing is using the "fragment"
part of the application URI to indicate the view. The resulting URI will
look something like http://.../application#!count .
Ok, one last thing: we need to set up a UI with a Navigator, and
register our views:
[source,java]
....
import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.Navigator.SimpleViewDisplay;
import com.vaadin.server.Page;
import com.vaadin.server.WrappedRequest;
import com.vaadin.ui.UI;
public class NavigationtestUI extends UI {
@Override
public void init(VaadinRequest request) {
// Create Navigator, use the UI content layout to display the views
Navigator navigator = new Navigator(this, this);
// Add some Views
navigator.addView(MainView.NAME, new MainView()); // no fragment
// #!count will be a new instance each time we navigate to it, counts:
navigator.addView(CountView.NAME, CountView.class);
// The Navigator attached to the UI will automatically navigate to the initial fragment once
// the UI has been initialized.
}
}
....
There are advanced ways to use the Navigator API, and there are simple
ways. Most applications will do fine with the simple ways, and the
Navigator constructor we used is written that in mind. It simply takes
any ComponentContainer, assumes that all our Views are also Components,
and on a view change sets the given view as the ComponentContainer's
only child. Internally, it uses a _ViewDisplay_ subclass called
ComponentContainerViewDisplay to do this. If we had more advanced
requirements, we could write our own ViewDisplay subclass to show our
views in whatever fashion we'd like.
The Navigator finds out about URI fragment changes through the Page, and
directs the ViewDisplay accordingly. We register our Views using
_addView()_ so that the Navigator knows how to connect fragments with
Views. Again notice how we use the static NAME instead of
_addView("name", view)_ - but feel free to use other approaches.
In order to illustrate how the two differ, we register an _instance_ of
the MainView, but _CountView.class_. As a result, the MainView is
created once, when the UI is created, and lives as long as the UI lives.
On the other hand, a new CountView instance will be created each time we
navigate to it (but no earlier). You can try navigating back-and-forth
and see how the count is updated - try registering it using new
CountView() instead…
It's also good to keep in mind that a new UI is created each time you
press reload in the browser, unless you use the @PreserveOnRefresh
annotation on the UI.

+ 98
- 0
documentation/articles/CreatingAComponentExtension.asciidoc Bestand weergeven

@@ -0,0 +1,98 @@
---
title: Creating A Component Extension
order: 51
layout: page
---
[[creating-a-component-extension]]
Creating a component extension
------------------------------
In this tutorial we create a simple extension that can be attached to a
`PasswordField`, displaying a floating notification if the user's Caps
Lock seems to be enabled. We assume the reader is already familiar with
the <<CreatingAUIExtension#creating-a-ui-extension,Creating a UI extension>>
tutorial.
This extension has almost no server-side functionality; the whole Extension
class is as follows:
[source,java]
....
public class CapsLockWarning extends AbstractExtension {
protected CapsLockWarning(PasswordField field) {
// Non-public constructor to discourage direct instantiation
extend(field);
}
public static CapsLockWarning warnFor(PasswordField field) {
return new CapsLockWarning(field);
}
}
....
When there's nothing to configure for the extension, users just want to
enable it for some component and be done with it. By defining a static
factory method, the user only needs to do something like
`CapsLockWarning.warnFor(myPasswordField);` to make `myPasswordField`
get the new functionality.
The client side is not overly complicated, either. We override the
`extend` method, called by the framework when the client-side extension
connector is attached to its target the client-side counterpart of the
connector to which the server-side extension instance is attached in
this case, `PasswordFieldConnector`.
We add a key press handler to the password widget, checking if the input
looks like Caps Lock might be enabled. The Caps Lock state cannot be
directly queried in GWT/JavaScript, so we use a trick: check if either
* the shift key was not held but the entered character was uppercase, or
* the shift key _was_ held but the entered character was lowercase.
If this is the case, we show a warning in the form of a floating widget
(`VOverlay`). This demonstrates how an extension may make use of UI
elements even though it is not a part of the layout hierarchy. A
frequent use case for extensions is showing different types of floating
overlay elements that are temporary in character.
[source,java]
....
@Connect(CapsLockWarning.class)
public class CapsLockWarningConnector extends AbstractExtensionConnector {
@Override
protected void extend(ServerConnector target) {
final Widget passwordWidget = ((ComponentConnector) target).getWidget();
final VOverlay warning = new VOverlay();
warning.setOwner(passwordWidget);
warning.add(new HTML("Caps Lock is enabled!"));
passwordWidget.addDomHandler(new KeyPressHandler() {
@Override
public void onKeyPress(KeyPressEvent event) {
if (isEnabled() && isCapsLockOn(event)) {
warning.showRelativeTo(passwordWidget);
} else {
warning.hide();
}
}
}, KeyPressEvent.getType());
}
private boolean isCapsLockOn(KeyPressEvent e) {
return e.isShiftKeyDown() ^ Character.isUpperCase(e.getCharCode());
}
}
....
To use the Caps Lock warning, compile your widgetset and extend a
PasswordField with something like this
[source,java]
....
PasswordField field = new PasswordField("Enter your password");
CapsLockWarning.warnFor(field);
addComponent(field);
....

+ 146
- 0
documentation/articles/CreatingASimpleComponent.asciidoc Bestand weergeven

@@ -0,0 +1,146 @@
---
title: Creating A Simple Component
order: 48
layout: page
---
[[creating-a-simple-component]]
Creating a simple component
---------------------------
To make a component with a new client-side widget (as opposed to making
a server-side composite), you will need to make three things: the
_server-side component_ you'll actually use in your application (let's
call it *MyComponent*), the corresponding _client-side (GWT) widget_
that will render your component in the browser (*MyComponentWidget*) and
a _Connector_ that handles the communication between the two
(*MyComponentConnector*). (Note that although MyComponentWidget could in
principle be a Connector as well, in practice it's a good idea to
separate the two.)
At this point the basic MyComponent has no functionality except
inherited basic component features (we'll add functionality in following
articles):
[source,java]
....
package com.example.mycomponent;
import com.vaadin.ui.AbstractComponent;
public class MyComponent extends AbstractComponent {
}
....
The main thing to notice here is that it inherits `AbstractComponent`,
which is the most common case (unless it will contain other components,
see separate article about component containers). The component will
automatically have the basic component features, such as size and
caption.
At this point our basic client-side widget will just statically render
some text:
[source,java]
....
package com.example.mycomponent.client;
import com.google.gwt.user.client.ui.Label;
public class MyComponentWidget extends Label {
public static final String CLASSNAME = "mycomponent";
public MyComponentWidget() {
setText("This is MyComponent");
setStyleName(CLASSNAME);
}
}
....
Notice that this is actually a plain GWT widget that can be used as any
other GWT widget. It's a good idea to set a style name from the start,
so that the component can be styled.
Now all we have to do is connect the component to the widget using a
Connector:
[source,java]
....
package com.example.mycomponent.client;
import com.example.mycomponent.MyComponent;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.Connect;
@Connect(com.example.mycomponent.MyComponent.class)
public class MyComponentConnector extends AbstractComponentConnector {
@Override
protected Widget createWidget() {
return GWT.create(MyComponentWidget.class);
}
}
....
The *crucial Connect annotation* is what actually tells the framework
what is connected where - do this first, since it's easy to forget.
In `createWidget()` use `GWT.create()` instead of `new` whenever possible,
since it allows for some flexibility that might come in handy later on.
Though this is optional, you might also want to override getWidget() so
that you can narrow it's return type from Widget to your actual
implementation class:
[source,java]
....
@Override
public MyComponentWidget getWidget() {
return (MyComponentWidget) super.getWidget();
}
....
The package structure usually looks something like this:
* com.example.mycomponent
** MyComponent.java
** MyComponentWidgetset.gwt.xml
* com.example.mycomponent.client
** MyComponentConnector.java
** MyComponentWidget.java
Finally, compile the widgetset, and *make sure the widgetset is defined with the @Widgetset annotation in the UI class*:
[source,java]
....
@Widgetset("com.example.mycomponent.MyComponentWidgetset")
class MyUI extends UI {
....
If you are using web.xml, it should contain the widgetset parameter:
[source,xml]
....
<servlet>
<servlet-name>My Vaadin App</servlet-name>
<servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
<init-param>
<description>Vaadin UI</description>
<param-name>UI</param-name>
<param-value>com.example.myexampleproject.MyApplicationUI</param-value>
</init-param>
<init-param>
<param-name>widgetset</param-name>
<param-value>com.example.mycomponent.MyComponentWidgetset</param-value>
</init-param>
</servlet>
....
Add MyComponent to your application, and it should render a label saying
"This is MyComponent".
Next have a look at the articles covering shared state and RPC, to learn
how to add more functionality to the component.

+ 249
- 0
documentation/articles/CreatingASimpleComponentContainer.asciidoc Bestand weergeven

@@ -0,0 +1,249 @@
---
title: Creating A Simple Component Container
order: 49
layout: page
---
[[creating-a-simple-component-container]]
Creating a simple component container
-------------------------------------
Components in Vaadin can be roughly split into two groups, `Component`{empty}s
and `ComponentContainer`{empty}s. ComponentContainers are Components in
themselves which can also contain other components. If you are about to
implement a component that contains other components, then you'll get a
headstart by extending Vaadin's `ComponentContainer`. The biggest feature
is in tranferring the list of server side components from your component
to the client. Here's how you do it.
[[server-side]]
Server Side
^^^^^^^^^^^
To start of we implement our server side component. For this we extend
the ready made abstract implementation `AbstractComponentContainer`. This
requires us to implement `addComponent(Component)`,
`removeComponent(Component)`, `replaceComponent(Component, Component)`,
`getComponentCount` and `getComponentIterator()`.
[source,java]
....
package com.example.widgetcontainer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.vaadin.ui.AbstractComponentContainer;
import com.vaadin.ui.Component;
public class WidgetContainer extends AbstractComponentContainer {
List<Component> children = new ArrayList<Component>();
@Override
public void addComponent(Component c) {
children.add(c);
super.addComponent(c);
markAsDirty();
}
@Override
public void removeComponent(Component c) {
children.remove(c);
super.removeComponent(c);
markAsDirty();
}
public void replaceComponent(Component oldComponent, Component newComponent) {
int index = children.indexOf(oldComponent);
if (index != -1) {
children.remove(index);
children.add(index, newComponent);
fireComponentDetachEvent(oldComponent);
fireComponentAttachEvent(newComponent);
markAsDirty();
}
}
public int getComponentCount() {
return children.size();
}
public Iterator<Component> iterator() {
return children.iterator();
}
}
....
Add, remove and replace are quite straightforward. In the class we
upkeep a list of children internally, and these three methods modify
them. Add and remove have ready made methods in the super class for
notifying all event handlers that the children have changed and because
of that we should make calls to the super methods after we have updated
the list. In `replaceComponent` we have to call
`fireComponentDetachEvent(Component)` and
`fireComponentAttachEvent(Component)` to manually trigger these events. In
all three methods we should also call `markAsDirty` as a last step to
notify the client side that the children have changed.
The methods `getComponentCount()` and `iterator()` takes care of providing
the required information that we need to the client side. Here they are
simple delegate methods to the List's `size()` and `iterator()`.
[[client-side]]
Client Side
^^^^^^^^^^^
Next up, we want to set up a standard GWT widget which will be our
component container's client side widget. GWT in itself has a bunch of
component containers in it. In GWT, these are called Panels. For this
case I will start with a `VerticalPanel`. It is roughly the same as
`VerticalLayout` in Vaadin. Down the road you want to edit this file to
add features or even extend Widget to create a complete custom widget.
For now extending `VerticalPanel` is enough and we'll use that as-is.
[source,java]
....
package com.example.widgetcontainer.client.ui;
import com.google.gwt.user.client.ui.VerticalPanel;
public class VWidgetContainer extends VerticalPanel {
public static final String CLASSNAME = "v-widgetcontainer";
public VWidgetContainer() {
setStyleName(CLASSNAME);
}
}
....
[[connector]]
Connector
^^^^^^^^^
Your widget's Connector will transfer the components from the server
side as child widgets to our widget. The connector will feed the
children to the panel trough it's standard API, namely `add(Widget)`,
`remove(Widget)` and `clear();`
Instead of going the standard route of extending
`AbstractComponentConnector` as your connector, here we can take use of
Vaadin's internal features and extend
`AbstractComponentContainerConnector`. Additionally to implementing the
`getWidget()` -method from `AbstractComponentConnector`, we also have to
supply the class with an implementation to a method called
`updateCaption(ComponentConnector)`. This method is there if we want the
container to take care of the captions for all the components. We don't
need to take care of these captions in this example so we can leave the
implementation empty.
The real benefit of extending `AbstractComponentContainerConnector` is
that we can now extend a method called
`onConnectorHierarchyChange(ConnectorHierarchyChangeEvent)`. This method
will be called every time that the server side calls `markAsDirty()` if
the component hierarchy has been changed. From within it, we can call on
`getChildComponents` to get a list of all the child components, and
populate our widget with those.
[source,java]
....
package com.example.widgetcontainer.client.ui;
import java.util.List;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.Widget;
import com.example.widgetcontainer.WidgetContainer;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ConnectorHierarchyChangeEvent;
import com.vaadin.client.ui.AbstractComponentContainerConnector;
import com.vaadin.client.ui.Connect;
@Connect(WidgetContainer.class)
public class WidgetContainerConnector extends
AbstractComponentContainerConnector {
@Override
public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) {
List<ComponentConnector> children = getChildComponents();
VWidgetContainer widget = getWidget();
widget.clear();
for (ComponentConnector connector : children) {
widget.add(connector.getWidget());
}
}
@Override
public VWidgetContainer getWidget() {
return (VWidgetContainer) super.getWidget();
}
public void updateCaption(ComponentConnector connector) {
}
}
....
This implementation removes all the component's in the widget and adds
all that are returned from `getChildComponents`. An obvious optimization
to these is to compare what is already in the widget and only
add/remove/move those widgets that have changed.
[[example-usage]]
Example Usage
^^^^^^^^^^^^^
Nothing left but to use the component! Compile the widgetset and check
that the widgetset is defined with the @WidgetSet annotation in the UI class.
Here is a little stand-alone application that uses this component:
[source,java]
....
package com.example.widgetcontainer;
import java.util.Random;
import com.vaadin.annotations.Widgetset;
import com.vaadin.terminal.WrappedRequest;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
@Widgetset("com.example.widgetcontainer.Widgetset")
public class WidgetcontainerUI extends UI {
@Override
public void init(VaadinRequest request) {
VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
Label label = new Label("Hello Vaadin user");
layout.addComponent(label);
final WidgetContainer widgetContainer = new WidgetContainer();
layout.addComponent(widgetContainer);
widgetContainer.addComponent(new Label(
"Click the button to add components to the WidgetContainer."));
Button button = new Button("Add more components", new ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
Random randomGenerator = new Random();
int random = randomGenerator.nextInt(3);
Component component;
if (random % 3 == 0) {
component = new Label("A new label");
} else if (random % 3 == 1) {
component = new Button("A button!");
} else {
component = new CheckBox("A textfield");
}
widgetContainer.addComponent(component);
}
});
layout.addComponent(button);
}
}
....

+ 201
- 0
documentation/articles/CreatingAThemeUsingSass.asciidoc Bestand weergeven

@@ -0,0 +1,201 @@
---
title: Creating A Theme Using SASS
order: 53
layout: page
---
[[creating-a-theme-using-sass]]
Creating a theme using SASS
---------------------------
Vaadin 7 comes with built in support for Sass, which can be thought of
as a preprocessor for CSS. From the Sass homepage:
_Sass makes CSS fun again. Sass is an extension of CSS3, adding nested
rules, variables, mixins, selector inheritance, and more._
Sass looks like CSS with some added features, and is compiled into CSS
before being sent to the browser. The compilation is either done
beforehand, or (during development) on-the-fly by the servlet.
In Vaadin 7 you can make use of Sass in any of your CSS, and as usual
there are more than one way to arrange this. The recommended way if you
do not have a specific reason not to do so, is to compile your theme
into one CSS file (that is: without any CSS @include), but we'll start
with the getting-your-feet-wet approach that looks exactly as
before.It’s worth noting that you can continue to use CSS without Sass
just as before, if you prefer.
[[getting-your-feet-wet]]
Getting your feet wet
^^^^^^^^^^^^^^^^^^^^^
In Vaadin 7 you set the theme in use by specifying the `@Theme` annotation
on your UI, e.g `@Theme(“themename”)`. Ignoring Sass for a second, you
would then create a `mytheme/styles.css` that typically `@import` the
Reindeer theme (in case you forgot, your theme should be located in
`WebContent/VAADIN/themes/<themename>/styles.css`). You can start using
Sass with this approach, by renaming your `styles.css` to `styles.scss` and
importing `legacy-styles.css` instead of `styles.css` - the resulting CSS
will be exactly as the same as before, BUT now you're free to use Sass
in your theme:
[source,scss]
....
@import url(../reindeer/legacy-styles.css);
$color : green;
.v-button-caption {
color: $color;
}
....
Here we just define a Sass variable to use as color for button captions.
*NOTE* that this way (using legacy-styles) you still lose one important
new feature: you can't have multiple themes on the same page when using
the legacy-styles.css -approach. To gain this feature, which is crucial
if you intend to run multiple applications with different themes
embedded in the same page (e.g portals), you must use Sass.
[[compiling]]
Compiling
^^^^^^^^^
Provided you’re in development mode (not production), the scss will
automatically be translated into CSS. You can also compile the scss
manually (and MUST do so for production). To do this you should run
`com.vaadin.sass.SassCompiler` with the Vaadin jars on the classpath and
give it your scss file and output file as arguments. If you have the
jars readily available, you could do something like this in the command
line:
[source,bash]
....
> java -cp '../../../WEB-INF/lib/*' com.vaadin.sass.SassCompiler styles.scss styles.css
....
Another way would be to save the auto-compiled styles.css from the
browser.
Support has been added to the Eclipse plugin through the _Compile Vaadin
Theme_ button .
NOTE that if you're using Ivy (the default if you're using the Eclipse
plugin), you must make sure to get the appropriate dependencies on your
classpath some other way (since they are not present in `WEB-INF/lib`). In
Eclipse, use the Run -dialog to inherit the classpath from your project.
You'll notice that the resulting theme still uses `@import` to 'extend'
the Reindeer theme:
[source,scss]
....
@import url(../reindeer/legacy-styles.css);
....
This approach is an easy way to get started with Sass, but will cause
two requests (one for our theme, one for Reindeer). Let’s have a look at
the recommended approach next.
[[going-deeper]]
Going deeper
^^^^^^^^^^^^
Instead of using CSS `@import` to base your application theme on, you can
(and probably should) use Sass `@import` to make a monolithic theme (one
CSS file, one request when using the application). Just `@import reindeer.scss`, and `@include` it:
[source,scss]
....
// mytheme.scss
@import "../reindeer/reindeer.scss";
.mytheme {
@include reindeer;
$color : yellow;
.v-button-caption {
color: $color;
}
}
....
This produces a styles.css that contains all the styles for Reindeer as
well as your custom styles (note that this makes your final CSS quite
big to scroll trough, so you might not want to do this when just
learning the Sass syntax). There is no `@import` in the compiled CSS, so
it will not cause additional requests. Additionally, due to the way
Vaadin Sass is structured, this opens up for many possibilities to
customize, mix-and-match themes, and leave unused stuff out.
One important thing to notice, is that we wrapped everything in
`.themename {}`, in this case `.mytheme {}`. This is the magic sauce that
makes it possible to have multiple themes on one page. _It is crucial
that the name matches your themename, or your styles will not be
applied._
Some of the nice features you get with Sass include variables, selector
nesting, mixins (optionally with paramaters), selector inheritance. For
more information of what you can do with Sass, you should refer to the
official documentation at http://sass-lang.com
Please note that the Vaadin Sass compiler only supports the “SCSS”,
which is the “new main syntax” (the original Sass also supports another,
older syntax).The Vaadin version aims to be completely compatible,
though initially there will be some limitations (and actually some added
functionality). Please let us know if you find something is not working
as expected.
[[one-more-thing-recommended-structure]]
One more thing: Recommended structure
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In Vaadin 7, all Vaadin core themes are using Sass. The
_reindeer/styles.css_ we included first, is the compiled Reindeer theme,
including the stuff from the Base theme that Reindeer extends. The Sass
for the Reindeer theme is in _reindeer/reindeer.scss_, and contains one
big mixin that will include the whole theme, unless you specifically
tell it to leave out some parts. The themes are further divided into
smaller parts, that can be left out, or separately included and renamed
- providing a powerful way to customize and mix-and-match themes.
*It is recommended* that you go ahead an divide your own theme into at
least two files as well: *styles.scss* and *themename.scss* (where
'themename' is the name of your theme). This is will make your theme
extendable, and also has the nice benefit that file you usually edit is
uniquely named (themename.scss) instead of a generic styles.scss that
you might have many of.
For a theme named 'mytheme', this would look as follows:
`mytheme/styles.scss:`
[source,scss]
....
@import "mytheme.scss";
.mytheme {
@include mytheme;
}
....
`mytheme/mytheme.scss`:
[source,scss]
....
@import "../reindeer/reindeer.scss";
@mixin mytheme {
// your styles go here
@include reindeer;
}
....
This is the exact structure Vaadin core themes are using, and the way
the Eclipse plugin will set things up for you (not yet in beta 10).
Of course, you're still free to arrange your theme in another way if you
prefer.
Upcoming tutorials will address specific use-cases!

+ 178
- 0
documentation/articles/CreatingAUIExtension.asciidoc Bestand weergeven

@@ -0,0 +1,178 @@
---
title: Creating A UI Extension
order: 50
layout: page
---
[[creating-a-ui-extension]]
Creating a UI extension
-----------------------
An *Extension* is an entity that is not a full-fledged UI component, but
is instead used to enhance or extend the functionality of an existing
component (or connector, more generally.) Unlike components, extensions
cannot be detached and reattached once they are attached to their
target.
Extensions usually consist of a pair of `Connector`{empty}s like components do.
Hence, they can use the regular shared state and RPC mechanisms to
communicate between the client and the server. Extensions may or may not
have a UI. They can create and display widgets on the client side, but
are not part of the regular layout hierarchy.
We will rewrite the
https://vaadin.com/directory/component/refresher[Refresher] add-on as an
extension. The Refresher causes the client to "ping" the server at
regular intervals, allowing the server to keep the client up-to-date if
the application state is changed eg. by a background thread (because of
the way Vaadin works, the server cannot itself initiate communication.)
We start by writing the barebones server-side class for our extension:
[source,java]
....
public class Refresher extends AbstractExtension {
public Refresher(UI ui) {
extend(target);
}
}
....
Two things to note:
* If we were writing a component, we would probably want to inherit from
`AbstractComponent`. Here, we inherit from `AbstractExtension` instead.
* The connector that should be extended is passed to the constructor,
which then uses the protected `extend(Connector)` method to attach
itself to the target connector. In this case it does not make much sense
attached to individual components, so the constructor only accepts `UI`.
Next, the Refresher needs an RPC interface to ping the server and a
shared state to keep track of the interval. These are rather trivial:
[source,java]
....
public interface RefresherRpc extends ServerRpc {
public void refresh();
}
....
[source,java]
....
public class RefresherState extends SharedState {
public int interval;
}
....
The client-side connector is just like a component connector except that
we inherit from `AbstractExtensionConnector`, not
`AbstractComponentConnector`. We do not write a client-side widget at
all, because the Refresher does not have a UI.
We create a `Timer` instance that calls the `refresh` RPC method when
run. In `onStateChange()`, we know that either the interval, enabled
state, or both have changed, so we always cancel a possible
currently-running timer and schedule a new one if we're enabled. We also
remember to cancel the timer when the extension is detached.
[source,java]
....
@Connect(Refresher.class)
public class RefresherConnector extends AbstractExtensionConnector {
private Timer timer = new Timer() {
@Override
public void run() {
getRpcProxy(RefresherRpc.class).refresh();
}
};
@Override
public void onStateChanged(StateChangeEvent event) {
super.onStateChanged(event);
timer.cancel();
if (isEnabled()) {
timer.scheduleRepeating(getState().interval);
}
}
@Override
public void onUnregister() {
timer.cancel();
}
@Override
protected void extend(ServerConnector target) {
// Nothing for refresher to do here as it does not need to access the
// connector it extends
}
@Override
public RefresherState getState() {
return (RefresherState) super.getState();
}
}
....
Finally, we add an event listener interface and some accessor methods to
`Refresher`. There is nothing extension-specific in the following code:
[source,java]
....
public interface RefreshListener {
static Method METHOD = ReflectTools.findMethod(RefreshListener.class,
"refresh", RefreshEvent.class);
public void refresh(RefreshEvent refreshEvent);
}
public class RefreshEvent extends EventObject {
public RefreshEvent(Refresher refresher) {
super(refresher);
}
public Refresher getRefresher() {
return (Refresher) getSource();
}
}
public Refresher(UI ui) {
registerRpc(new RefresherRpc() {
@Override
public void refresh() {
fireEvent(new RefreshEvent(Refresher.this));
}
});
extend(ui);
}
@Override
public RefresherState getState() {
return (RefresherState) super.getState();
}
public void setInterval(int millis) {
getState().interval = millis;
}
public int getInterval() {
return getState().interval;
}
public void setEnabled(boolean enabled) {
getState().enabled = enabled;
}
public boolean isEnabled() {
return getState().enabled;
}
public void addRefreshListener(RefreshListener listener) {
super.addListener(RefreshEvent.class, listener, RefreshListener.METHOD);
}
public void removeRefreshListener(RefreshListener listener) {
super.removeListener(RefreshEvent.class, listener,
RefreshListener.METHOD);
}
....

+ 191
- 0
documentation/articles/CustomizingComponentThemeWithSass.asciidoc Bestand weergeven

@@ -0,0 +1,191 @@
---
title: Customizing Component Theme With SASS
order: 47
layout: page
---
[[customizing-component-theme-with-sass]]
Customizing component theme with SASS
-------------------------------------
In addition to the general benefits Sass brings to the world of CSS in
Vaadin 7, the way themes are set up allows us to quite easily accomplish
some things that were previously hard.
Let’s start from the top, without Sass, and continue from there. We'll
use the new _setPrimaryStyleName()_ to do some things previously not
possible.
We’ll work on a small example with buttons that we want to customize:
[source,java]
....
@Theme("sassy")
public class SassyUI extends UI {
@Override
public void init(VaadinRequest request) {
Button b = new Button("Reindeer");
Layout layout = new VerticalLayout();
layout.addComponent(b);
setContent(layout);
}
}
....
And our basic (mostly empty at this point) “sassy” theme, based on
Reindeer, looks like this (assuming you're using the recommended
styles.scss+themename.scss structure as introduced in the previous
tutorial):
[source,scss]
....
@import "../reindeer/reindeer.scss";
@mixin sassy {
@include reindeer;
// your styles go here
}
....
And the result is a basic Reindeer-looking button. We can change the
color of the caption like this:
[source,scss]
....
.v-button-caption {
color: red;
}
....
…but this changes ALL buttons. We just want some of the buttons to stand
out:
[source,java]
....
b = new Button("important");
b.addStyleName("important");
layout.addComponent(b);
....
css:
[source,scss]
....
.important .v-button-caption {
color: red;
}
....
Ok, this is all fine - but we realize our important button should
actually not look at all like a Reindeer button.
Since Reindeer adds quite a few styles, this requires quite a lot of
customization with this approach. Enter _setPrimaryStyleName()_:
[source,java]
....
b = new Button("More important");
b.setPrimaryStyleName("my-button");
addComponent(b);
....
Now everything that was previously _.v-button_ in the browser DOM is all
of a sudden _.my-button_, and we have a completely unstyled button, but
with the DOM-structure and functionality of a regular button. We can
easily style this without interference from theme styles:
[source,scss]
....
.my-button {
color: red;
}
....
However, in our case we realize we still want it to look like a button,
just not with so much decorations as a Reindeer button. Let’s apply Base
styles:
[source,scss]
....
@include base-button($primaryStyleName: my-button);
.my-button {
color: red;
}
....
What? We now have a basic button with red text, but how?
We have @included base-button and renamed it’s selectors to “my-button”
(instead of the default “v-button”). This makes the rules match our
button perfectly (we used setPrimaryStyleName() to rename it) - in
effect we apply base-button to our “my-button”.
Now we have a good starting-point. Note that this might not be such a
big deal for small things, like buttons, but imagine something like
Table witout _any_ styles. Yikes.
Here are the full sources (using distinct colors for each button for
clarity):
[source,java]
....
package com.example.sassy;
import com.vaadin.annotations.Theme;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Button;
import com.vaadin.ui.Layout;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
@Theme("sassy")
public class SassyUI extends UI {
@Override
public void init(VaadinRequest request) {
Button b = new Button("Reindeer");
Layout layout = new VerticalLayout();
layout.addComponent(b);
b = new Button("important");
b.addStyleName("important");
layout.addComponent(b);
b = new Button("More important");
b.setPrimaryStyleName("my-button");
layout.addComponent(b);
setContent(layout);
}
}
....
[source,scss]
....
// sassy/styles.scss
@import "sassy.scss";
.sassy {
@include sassy;
}
....
[source,scss]
....
// sassy/sassy.scss
@import "../reindeer/reindeer.scss";
@mixin sassy {
@include reindeer;
.v-button-caption {
color: red;
}
.important .v-button-caption {
color: green;
}
@include base-button($name: my-button);
.my-button {
color: blue;
}
}
....

+ 120
- 0
documentation/articles/CustomizingTheStartupPageInAnApplication.asciidoc Bestand weergeven

@@ -0,0 +1,120 @@
---
title: Customizing The Startup Page In An Application
order: 43
layout: page
---
[[customizing-the-startup-page-in-an-application]]
Customizing the startup page in an application
----------------------------------------------
In Vaadin 6, the startup page - used to bootstrap a new Vaadin UI
instance in the browser - was generated as a monolithic chunk of HTML
and was not easily customizable. In Vaadin 7, we added a new facility
for registering special _bootstrap listeners_ that are invoked before
the bootstrap response is sent. In addition, instead of bare HTML in a
string, the response is now built as a DOM tree that is easy to
manipulate programmatically.
Here's an example of a simple bootstrap listener:
[source,java]
....
import org.jsoup.nodes.Comment;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.parser.Tag;
// ...
new BootstrapListener() {
@Override
public void modifyBootstrapPage(BootstrapPageResponse response) {
response.getDocument().body().appendChild(new Comment("Powered by Vaadin!", ""));
}
@Override
public void modifyBootstrapFragment(BootstrapFragmentResponse response) {
// Wrap the fragment in a custom div element
Element myDiv = new Element(Tag.valueOf("div"), "");
List<Node> nodes = response.getFragmentNodes();
for(Node node : nodes) {
myDiv.appendChild(node);
}
nodes.clear();
nodes.add(myDiv);
}
}
....
The HTML library we use is http://jsoup.org/[jsoup]. It provides a very
convenient API for traversing, manipulating and extracting data from a
DOM, and is HTML5 compliant.
The `BootstrapListener` interface contains two methods, one of which is
usually left empty. This is because a Vaadin application can be either
stand-alone, in which case it "owns" the whole page its UI resides in,
or embedded, such as a portlet, in which case it does not control the
content of the page it is embedded in.
The `modifyBootstrapFragment` method is called in both cases. It
receives a `BootstrapFragmentResponse` that represents the HTML fragment
that is inserted in the host page, whether the page is controlled by
Vaadin or not. Hence, you only need to implement this method if you do
not care about the host page, whether your application is embedded or
standalone.
The `modifyBootstrapPage` method is called with a
`BootstrapPageResponse` argument that represents the whole bootstrap
page, including the fragment mentioned above. Thus, it is only invoked
when the application is standalone and actually responsible for
generating the page. This method allows you to, for instance, add things
to the `head` element. The `BootstrapPageResponse` class also allows
setting arbitrary HTTP response headers:
[source,java]
....
public void modifyBootstrapPage(BootstrapPageResponse response) {
response.setHeader("X-Powered-By", "Vaadin 7");
}
....
But how and where should the bootstrap listeners be registered? It
should be only once per session, and right in the beginning, so that
they are already added when the first response is sent.
To do that you should write a custom servlet that extends
`VaadinServlet`, or a custom portlet extending `VaadinPortlet`, and a
session init listener that adds the bootstrap listener to the new
session.
[source,java]
....
class MyVaadinServlet extends VaadinServlet {
@Override
protected void servletInitialized() throws ServletException {
super.servletInitialized();
getService().addSessionInitListener(new SessionInitListener() {
@Override
public void sessionInit(SessionInitEvent event) {
event.getSession().addBootstrapListener(listener);
}
});
}
}
// Or...
class MyVaadinPortlet extends VaadinPortlet {
@Override
protected void portletInitialized() throws PortletException {
super.portletInitialized();
getService().addSessionInitListener(new SessionInitListener() {
@Override
public void sessionInit(SessionInitEvent event) {
event.getSession().addBootstrapListener(listener);
}
});
}
}
....

+ 140
- 0
documentation/articles/ExposingServerSideAPIToJavaScript.asciidoc Bestand weergeven

@@ -0,0 +1,140 @@
---
title: Exposing Server Side API To JavaScript
order: 41
layout: page
---

[[exposing-server-side-api-to-javascript]]
Exposing server-side API to JavaScript
--------------------------------------

The new JavaScript integration functionality will allow you to easily
publish methods that can be called with JavaScript on the client side.
In effect, you can publish a JavaScript API for your application.
Although you will probably not find yourself using this very often, it
can be useful when integrating with JavaScript frameworks or embedding
within legacy sites.

Exposing a `notify()` method that takes a message and displays that as a
notification can be done in one simple block in e.g `UI.init()`:

[source,java]
....
JavaScript.getCurrent().addFunction("notify", new JavaScriptFunction() {
public void call(JSONArray arguments) throws JSONException {
Notification.show(arguments.getString(0));
}
});
....

This will expose the `notify()`{empty}-method globally in the window object.
Technically it's thus `window.notify()`, but you can call it by simply
by `notify()`. Try entering `notify("Hey!")` into the Firebug or
Developler Tools console, or `javascript:notify("Hey!")` into the
address bar.

You'll notice that this assumes there is a String in the first position
of the array. Also, this will clutter the global namespace, which is
generally not a good idea, unless you really have a specific need for
that.

Let's make a complete example with two arguments, some simple error
handling, and namespacing:

[source,java]
....
JavaScript.getCurrent().addFunction("com.example.api.notify",
new JavaScriptFunction() {
public void call(JSONArray arguments) throws JSONException {
try {
String caption = arguments.getString(0);
if (arguments.length() == 1) {
// only caption
Notification.show(caption);
} else {
// type should be in [1]
Notification.show(caption,
Type.values()[arguments.getInt(1)]);
}
} catch (JSONException e) {
// We'll log in the console, you might not want to
JavaScript.getCurrent().execute(
"console.error('" + e.getMessage() + "')");
}
}
});
}
....

Using the dotted notation for the method will automatically create those
objects in the browser; you'll call this method like so:
`com.example.api.notify("Hey!")`. You do not have to use a long name
like this, though - it's up to you and your use-case.

The second thing to notice is that we now wrapped the code in a
try-catch, so that the wrong number or wrong types of arguments does not
cause an ugly stacktrace in our server logs. Again, how you should react
to erroneous use of your exposed API depends on your use-case. We'll log
an error message to the browser console as an example.

We're now accepting a second (integer) argument, and using that as
_type_ for the `Notification`.

Finally, we'll add a link that will call the function, and work as a
_Bookmarklet_. You can drag the link to your bookmarks bar, and when you
invoke it when viewing the application with our exposed `notify()`{empty}-method, you will be prompted for a message that will then be sent to
the method. Here is the plain HTML code for creating such a link:

[source,html]
....
<a href="javascript:(function(){com.example.api.notify(prompt('Message'),2);})();">Send message</a>
....

Here is the full source for our application:

[source,java]
....
import org.json.JSONArray;
import org.json.JSONException;
import com.vaadin.server.ExternalResource;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.JavaScript;
import com.vaadin.ui.JavaScriptFunction;
import com.vaadin.ui.Link;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Notification.Type;
import com.vaadin.ui.UI;

public class JSAPIUI extends UI {
@Override
public void init(VaadinRequest request) {

JavaScript.getCurrent().addFunction("com.example.api.notify",
new JavaScriptFunction() {
public void call(JSONArray arguments) throws JSONException {
try {
String caption = arguments.getString(0);
if (arguments.length() == 1) {
// only caption
Notification.show(caption);
} else {
// type should be in [1]
Notification.show(caption,
Type.values()[arguments.getInt(1)]);
}
} catch (JSONException e) {
// We'll log in the console, you might not want to
JavaScript.getCurrent().execute(
"console.error('" + e.getMessage() + "')");
}
}
});


setContent(new Link(
"Send message",
new ExternalResource(
"javascript:(function(){com.example.api.notify(prompt('Message'),2);})();")));
}
}
....

+ 2
- 2
documentation/articles/FormattingDataInGrid.asciidoc Bestand weergeven

@@ -114,8 +114,8 @@ Full example
^^^^^^^^^^^^

Putting all these pieces together, we end up with this class that uses
the same data as in the link:UsingGridWithAContainer.asciidoc[Using
Grid with a Container] example.
the same data as in the <<UsingGridWithAContainer#using-with-a-container,Using
Grid with a Container>> example.

[source,java]
....

+ 116
- 0
documentation/articles/IntegratingAJavaScriptComponent.asciidoc Bestand weergeven

@@ -0,0 +1,116 @@
---
title: Integrating A JavaScript Component
order: 38
layout: page
---
[[integrating-a-javascript-component]]
Integrating a JavaScript component
----------------------------------
You can use an existing JavaScript component as a component in Vaadin by
creating a server-side API for the component as well as writing the
JavaScript code that connects the server-side API to the actual
JavaScript component. Because of the dynamic nature of JavaScript, you
don't need to use GWT development mode or recompile the widgetset while
making client-side changes.
The server-side component should extend `AbstractJavaScriptComponent` and
provide the API that the developer uses to interact with the component.
The class should also have a `@JavaScript` annotation that defines the
required JavaScript libraries in the order they should be loaded. This
example uses the Flot graph library from http://code.google.com/p/flot/.
Float requires jQuery which is loaded using
https://developers.google.com/speed/libraries/[Google Libraries API].
[source,java]
....
import com.vaadin.annotations.*;
@JavaScript({"https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js", "jquery.flot.js", "flot_connector.js"})
public class Flot extends AbstractJavaScriptComponent {
public void addSeries(double... points) {
List<List<Double>> pointList = new ArrayList<List<Double>>();
for (int i = 0; i < points.length; i++) {
pointList.add(Arrays.asList(Double.valueOf(i),
Double.valueOf(points[i])));
}
getState().series.add(pointList);
}
@Override
public FlotState getState() {
return (FlotState) super.getState();
}
}
....
The shared state class will not be used by any GWT code so you don't
have to put it in the widgetset's client package. The state class should
extend `JavaScriptComponentState` but is otherwise similar to the shared
state of a normal GWT component.
[source,java]
....
public class FlotState extends JavaScriptComponentState {
public List<List<List<Double>>> series = new ArrayList<List<List<Double>>>();
}
....
The only remaining code is the client-side JavaScript connector in
`flot_connector.js`. The connector defines a global initializer function
named based on the fully qualified name of the server-side `Component`
class with dots replaced with underscores. In this example the
server-side `Component` is `com.example.Flot` which means that the function
name should be `com_example_Flot`.
This initializer function should initialize the JavaScript part of the
component. It is called by the framework with `this` pointing to a
connector wrapper providing integration to the framework. For full
information about the services provided by the connector wrapper, please
read the Javadoc for the `AbstractJavaScriptComponent` class.
In this example, the initializer first initializes the `element`
variable with a jQuery object for the DOM element of the component.
Next, a state change listener is defined by assigning a function to the
`onStateChange` field of the connector wrapper. This function will be
called whenever the shared state is changed from the server-side code.
In the state change listener, the Flot API is used to initialize a graph
with the data series from the shared state into the DOM element.
The format of the series property in the `FlotState` Java class has been
chosen with the Flot API in mind. Flot expects an array of data series
where each item is an array of data points where each data point is an
array with the x value followed by the y value. This is defined in Java
as `List<List<List<Double>>>` and then the framework takes care of the
conversion between server-side Java values and client-side JavaScript
values. `double[][][]` in Java would give the same JavaScript structure,
but it was not used here as it gives less flexibility in the Java code.
[source,javascript]
....
window.com_example_Flot = function() {
var element = $(this.getElement());
this.onStateChange = function() {
$.plot(element, this.getState().series);
}
}
....
By implementing a server-side Java class extending
`AbstractJavaScriptConnector` and a client-side JavaScript connector
initialization function, existing JavaScript component libraries can
easily be integrated to Vaadin. The server-side code is almost similar
to the code required for a component based on GWT and the client-side
code is quite similar to a `ComponentConnector` implemented using GWT.
[WARNING]
.Security Warning
====
Do note that third-party JavaScript code could be dangerous
(https://www.owasp.org/index.php/3rd_Party_Javascript_Management_Cheat_Sheet),
and you should take into account the security risks of using such.
====

+ 96
- 0
documentation/articles/IntegratingAJavaScriptLibraryAsAnExtension.asciidoc Bestand weergeven

@@ -0,0 +1,96 @@
---
title: Integrating A JavaScript Library As An Extension
order: 39
layout: page
---
[[integrating-a-javascript-library-as-an-extension]]
Integrating a JavaScript library as an extension
------------------------------------------------
JavaScript can also be used for creating Extensions e.g. for integrating
existing JavaScript libraries. See <<CreatingAUIExtension#creating-a-ui-extension,
Creating a UI extension>> for general information about Extensions. The main
difference when using JavaScript is that you extend
`AbstractJavaScriptExtension`, that your shared state class should
extend `JavaScriptExtensionState` and then of course that your
client-side implementation is written in JavaScript. See
<<IntegratingAJavaScriptComponent#integrating-a-javascript-component,
Integrating a JavaScript component>> for basic information about how to use
JavaScript for your client-side logic.
This tutorial will create a simple Extension for integrating
https://developers.google.com/analytics/devguides/collection/gajs/[Google
Analytics]. Because the Analytics API just uses the same `_gaq.push`
function with different arguments, the JavaScript connector logic can be
equally simple. Aside from asynchronously loading ga.js, the client-side
code just adds a callback that the server-side code can use to push new
commands.
[source,javascript]
....
window._gaq = window._gaq || [];
(function() {
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') +
'.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();
window.com_example_Analytics = function() {
this.pushCommand = function(command) {
_gaq.push(command);
}
}
....
The server-side Extension class provides the common Extension API for
extending a UI instance as well as API for some Analytics features. All
the Analytics features are based on the `pushCommand` method that
invokes the corresponding client-side callback.
The Analytics API used in this example has nothing that warrants using
shared state, but you can of course use shared state in your own
JavaScript Extension if you want to as long as your state class extends
`JavaScriptExtensionState`.
[source,java]
....
@JavaScript("analytics_connector.js")
public class Analytics extends AbstractJavaScriptExtension {
public Analytics(UI ui, String account) {
extend(ui);
pushCommand("_setAccount", account);
}
public void trackPageview(String name) {
pushCommand("_trackPageview", name);
}
private void pushCommand(Object... commandAndArguments) {
// Cast to Object to use Object[] commandAndArguments as the first
// varargs argument instead of as the full varargs argument array.
callFunction("pushCommand", (Object) commandAndArguments);
}
}
....
Extensions are suitable for integrating many existing JavaScript
libraries that do not provide a component that is added to a layout. By
using a client-side JavaScript connector for integrating the JavaScript
library, you can eliminate GWT from the equation to give you slightly
less code to maintain.
[WARNING]
.Security Warning
====
Do note that third-party JavaScript code can be dangerous
(https://www.owasp.org/index.php/3rd_Party_Javascript_Management_Cheat_Sheet),
and you should take into account the security risks of using such.
====

+ 62
- 59
documentation/articles/MigratingFromVaadin6ToVaadin7.asciidoc Bestand weergeven

@@ -8,8 +8,8 @@ layout: page
= Migrating from Vaadin 6 to Vaadin 7

For migration to Vaadin 7.1,  see
link:MigratingFromVaadin7.0ToVaadin7.1.asciidoc[Migrating
from Vaadin 7.0 to Vaadin 7.1]
<<MigratingFromVaadin7.0ToVaadin7.1#migrating-from-vaadin-7.0-to-vaadin-7.1,
Migrating From Vaadin 7.0 To Vaadin 7.1>>

[[getting-started]]
Getting Started
@@ -71,7 +71,7 @@ public class V6tm1Application extends Application {
Label label = new Label("Hello Vaadin!");
mainWindow.addComponent(label);
setMainWindow(mainWindow);
setTheme(“mytheme”);
setTheme("mytheme");
}
}
....
@@ -180,9 +180,9 @@ In Vaadin 6, Window, Panel and some other components had a *default
layout* and addComponent() etc. As this often caused confusion and
caused layout problems when unaware of the implicit layout or forgetting
to set its layout parameters, Vaadin 7 now requires *explicitly setting
the content*. See See e.g.
link:CreatingABasicApplication.asciidoc[Creating
a basic application]
the content*. See e.g.
<<CreatingABasicApplication#creating-a-basic-application,Creating
a basic application>>

If you want to minimize the impact of this on the look and theme of an
old application, you can reproduce the *old structure* simply by setting
@@ -213,8 +213,9 @@ of synchronizing to the Application instance - see the javadoc for

To customize the creation of UIs - for instance to create different UIs
for mobile and desktop devices -
*link:CreatingAnApplicationWithDifferentFeaturesForDifferentClients.asciidoc[a
custom UIProvider]* can be used.
<<CreatingAnApplicationWithDifferentFeaturesForDifferentClients#creating-
an-application-with-different-features-for-different-clients,a
custom UIProvider>> can be used.

[[forms-and-data-binding]]
Forms and Data Binding
@@ -231,21 +232,24 @@ data binding works mostly as is, version 7 brings something better:

* *FieldGroup* supporting *automated data binding*, whether for a hand-designed
form or
link:AutoGeneratingAFormBasedOnABeanVaadin6StyleForm.asciidoc[creating
the fields automatically]
<<AutoGeneratingAFormBasedOnABeanVaadin6StyleForm#
auto-generating-a-form-based-on-a-bean-vaadin-6-style,creating the fields automatically>>

* *link:CreatingATextFieldForIntegerOnlyInputUsingADataSource.asciidoc[typed
fields and properties]*
* *<<CreatingATextFieldForIntegerOnlyInputWhenNotUsingADataSource#
creating-a-textfield-for-integer-only-input-when-not-using-a-data-source,typed
fields and properties>>*

* *link:CreatingYourOwnConverterForString.asciidoc[converters]*,
* *<<CreatingYourOwnConverterForString#creating-your-own-converter-for-string-mytype-conversion,
converters>>*,
both
link:ChangingTheDefaultConvertersForAnApplication.asciidoc[automatic
via ConverterFactory] and
link:CreatingATextFieldForIntegerOnlyInputWhenNotUsingADataSource.asciidoc[explicitly set]
<<ChangingTheDefaultConvertersForAnApplication#changing-the-default-converters-for-an-application,
automatic via ConverterFactory>> and
<<CreatingATextFieldForIntegerOnlyInputWhenNotUsingADataSource#
creating-a-textfield-for-integer-only-input-when-not-using-a-data-source,explicitly set>>

* improved *validation* (performed on data model values after
conversion) - see e.g.
link:UsingBeanValidationToValidateInput.asciidoc[bean validation example]
<<UsingBeanValidationToValidateInput#using-bean-validation-to-validate-input,bean validation example>>

* and more

@@ -305,8 +309,7 @@ optional additional optional parameters before the module name.

If you have optimized your widgetset to limit what components to load
initially, see
link:OptimizingTheWidgetSet.asciidoc[this
tutorial] and the
<<OptimizingTheWidgetSet#optimizing-the-widget-set,this tutorial>> and the
https://vaadin.com/directory/component/widget-set-optimizer[WidgetSet
Optimizer add-on].

@@ -332,18 +335,18 @@ fully migrating your themes to the SCSS format with a theme name
selector.

To take advantage of the new features, see
link:CreatingAThemeUsingSass.asciidoc[Creating
a theme using sass] and
link:CustomizingComponentThemeWithSass.asciidoc[Customizing
component theme with Sass].
<<CreatingAThemeUsingSass#creating-a-theme-using-sass,Creating a theme using Sass>>
and
<<CustomizingComponentThemeWithSass#customizing-component-theme-with-sass,
Customizing component theme with Sass>>.

Note that the SCSS theme needs to be *compiled* to CSS before use - in
development mode, this takes place automatically on the fly whenever the
theme is loaded, but when moving to production mode, you need to run the
theme compiler on it to produce a pre-compiled static theme.

link:WidgetStylingUsingOnlyCSS.asciidoc[CSS
can be used to style components] somewhat more freely than in Vaadin 6.
<<WidgetStylingUsingOnlyCSS#widget-styling-using-only-css,CSS can be used to style
components>> somewhat more freely than in Vaadin 6.

The DOM structure of several layouts has changed, which might require
changes to themes for layouts. See also the section on layouts below.
@@ -359,14 +362,12 @@ navigate to them.

The best way to get acquainted with the new navigation features is to
check the tutorials on
link:CreatingABookmarkableApplicationWithBackButtonSupport.asciidoc[creating
a bookmarkable application],
link:UsingParametersWithViews.asciidoc[using
parameters with views],
link:AccessControlForViews.asciidoc[access
control for views] and
link:ViewChangeConfirmations.asciidoc[view
change confirmations].
<<CreatingABookmarkableApplicationWithBackButtonSupport#
creating-a-bookmarkable-application-with-back-button-support,
creating a bookmarkable application>>,
<<UsingParametersWithViews#using-parameters-with-views,using parameters with views>>,
<<AccessControlForViews#access-control-for-views,access control for views>> and
<<ViewChangeConfirmations#view-change-confirmations,view change confirmations>>.

When logging out a user, you can use *Page.setLocation()* to redirect
the user to a suitable page.
@@ -380,8 +381,8 @@ As ApplicationServlet moved to history and is replaced by

The most common customizations:

* link:CustomizingTheStartupPageInAnApplication.asciidoc[Customizing
the bootstrap page]: JavaScript, headers, ...
* <<CustomizingTheStartupPageInAnApplication#customizing-the-startup-page-in-an-application,
Customizing the bootstrap page in an application>>: JavaScript, headers, ...
* Add-ons using customized servlets for other purposes (e.g. customizing
communication between client and server) probably need more extensive
rework
@@ -413,20 +414,21 @@ server side component Label, but the communication part has been split
off into LabelConnector. The annotations linking the client side and the
server side have also changed, now the LabelConnector has an *@Connect*
annotation linking it to the server side component Label.
https://vaadin.com/book/vaadin7/-/page/architecture.client-side.html[the
https://vaadin.com/book/vaadin7/-/page/architecture.client-side.html[The
book] provides some background and the tutorial on
link:CreatingASimpleComponent.asciidoc[creating
a simple component] shows an example.
<<CreatingASimpleComponent#creating-a-simple-component,creating a simple
component>> shows an example.

The connector communicates with the server primarily via shared
state from the server to the client and **RPC
calls **link:SendingEventsFromTheClientToTheServerUsingRPC.asciidoc[from
client to server] and
link:UsingRPCToSendEventsToTheClient.asciidoc[from
server to client], with a larger set of supported data types. For
calls **<<SendingEventsFromTheClientToTheServerUsingRPC#
sending-events-from-the-client-to-the-server-using-RPC,from
client to server>> and
<<UsingRPCToSendEventsToTheClient#using-rpc-to-send-events-to-the-client,
from server to client>>, with a larger set of supported data types. For
component containers,
link:CreatingASimpleComponentContainer.asciidoc[the
hierarchy of the contained components is sent separately].
<<CreatingASimpleComponentContainer#creating-a-simple-component-container,
the hierarchy of the contained components is sent separately>>.

The old mechanism with UIDL, *paintContent()* and *changeVariables()* is
still there for a while to ease migration, but it is recommended to
@@ -436,15 +438,16 @@ in much cleaner code. Using the old mechanisms requires implementing

There are also new features such as support for *Extensions* (components
which
link:CreatingAUIExtension.asciidoc[extend
the UI] or
link:CreatingAComponentExtension.asciidoc[other
components] without having a widget in a layout) and
link:UsingAJavaScriptLibraryOrAStyleSheetInAnAddOn.asciidoc[support
for JavaScript], also for
link:IntegratingAJavaScriptComponent.asciidoc[implementing
components] and
link:IntegratingAJavaScriptLibraryAsAnExtension.asciidoc[extensions],
<<CreatingAUIExtension#creating-a-ui-extension,extend the UI>> or
<<CreatingAComponentExtension#creating-a-component-extension,other
components>> without having a widget in a layout) and
<<UsingAJavaScriptLibraryOrAStyleSheetInAnAddOn#
using-a-javascript-library-or-a-style-sheet-in-an-addon,support for
JavaScript>>, also for
<<IntegratingAJavaScriptComponent#integrating-a-javascript-component,
implementing components>> and
<<IntegratingAJavaScriptLibraryAsAnExtension#
integrating-a-javascript-library-as-an-extension,extensions>>,
which might simplify the implementation of some components. Shared state
and RPC can also be used from JavaScript, and there are other techniques
for client-server communication.
@@ -550,8 +553,8 @@ side component containers, but a few can also affect other developers.

Among the changes affecting others than layout developers, *CssLayout*
now consists of a single DIV instead of three nested elements, and
link:WidgetStylingUsingOnlyCSS.asciidoc[CSS
can be used to do more customization] than in previous Vaadin versions.
<<WidgetStylingUsingOnlyCSS#widget-styling-using-only-css,CSS
can be used to do more customization>> than in previous Vaadin versions.
Also other layouts have changed in terms of their *DOM structure* on the
client, which might require changes to themes. The interface
*MarginHandler* is now only implemented by layouts that actually support
@@ -565,10 +568,10 @@ of *ComponentContainer*.

For those implementing new component containers or layouts, see the
related tutorials
link:CreatingASimpleComponentContainer.asciidoc[Creating
a simple component container] and
link:WidgetStylingUsingOnlyCSS.asciidoc[Widget
styling using only CSS].
<<CreatingASimpleComponentContainer#creating-a-simple-component-container,
Creating a simple component container>> and
<<WidgetStylingUsingOnlyCSS#widget-styling-using-only-css,
Widget styling using only CSS>>.

[[migration-steps-for-componentcontainers]]
Migration steps for ComponentContainers

+ 3
- 3
documentation/articles/MigratingFromVaadin7.0ToVaadin7.1.asciidoc Bestand weergeven

@@ -13,9 +13,9 @@ This guide describes how to migrate from earlier versions to Vaadin 7.1.
Migrating from Vaadin 6
~~~~~~~~~~~~~~~~~~~~~~~

When migrating from Vaadin 6, first review
link:MigratingFromVaadin6ToVaadin7.asciidoc[Migrating
from Vaadin 6 to Vaadin 7], then continue with the rest of this guide.
When migrating from Vaadin 6, first review
<<MigratingFromVaadin6ToVaadin7#migrating-from-vaadin-6-to-vaadin-7,Migrating
from Vaadin 6 to Vaadin 7>>, then continue with the rest of this guide.

[[migrating-from-vaadin-7.0]]
Migrating from Vaadin 7.0

+ 193
- 0
documentation/articles/OptimizingTheWidgetSet.asciidoc Bestand weergeven

@@ -0,0 +1,193 @@
---
title: Optimizing The Widget Set
order: 44
layout: page
---
[[optimizing-the-widget-set]]
Optimizing the widget set
-------------------------
Vaadin contains a lot of components and most of those components
contains a client side part which is executed in the browser. Together
all the client side implementations sum up to a big amount of data the
enduser needs to download to the browser even if he might never use all
the components.
For that reason Vaadin uses three strategies for downloading the
components:
[[eager]]
Eager
+++++
What eager means is that the client implementation for the component is
included in the payload that is initially downloaded when the
application starts. The more components that is made eager the more will
need to be downloaded before the initial view of the application is
shown. By default Vaadin puts most components here since Vaadin does not
know which components will be used in the first view and cannot thus
optimize any further. You would have noticed this if you ever made a
Hello World type of application and wondered why Vaadin needed to
download so much for such a simple application.
[[deferred]]
Deferred
++++++++
When marking a component as deferred it means that its client side
implementation will be downloaded right after the initial rendering of
the application is done. This can be useful if you know for instance
that a component will soon be used in that application but is not
displayed in the first view.
[[lazy]]
Lazy
++++
Lazy components client side implementation doesn't get downloaded until
the component is shown. This will sometimes mean that a view might take
a bit longer to render if several components client side implementation
needs to first be downloaded. This strategy is useful for components
that are rarely used in the application which everybody might not see.
`RichTextArea` and `ColorPicker` are examples of components in Vaadin that by
default are Lazy.
[[optimizing-the-loading-of-the-widgets]]
Optimizing the loading of the widgets
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Now that we know what Vaadin provides, lets see how we can modify how a
component is loaded to provide the best experience for our application.
Lets say we want to build a HelloWorld application which only needs a
few components. Specifically these components will be shown on the
screen:
* UI - The UI of the application.
* VerticalLayout - The Vertical layout inside the UI where the message
is shown
* Label - A label with the text "Hello World"
All other Vaadin components provided by Vaadin we don't want to load. To
do this we are going to mark those three components as Eager (initially
loaded) and all the rest as Lazy.
To do that we need to implement our own `ConnectorBundleLoaderFactory`.
Here is my example one:
[source,java]
....
public class MyConnectorBundleLoaderFactory extends
ConnectorBundleLoaderFactory {
private static final List<Class> eagerComponents = new
LinkedList<Class>();
static {
eagerComponents.add(UI.class);
eagerComponents.add(VerticalLayout.class);
eagerComponents.add(Label.class);
}
@Override protected LoadStyle getLoadStyle(JClassType connectorType){
Connect annotation = connectorType.getAnnotation(Connect.class);
Class componentClass = annotation.value();
// Load eagerly marked connectors eagerly
if(eagerComponents.contains(componentClass)) {
return LoadStyle.EAGER;
}
//All other components should be lazy
return LoadStyle.LAZY;
}
}
....
We also need to add our factory to the widgetset by adding the following
to our <widgetset>.gwt.xml:
[source,xml]
....
<generate-with class="com.example.widgetsetoptimization.MyConnectorBundleLoaderFactory">
<when-type-assignable class="com.vaadin.client.metadata.ConnectorBundleLoader" />
</generate-with>
....
If you are using the Eclipse Plugin to compile the widgetset you will
also want to add the following meta data for the compiler so it does not
overwrite our generator setting:
[source,xml]
....
<!-- WS Compiler: manually edited -->
....
If you have used the Maven archetype for setting up your project, you
might need to add vaadin-client-compiler as a dependency in your project
as it is by default only used when actually starting the widgetset
compiler. See http://dev.vaadin.com/ticket/11533 for more details.
Finally, here is my simple test application UI for which I have
optimized the widgetset:
[source,java]
....
public class HelloWorldUI extends UI {
@Override
protected void init(VaadinRequest request) {
VerticalLayout layout = new VerticalLayout();
layout.addComponent(new Label("Hello world"));
setContent(layout);
}
}
....
Now, all I have to do is recompile the widgetset for the new load
strategy to take effect.
If you now check the network traffic when you load the application you
will notice a *huge difference*. Using the default widgetset with the
default loading strategy our Hello World application will load over *1
Mb* of widgetset data. If you then switch to using our own widgetset
with our own custom loader factory the widgetset will only be about *375
kb*. That is over *60% less!*
Using your own custom widgetset loader factory is highly recommended in
all projects.
[[finding-out-which-components-are-loaded-by-a-view]]
Finding out which components are loaded by a View
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
So you want to start optimizing your widgetset but how do you find out
which components are needed for the initial view so you can make them
eager while keeping everything else deferred or lazy? Fortunately there
is an addon
https://vaadin.com/directory#addon/widget-set-optimizer[WidgetSetOptimizer]
for doing just this.
To use it you download this addon and add it to your project.
Add the following to the <widgetset>.gwt.xml:
[source,xml]
....
<inherits name="org.vaadin.artur.widgetsetoptimizer.WidgetSetOptimizerWidgetSet" />
....
You will also need to add the following to your UI classes init method
[source,java]
....
new WidgetSetOptimizer().extend(this);
....
Finally compile the widgetset and run the application with the &debug
parameter. In the debug window there will be a new button "OWS" which by
pressing you will get the Generator class automatically generated for
you. The generated generator class will mark the currently displayed
components as Eager while loading everything else as Deferred. More
information about the addon and its usage can be found on the Addon page
in the directory.

+ 145
- 0
documentation/articles/SendingEventsFromTheClientToTheServerUsingRPC.asciidoc Bestand weergeven

@@ -0,0 +1,145 @@
---
title: Sending Events From The Client To The Server Using RPC
order: 37
layout: page
---
[[sending-events-from-the-client-to-the-server-using-RPC]]
Sending events from the client to the server using RPC
------------------------------------------------------
An RPC mechanism can be used to communicate from the client to the
server. In effect, the client can call methods that are executed by the
server component. The server component can then take appropriate action
- e.g updating the shared state or calling event listeners.
To set up client-server RPC we need to create one interface defining the
RPC methods, and then make use of that interface on both the client and
the server. Place the `MyComponentServerRpc` interface in the client
package:
[source,java]
....
package com.example.mycomponent.client;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.communication.ServerRpc;
public interface MyComponentServerRpc extends ServerRpc {
public void clicked(MouseEventDetails mouseDetails);
}
....
Note that the RPC methods can not have return values. In this example,
we pass `MouseEventDetails` to get a more complete example, but you
could pass almost any (or no) parameters.
In the server side `MyComponent` we need to implement the interface, and
register it for use:
[source,java]
....
package com.example.mycomponent;
import com.example.mycomponent.client.MyComponentServerRpc;
import com.example.mycomponent.client.MyComponentState;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.ui.AbstractComponent;
public class MyComponent extends AbstractComponent {
private int clickCount = 0;
private MyComponentServerRpc rpc = new MyComponentServerRpc() {
public void clicked(MouseEventDetails mouseDetails) {
clickCount++;
setText("You have clicked " + clickCount + " times");
}
};
public MyComponent() {
registerRpc(rpc);
}
/* Previous code commented out for clarity:
@Override
public MyComponentState getState() {
return (MyComponentState) super.getState();
}
public void setText(String text) {
getState().text = text;
}
public String getText() {
return getState().text;
}
*/
}
....
Here we react to the RPC call by incrementing a counter. We do not make
use of the `MouseEventDetails` (yet). Notice the *important call to
`registerRpc()`* in the added constructor.
In the client side `MyComponentConnector`, we use `RpcProxy` to get an
implementation of the RPC interface, and call the `clicked()` method
when the widget is clicked:
[source,java]
....
package com.example.mycomponent.client;
// imports removed for clarity
import com.vaadin.terminal.gwt.client.communication.RpcProxy;
@Connect(MyComponent.class)
public class MyComponentConnector extends AbstractComponentConnector {
MyComponentServerRpc rpc = RpcProxy
.create(MyComponentServerRpc.class, this);
public MyComponentConnector() {
getWidget().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
final MouseEventDetails mouseDetails = MouseEventDetailsBuilder
.buildMouseEventDetails(event.getNativeEvent(),
getWidget().getElement());
rpc.clicked(mouseDetails);
}
});
}
/* Previous code commented out for clarity:
@Override
protected Widget createWidget() {
return GWT.create(MyComponentWidget.class);
}
@Override
public MyComponentWidget getWidget() {
return (MyComponentWidget) super.getWidget();
}
@Override
public MyComponentState getState() {
return (MyComponentState) super.getState();
}
@OnStateChange("text")
void updateText() {
getWidget().setText(getState().text);
}
*/
}
....
Notice that most of the code is for attaching the click handler and
creating the `MouseEventDetails`, the code for the actual RPC is quite
minimal.
Compile the widgetset, and the label text should be updated with the
click count whenever you click it (remember that the counting is done on
the server-side).
Finally, note that you can use multiple RPC interfaces in one component,
allowing for better code separation and reuse.
You can do the same thing in the other direction, see the article about
server to client RPC for details.

+ 2
- 2
documentation/articles/ShowingExtraDataForGridRows.asciidoc Bestand weergeven

@@ -18,8 +18,8 @@ expanded, and then you need to hook up the events for actually expanding
a row.

This example uses the same data as in the
link:UsingGridWithAContainer.asciidoc[Using Grid with a Container]
example.
<<UsingGridWithAContainer#using-grid-with-a-container,
Using Grid with a Container>> example.

[[detailsgenerator]]
DetailsGenerator

+ 10
- 9
documentation/articles/SimplifiedRPCusingJavaScript.asciidoc Bestand weergeven

@@ -8,16 +8,17 @@ layout: page
= Simplified RPC using JavaScript

This tutorial continues where
link:IntegratingAJavaScriptComponent.asciidoc[Integrating a JavaScript
component] ended. We will now add RPC functionality to the JavaScript
Flot component. RPC can be used in the same way as with ordinary GWT
components as described in link:UsingRPCFromJavaScript.asciidoc[Using
RPC from JavaScript]. This tutorial describes a simplified way that is
<<IntegratingAJavaScriptComponent#integrating-a-javascript-component,
Integrating a JavaScript component>> ended. We will now add RPC
functionality to the JavaScript Flot component. RPC can be used in the
same way as with ordinary GWT components as described in
<<IntegratingAJavaScriptComponent#integrating-a-javascript-component,
Using RPC from JavaScript>>. This tutorial describes a simplified way that is
based on the same concepts as in
link:ExposingServerSideAPIToJavaScript.asciidoc[Exposing server
side API to JavaScript]. This way of doing RPC is less rigorous and is
intended for simple cases and for developers appreciating the dynamic
nature of JavaScript.
<<ExposingServerSideAPIToJavaScript#exposing-server-side-api-to-javascript,
Exposing server side API to JavaScript>>. This way of doing RPC is less
rigorous and is intended for simple cases and for developers appreciating
the dynamic nature of JavaScript.

The simplified way is based on single callback functions instead of
interfaces containing multiple methods. We will invoke a server-side

+ 61
- 0
documentation/articles/UsingAJavaScriptLibraryOrAStyleSheetInAnAddOn.asciidoc Bestand weergeven

@@ -0,0 +1,61 @@
---
title: Using A JavaScript Library Or A Style Sheet In An Add On
order: 40
layout: page
---
[[using-a-javascript-library-or-a-style-sheet-in-an-addon]]
Using a JavaScript library or a style sheet in an add-on
--------------------------------------------------------
Including style sheets or JavaScript files in your add-ons or as a part
of your application can now be done by adding a `@StyleSheet` or
`@JavaScript` annotation to a `Component` or `Extension` class. Each
annotation takes a list of strings with URLs to the resources that
should be loaded on the page before the framework initializes the
client-side `Component` or `Extension`.
The URLs can either be complete absolute urls (e.g. https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js) or
relative URLs (e.g. _redbutton.css_). A relative URL is converted to a
special URL that will download the file from the Java package where the
defining class is located. This means that e.g.
`@StyleSheet({"redbutton.css"})` on the class `com.example.RedButton` will
cause the file `com/example/redbutton.css` on the classpath to be loaded
in the browser. `@JavaScript` works in exactly the same way - see
<<IntegratingAJavaScriptComponent#integrating-a-javascript-component,
Integrating a JavaScript component>> for a practical example.
[source,java]
....
@StyleSheet("redbutton.css")
public class RedButton extends NativeButton {
public RedButton(String caption) {
super(caption);
addStyleName("redButton");
}
}
....
In this simple example, the `RedButton` component just adds a `redButton`
style name to a normal `NativeButton`. _redbutton.css_ is located in the
same folder as _RedButton.java_ and has this content:
[source,css]
....
.redButton {
background-color: red;
}
....
This new mechanism makes it very easy to include style sheet or
JavaScript files with add-ons and automatically load them in the browser
when the add-on is used.
[WARNING]
.Security Warning
====
Do note that third-party JavaScript code can be dangerous
(https://www.owasp.org/index.php/3rd_Party_Javascript_Management_Cheat_Sheet),
and you should take into account the security risks of using such.
====

+ 59
- 0
documentation/articles/UsingBeanValidationToValidateInput.asciidoc Bestand weergeven

@@ -0,0 +1,59 @@
---
title: Using Bean Validation To Validate Input
order: 45
layout: page
---
[[using-bean-validation-to-validate-input]]
Using Bean Validation to validate input
---------------------------------------
Before you get started with Bean Validation you need to download a Bean
Validation implementation and add it to your project. You can find one
for instance at http://bval.apache.org/downloads.html. Just add the jars
from the lib folder to your project.
Bean Validation works as a normal validator. If you have a bean with
Bean Validation annotations, such as:
[source,java]
....
public class Person {
@Size(min = 5, max = 50)
private String name;
@Min(0)
@Max(100)
private int age;
// + constructor + setters + getters
}
....
You can create a field for the name field as you always would:
[source,java]
....
Person person = new Person("John", 26);
BeanItem<Person> item = new BeanItem<Person>(person);
TextField firstName = new TextField("First name",
item.getItemProperty("name"));
firstName.setImmediate(true);
setContent(firstName);
....
and add the bean validation as a normal validator:
[source,java]
....
firstName.addValidator(new BeanValidator(Person.class, "name"));
....
Your `firstName` field is now automatically validated based on the
annotations in your bean class. You can do the same thing for the `age`
field and you won't be able to set a value outside the valid 0-100
range.
A Bean Validation tutorial is available here:
http://docs.oracle.com/javaee/6/tutorial/doc/gircz.html

+ 2
- 1
documentation/articles/UsingGridWithInlineData.asciidoc Bestand weergeven

@@ -8,7 +8,8 @@ layout: page
= Using Grid with inline data

Instead of using a Vaadin Container as explained in
link:UsingGridWithAContainer.asciidoc[Using Grid with a Container],
<<UsingGridWithAContainer#
using-grid-with-a-container,Using Grid With a Container>>,
you can also directly add simple inline data to Grid without directly
using a Container.


+ 118
- 0
documentation/articles/UsingParametersWithViews.asciidoc Bestand weergeven

@@ -0,0 +1,118 @@
---
title: Using Parameters With Views
order: 36
layout: page
---
[[using-parameters-with-views]]
Using parameters with Views
---------------------------
When the Navigator API is in use, one can pass "parameters" to Views in
the URI fragment.
The remainder of the fragment that is left after the (longest) view name
matched is removed, is considered to be "fragment parameters". These are
passed to the View in question, which can then handle the parameter(s).
Basically: `#!viewname/parameters`.
Continuing from the basic navigation example, let's make a View that
displays a message passed as a fragment parameter:
[source,java]
....
import com.vaadin.navigator.View;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
public class MessageView extends Panel implements View {
public static final String NAME = "message";
public MessageView() {
super(new VerticalLayout());
setCaption("Messages");
}
@Override
public void enter(ViewChangeEvent event) {
if(event.getParameters() != null){
// split at "/", add each part as a label
String[] msgs = event.getParameters().split("/");
for (String msg : msgs) {
((Layout)getContent()).addComponent(new Label(msg));
}
}
}
}
....
Let's register `MessageView` along with the other Views:
[source,java]
....
import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.Navigator.SimpleViewDisplay;
import com.vaadin.server.Page;
import com.vaadin.server.WrappedRequest;
import com.vaadin.ui.UI;
public class NavigationtestUI extends UI {
@Override
public void init(VaadinRequest request) {
// Create Navigator, make it control the ViewDisplay
Navigator navigator = new Navigator(this, this);
// Add some Views
navigator.addView(MainView.NAME, new MainView()); // no fragment
// #!count will be a new instance each time we navigate to it, counts:
navigator.addView(CountView.NAME, CountView.class);
// #!message adds a label with whatever it receives as a parameter
navigator.addView(MessageView.NAME, new MessageView());
}
}
....
Finally, we'll add two labels to the MainView so we don't have to type
in the browsers address-bar to try it out:
[source,java]
....
import com.vaadin.navigator.View;
import com.vaadin.server.ExternalResource;
import com.vaadin.ui.Link;
import com.vaadin.ui.Panel;
public class MainView extends Panel implements View {
public static final String NAME = "";
public MainView() {
VerticalLayout layout = new VerticalLayout();
Link lnk = new Link("Count", new ExternalResource("#!" + CountView.NAME));
layout.addComponent(lnk);
lnk = new Link("Message: Hello", new ExternalResource("#!"
+ MessageView.NAME + "/Hello"));
layout.addComponent(lnk);
lnk = new Link("Message: Bye", new ExternalResource("#!"
+ MessageView.NAME + "/Bye/Goodbye"));
layout.addComponent(lnk);
setContent(layout);
}
@Override
public void enter(ViewChangeEvent event) {
}
}
....
Simple! Let's just conclude by noting that it's usually a good idea to
make sure the parameters are URI encoded, or the browser might
disapprove.

+ 114
- 0
documentation/articles/UsingRPCFromJavaScript.asciidoc Bestand weergeven

@@ -0,0 +1,114 @@
---
title: Using RPC From JavaScript
order: 42
layout: page
---

[[using-rpc-from-javascript]]
Using RPC from JavaScript
-------------------------

This tutorial continues where
<<IntegratingAJavaScriptComponent#integrating-a-javascript-component,
Integrating a JavaScript component>> ended. We will now add RPC
functionality to the JavaScript Flot component. RPC can be used in the
same way as with ordinary GWT components.

We will add RPC from the client to the server when the user clicks a
data point in the graph and RPC from server to client for highlighting a
data point in the graph. For each of these, we define an RPC interface.
Each interface has one method that takes a data series index and the
index of a point in that series. As with the shared state, the GWT code
doesn't need to know about these interfaces and it's thus not required
to put them in the widgetset's client package and to recompile the
widgetset after making changes.

[source,java]
....
public interface FlotClickRpc extends ServerRpc {
public void onPlotClick(int seriesIndex, int dataIndex);
}

public interface FlotHighlightRpc extends ClientRpc {
public void highlight(int seriesIndex, int dataIndex);
}
....

The server side code for this looks the same as if the client-side
connector was implemented using GWT. An RPC implementation is registered
in the constructor.

[source,java]
....
public Flot() {
registerRpc(new FlotClickRpc() {
public void onPlotClick(int seriesIndex, int dataIndex) {
Notification.show("Clicked on [" + seriesIndex + ", "
+ dataIndex + "]");
}
});
}
....

Highlighting is implemented by getting an RPC proxy object and invoking
the method.

[source,java]
....
public void highlight(int seriesIndex, int dataIndex) {
getRpcProxy(FlotHighlightRpc.class).highlight(seriesIndex, dataIndex);
}
....

The JavaScript connector uses similar functions from the connector
wrapper: `this.getRpcProxy()` for getting an object with functions that
will call the server-side counterpart and `this.registerRpc()` for
registering an object with functions that will be called from the
server. Because of the dynamic nature of JavaScript, you don't need to
use the interface names if you don't want to - all methods from all RPC
interfaces registered for the connector on the server will be available
in the RPC proxy object and any RPC method invoked from the server will
be called if present in the RPC object you registered. If a connector
uses multiple RPC interfaces that define methods with conflicting names,
you can still use the interface names to distinguish between interfaces.

We need to make some small adjustments to the connector JavaScript to
make it work with the way Flot processes events. Because a new Flot
object is created each time the `onStateChange` function is called, we
need to store a reference to the current object that we can use for
applying the highlight. We also need to pass a third parameter to
`$.plot` to make the graph area clickable. Aside from those changes, we
just call the function on the RPC proxy in a click listener and register
an RPC implementation with a function that highlights a point.

[source,javascript]
....
window.com_example_Flot = function() {
var element = $(this.getElement());
var rpcProxy = this.getRpcProxy();
var flot;

this.onStateChange = function() {
flot = $.plot(element, this.getState().series, {grid: {clickable: true}});
}

element.bind('plotclick', function(event, point, item) {
if (item) {
rpcProxy.onPlotClick(item.seriesIndex, item.dataIndex);
}
});

this.registerRpc({
highlight: function(seriesIndex, dataIndex) {
if (flot) {
flot.highlight(seriesIndex, dataIndex);
}
}
});
}
....

When the normal Vaadin RPC is used with JavaScript connectors, you can
use the same server-side code that you would use with a GWT connector
and the client-side code uses the same concepts as for GWT connectors,
just translated to fit into the world of JavaScript.

+ 154
- 0
documentation/articles/UsingRPCToSendEventsToTheClient.asciidoc Bestand weergeven

@@ -0,0 +1,154 @@
---
title: Using RPC To Send Events To The Client
order: 56
layout: page
---
[[using-rpc-to-send-events-to-the-client]]
Using RPC to send events to the client
--------------------------------------
An RPC mechanism can be used to communicate from the server to the
client. In effect, the server-side component can call methods that are
executed by the client-side connector. As opposed to shared state
(discussed in a separate article), no information is automatically
re-transmitted when the client-side state is lost (e.g when a browser
reload is invoked).
Whether shared state or RPC is appropriate depends on the nature of the
data being transmitted, but if the information transmitted needs to be
retained on the client over a page refresh, you should probably use
shared state. You'll probably find shared state more appropriate in most
cases, and server-client RPC extremely useful in a few cases.
To set up server-client RPC, we need to create an interface extending
`ClientRpc` for the RPC methods, then register an implementation of the
RPC interface in the client-side connector, and call the method(s) via a
proxy on the server. This is the reverse of the server-client RPC
described in a separate article.
We'll create *MyComponentClientRpc* in the client package:
[source,java]
....
package com.example.mycomponent.client;
import com.vaadin.client.communication.ClientRpc;
public interface MyComponentClientRpc extends ClientRpc {
public void alert(String message);
}
....
Again, note that the RPC methods can not return anything, but can take
multiple arguments.
In *MyComponentConnector* we register the RPC implementation in the
constructor. This time we'll create the implementation inline:
[source,java]
....
package com.example.mycomponent.client;
// imports removed for clarity
@Connect(MyComponent.class)
public class MyComponentConnector extends AbstractComponentConnector {
MyComponentServerRpc rpc = RpcProxy
.create(MyComponentServerRpc.class, this);
public MyComponentConnector() {
registerRpc(MyComponentClientRpc.class, new MyComponentClientRpc() {
public void alert(String message) {
Window.alert(message);
}
});
/* The rest of the code remains unchanged:
getWidget().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
final MouseEventDetails mouseDetails = MouseEventDetailsBuilder
.buildMouseEventDetails(event.getNativeEvent(),
getWidget().getElement());
rpc.clicked(mouseDetails);
}
});
}
@Override
protected Widget createWidget() {
return GWT.create(MyComponentWidget.class);
}
@Override
public MyComponentWidget getWidget() {
return (MyComponentWidget) super.getWidget();
}
@Override
public MyComponentState getState() {
return (MyComponentState) super.getState();
}
@OnStateChange("text")
void updateText() {
getWidget().setText(getState().text);
}
*/
}
....
(`MyComponentServerRpc` is introduced in
<<SendingEventsFromTheClientToTheServerUsingRPC#
sending-events-from-the-client-to-the-server-using-RPC,
Sending events from the client to the server using RPC>>. `Window` here is
`com.google.gwt.user.client.Window`, _not_ `com.vaadin.ui.Window`.)
Finally, in *MyComponent* we use the RPC via a proxy:
[source,java]
....
import com.vaadin.ui.AbstractComponent;
public class MyComponent extends AbstractComponent {
private int clickCount = 0;
private MyComponentServerRpc rpc = new MyComponentServerRpc() {
public void clicked(MouseEventDetails mouseDetails) {
clickCount++;
// nag every 5:th click
if (clickCount % 5 == 0) {
getRpcProxy(MyComponentClientRpc.class).alert(
"Ok, that's enough!");
}
setText("You have clicked " + clickCount + " times");
}
};
/* Unchanged code follows:
public MyComponent() {
registerRpc(rpc);
}
@Override
public MyComponentState getState() {
return (MyComponentState) super.getState();
}
public void setText(String text) {
getState().text = text;
}
public String getText() {
return getState().text;
}
*/
}
....
That is: every fifth time the label is clicked, we get the RPC proxy by
calling `getRpcProxy()` and call our `alert()` method with a message to
send to the client.
Compile the widgetset, and you're all set to try out server-client RPC.

+ 1
- 1
documentation/articles/Vaadin7HierarchicalContainerAndTreeComponentExampleWithLiferayOrganizationService.asciidoc Bestand weergeven

@@ -12,7 +12,7 @@ user belongs to in a Hierarchical Tree.  I used Vaadin's tree and
hierarchical container components along with information from Vaadin's
book of examples to create the code below (http://demo.vaadin.com/book-examples-vaadin7/book#component.tree.itemstylegenerator).

See link:img/DmoOrgTreeUI.java[DmoOrgTreeUI.java] for full source code.
See <<img/DmoOrgTreeUI.java,DmoOrgTreeUI.java>> for full source code.

[source,java]
....

+ 226
- 0
documentation/articles/ViewChangeConfirmations.asciidoc Bestand weergeven

@@ -0,0 +1,226 @@
---
title: View Change Confirmations
order: 54
layout: page
---
[[view-change-confirmations]]
View change confirmations
-------------------------
The `Navigator` API provides ways to prevent the user from navigating away
from a view in some cases, usually when the view has some unsaved
changes. We'll make a simple example that does just that (and only
that).
We'll create our simple `SettingsView` later, because it has the actual
meat of this example. Let's set up the basic stuff first, our UI and our
`MainView`.
UI:
[source,java]
....
import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.UI;
public class NavigationtestUI extends UI {
@Override
public void init(VaadinRequest request) {
// Create Navigator, make it control the ViewDisplay
Navigator navigator = new Navigator(this, this);
// no fragment for main view
navigator.addView(MainView.NAME, new MainView(navigator));
// #!settings
navigator.addView(SettingsView.NAME, new SettingsView(navigator));
}
}
....
Minimalistic. The only thing to notice is that we pass the `Navigator` to
the `SettingsView`, so that it can attach a listener and trigger
navigation. More on that when we actually create the `SettingsView`.
Let's do the `MainView`:
[source,java]
....
import com.vaadin.navigator.View;
import com.vaadin.server.ExternalResource;
import com.vaadin.ui.Link;
import com.vaadin.ui.Panel;
public class MainView extends Panel implements View {
public static final String NAME = "";
public MainView(final Navigator navigator) {
Link lnk = new Link("Settings", new ExternalResource("#!"
+ SettingsView.NAME));
setContent(lnk);
}
@Override
public void enter(ViewChangeEvent event) {
}
}
....
Yeah, really nothing to see here - we just create this so we can
navigate back and forth when trying it out.
Now let's do the SettingsView, which has some more things going on in
order to make it fairly complete:
[source,java]
....
import java.util.Date;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.navigator.Navigator;
import com.vaadin.navigator.View;
import com.vaadin.navigator.ViewChangeListener;
import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.DateField;
import com.vaadin.ui.InlineDateField;
import com.vaadin.ui.Layout;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Notification.Type;
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.themes.Reindeer;
public class SettingsView extends Panel implements View {
public static String NAME = "settings";
Navigator navigator;
DateField date;
Button apply;
Button cancel;
String pendingViewAndParameters = null;
public SettingsView(final Navigator navigator) {
this.navigator = navigator;
Layout layout = new VerticalLayout();
date = new InlineDateField("Birth date");
date.setImmediate(true);
layout.addComponent(date);
// pretend we have a datasource:
date.setPropertyDataSource(new ObjectProperty<Date>(new Date()));
date.setBuffered(true);
// show buttons when date is changed
date.addValueChangeListener(new ValueChangeListener() {
public void valueChange(ValueChangeEvent event) {
hideOrShowButtons();
pendingViewAndParameters = null;
}
});
// commit the TextField changes when "Save" is clicked
apply = new Button("Apply", new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
date.commit();
hideOrShowButtons();
processPendingView();
}
});
layout.addComponent(apply);
// Discard the TextField changes when "Cancel" is clicked
cancel = new Button("Cancel", new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
date.discard();
hideOrShowButtons();
processPendingView();
}
});
cancel.setStyleName(Reindeer.BUTTON_LINK);
layout.addComponent(cancel);
// attach a listener so that we'll get asked isViewChangeAllowed?
navigator.addViewChangeListener(new ViewChangeListener() {
public boolean beforeViewChange(ViewChangeEvent event) {
if (event.getOldView() == SettingsView.this
&& date.isModified()) {
// save the View where the user intended to go
pendingViewAndParameters = event.getViewName();
if (event.getParameters() != null) {
pendingViewAndParameters += "/";
pendingViewAndParameters += event
.getParameters();
}
// Prompt the user to save or cancel if the name is changed
Notification.show("Please apply or cancel your changes",
Type.WARNING_MESSAGE);
return false;
} else {
return true;
}
}
public void afterViewChange(ViewChangeEvent event) {
pendingViewAndParameters = null;
}
});
setContent(layout);
}
// Hide or show buttons depending on whether date is modified or not
private void hideOrShowButtons() {
apply.setVisible(date.isModified());
cancel.setVisible(date.isModified());
}
// if there is a pending view change, do it now
private void processPendingView() {
if (pendingViewAndParameters != null) {
navigator.navigateTo(pendingViewAndParameters);
pendingViewAndParameters = null;
}
}
@Override
public void enter(ViewChangeEvent event) {
hideOrShowButtons();
}
}
....
First we set up a `DateField` with buffering and a (dummy) datasource to
make this work more as a real application would. With buffering on, the
value (date in this case) can be changed, but it will not be written to
the datasource before we `commit()`, which is what the Save -button does.
The Cancel -button does `discard()` on the DateField, which returns the
field to its unmodified state.
The buttons do not need to be shown if nothing has changed, so we add a
`ValueChangeListener` to the `DateField` for that purpose.
But the main thing that we're trying to demonstrate here happens in the
`ViewChangeListener` that we attach to the `Navigator`. There, if we're
about to change _away_ from our settings _and_ the date is changed but
_not_ saved, we'll make note of where the user wanted to go, but cancel
that navigation and prompt the user to save or cancel the changes.
When the user saves or cancels changes, we also check if the user
previously tried to navigate away form the page, and sends him on his
way if that is the case.
That is basically all there is to this. You'll notice we try to
carefully clear or set the 'pending view' and hide/show the buttons at
the right places to make the user happy, other than that this is pretty
straightforward.

+ 178
- 0
documentation/articles/WidgetStylingUsingOnlyCSS.asciidoc Bestand weergeven

@@ -0,0 +1,178 @@
---
title: Widget Styling Using Only CSS
order: 52
layout: page
---
[[widget-styling-using-only-css]]
Widget styling using only CSS
-----------------------------
The preferred way of styling your widget is to only use static CSS
included in the theme's styles.css file. For information on how to
create custom themes, please refer to
https://vaadin.com/book/-/page/themes.creating.html. Your component can
be styled using the CSS class names that are defined to the widget using
`setStyleName`.
Normal styling of components works in the same way as any styling using
CSS, but there are some special features to pay attention to when Vaadin
7 is used.
[[some-sizing-theory]]
Some sizing theory
~~~~~~~~~~~~~~~~~~
All Vaadin 7 components get the CSS class v-widget which sets the
box-sizing to border-box. This causes borders and paddings to be
considered when the browser calculates the component's size. This means
that e.g. a component with padding: 5px and width: 100% inside a 200px
wide slot will fill the slot without any overflow because the inner
width of the component will be calculated to 190px by the browser.
The Vaadin 7 server side API allows setting the size of the component in
three different ways:
* Undefined size, set e.g. using `setWidth(null)`, means that the
component's size should have it's default size that might vary depending
on its content.
* Relative size, set e.g. using `setWidth("100%")` means that the
component's size is determined by the size and settings of the
component's parent.
* Fixed size, set e.g. using `setWidth("250px")` or `setWidth("10em")` means
that the component's size is fixed, so that the parent doesn't affect
the size and neither does the component's content.
The three different ways of setting the size means that a component
should both support having its own natural size and filling the
allocated space depending on how the size is set. This usually means
that the main area of the component should adjust based on the settings.
[[a-simple-sample]]
A simple sample
~~~~~~~~~~~~~~~
Consider e.g. a simple date picker component with a text field where a
date can be entered and where the currently selected is displayed and a
button that is used to open a calendar view where a date can be picked
using the mouse.
[source,java]
....
public class MyPickerWidget extends ComplexPanel {
public static final String CLASSNAME = "mypicker";
private final TextBox textBox = new TextBox();
private final PushButton button = new PushButton("...");
public MyPickerWidget() {
setElement(Document.get().createDivElement());
setStylePrimaryName(CLASSNAME);
textBox.setStylePrimaryName(CLASSNAME + "-field");
button.setStylePrimaryName(CLASSNAME + "-button");
add(textBox, getElement());
add(button, getElement());
button.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
Window.alert("Calendar picker not yet supported!");
}
});
}
}
....
We then add this basic styling to the theme CSS file
[source,scss]
....
.mypicker {
white-space: nowrap;
}
.mypicker-button {
display: inline-block;
border: 1px solid black;
padding: 3px;
width: 15px;
text-align: center;
}
....
`display: inline-block` makes the button continue on the same line as the
text field, placing it to the right of the field. We also add
`white-space: nowrap` to the main div element to ensure the button is not
wrapped to the next row. Finally, there is some padding and a border to
make the button look more like a real button.
[[using-available-space]]
Using available space
^^^^^^^^^^^^^^^^^^^^^
This simple layout works well as long as the component's has it's
default undefined width. Changing the width from the server does however
not have any visible effect because only the size of the main div is
changed. If the component is made smaller, the contents goes beyond the
size of the element (this can be verified by adding `overflow: hidden;` to
`.mypicker`) and if it gets larger the extra space is just left as empty
space to the right of the button.
The first step towards making the size adjust is to make the text field
adjust to the main div element's width whenever the width is something
else then than undefined. In these situations, Vaadin 7 adds a
`v-has-width` class to the component's main element (`v-has-height` added
when the height is not undefined).
[source,scss]
....
.mypicker.v-has-width > .mypicker-field {
width: 100%;
}
....
With this additional CSS, the text field directly inside a picker that
has a defined width gets full width.
[[making-room-for-the-button-again]]
Making room for the button again
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
We're however not done yet. Setting the width of the text field to 100%
makes it as wide as the main div is, which means that the button goes
outside the main div. This can be verified using the DOM inspector in
your browser or by setting `overflow: hidden` to the style for `mypicker`.
To reserve space for the button, we can add some padding to the right
edge of the main div element. This does however cause the padding space
to remain unused if the component size is undefined. To compensate for
this, negative margin can be added to the right edge of the button,
effectively reducing its occupied size to 0px.
Finally, we need to use `box-sizing: border-box` to make the field's
borders and paddings be included in the 100% width.
The full CSS for the sample component:
[source,scss]
....
.mypicker {
white-space: nowrap;
padding-right: 23px;
}
.mypicker-button {
display: inline-block;
border: 1px solid black;
padding: 3px;
width: 15px;
text-align: center;
margin-right: -23px;
}
.mypicker.v-has-width > .mypicker-field {
width: 100%;
}
.mypicker-field {
-moz-box-sizing: border-box;
-webkit-boz-sizing: border-box;
box-sizing: border-box;
}
....

+ 27
- 4
documentation/articles/contents.asciidoc Bestand weergeven

@@ -1,11 +1,11 @@
---
--
title: Contents
order: 1
layout: page
---
--
= Community articles for Vaadin 7
[discrete]
== Articles
- <<LazyQueryContainer#lazy-query-container,"Lazy query container">>
@@ -42,3 +42,26 @@ layout: page
- <<UsingGridWithInlineData#using-grid-with-inline-data,"Using Grid with inline data">>
- <<MigratingFromVaadin6ToVaadin7#migrating-from-vaadin-6-to-vaadin-7,"Migrating from Vaadin 6 to Vaadin 7">>
- <<MigratingFromVaadin7%2E0ToVaadin7%2E1#migrating-from-vaadin-7.0-to-vaadin-7.1,"Migrating from Vaadin 7.0 to Vaadin 7.1">>
- <<UsingParametersWithViews#using-parameters-with-views,"Using parameters with views">>
- <<SendingEventsFromTheClientToTheServerUsingRPC#sending-events-from-the-client-to-the-server-using-RPC,"Sending events from the client to the server using RPC">>
- <<IntegratingAJavaScriptComponent#integrating-a-javascript-component,"Integrating a JavaScript component">>
- <<IntegratingAJavaScriptLibraryAsAnExtension#integrating-a-javascript-library-as-an-extension,"Integrating a JavaScript library as an extension">>
- <<UsingAJavaScriptLibraryOrAStyleSheetInAnAddOn#using-a-javascript-library-or-a-style-sheet-in-an-addon,"Using a JavaScript library or a style sheet in an add-on">>
- <<ExposingServerSideAPIToJavaScript#exposing-server-side-api-to-javascript,"Exposing Server Side API to JavaScript">>
- <<UsingRPCFromJavaScript#using-rpc-from-javascript,"Using RPC from JavaScript">>
- <<CustomizingTheStartupPageInAnApplication#customizing-the-startup-page-in-an-application,"Customizing the startup page in an application">>
- <<OptimizingTheWidgetSet#optimizing-the-widget-set,"Optimizing the widget set">>
- <<UsingBeanValidationToValidateInput#using-bean-validation-to-validate-input,"Using Bean Validation to validate input">>
- <<AccessControlForViews#access-control-for-views,"Access control for views">>
- <<CustomizingComponentThemeWithSass#customizing-component-theme-with-sass,"Customizing component theme with Sass">>
- <<CreatingASimpleComponent#creating-a-simple-component,"Creating a simple component">>
- <<CreatingASimpleComponentContainer#creating-a-simple-component-container,"Creating a simple component container">>
- <<CreatingAUIExtension#creating-a-ui-extension,"Creating a UI extension">>
- <<CreatingAComponentExtension#creating-a-component-extension,"Creating a component extension">>
- <<WidgetStylingUsingOnlyCSS#widget-styling-using-only-css,"Widget styling using only CSS">>
- <<CreatingAThemeUsingSass#creating-a-theme-using-sass,"Creating a theme using Sass">>
- <<ViewChangeConfirmations#view-change-confirmations,"View change confirmations">>
- <<CreatingABookmarkableApplicationWithBackButtonSupport#creating-a-bookmarkable-application-with-back-button-support,"Creating a bookmarkable application with back button support">>
- <<UsingRPCToSendEventsToTheClient#using-rpc-to-send-events-to-the-client,"Using RPC to send events to the client">>

Laden…
Annuleren
Opslaan