Browse Source

Merge branch 'master' into wip-java-10-compat-2

wip-java-10-compat-2
Sun Zhe 5 years ago
parent
commit
29fff54bac
No account linked to committer's email address
100 changed files with 1488 additions and 818 deletions
  1. 1
    1
      .github/stale.yml
  2. 4
    0
      CONTRIBUTING.md
  3. 25
    21
      README-TESTS.md
  4. 1
    1
      README.md
  5. 1
    1
      all/pom.xml
  6. 16
    17
      all/src/main/templates/release-notes.html
  7. 5
    5
      bom/pom.xml
  8. 1
    1
      client-compiled/pom.xml
  9. 6
    23
      client-compiled/src/main/java/com/vaadin/osgi/widgetset/DefaultWidgetsetContribution.java
  10. 1
    1
      client-compiler/pom.xml
  11. 1
    1
      client/pom.xml
  12. 1
    6
      client/src/main/java/com/vaadin/client/ComponentConnector.java
  13. 28
    0
      client/src/main/java/com/vaadin/client/HasWidget.java
  14. 2
    0
      client/src/main/java/com/vaadin/client/communication/Heartbeat.java
  15. 14
    0
      client/src/main/java/com/vaadin/client/communication/XhrConnection.java
  16. 60
    1
      client/src/main/java/com/vaadin/client/connectors/grid/ComponentRendererConnector.java
  17. 16
    3
      client/src/main/java/com/vaadin/client/connectors/grid/EditorConnector.java
  18. 19
    0
      client/src/main/java/com/vaadin/client/connectors/grid/GridDropTargetConnector.java
  19. 3
    1
      client/src/main/java/com/vaadin/client/data/AbstractRemoteDataSource.java
  20. 2
    2
      client/src/main/java/com/vaadin/client/extensions/AbstractEventTriggerExtensionConnector.java
  21. 20
    6
      client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java
  22. 9
    0
      client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java
  23. 36
    3
      client/src/main/java/com/vaadin/client/ui/VCheckBox.java
  24. 14
    1
      client/src/main/java/com/vaadin/client/ui/VCheckBoxGroup.java
  25. 4
    0
      client/src/main/java/com/vaadin/client/ui/VComboBox.java
  26. 3
    3
      client/src/main/java/com/vaadin/client/ui/VDateTimeCalendarPanel.java
  27. 61
    15
      client/src/main/java/com/vaadin/client/ui/VMenuBar.java
  28. 1
    21
      client/src/main/java/com/vaadin/client/ui/VNativeButton.java
  29. 25
    1
      client/src/main/java/com/vaadin/client/ui/VNativeSelect.java
  30. 11
    9
      client/src/main/java/com/vaadin/client/ui/VOverlay.java
  31. 128
    15
      client/src/main/java/com/vaadin/client/ui/VTabsheet.java
  32. 9
    0
      client/src/main/java/com/vaadin/client/ui/VUpload.java
  33. 45
    0
      client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
  34. 5
    1
      client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java
  35. 106
    89
      client/src/main/java/com/vaadin/client/ui/menubar/MenuBarConnector.java
  36. 24
    3
      client/src/main/java/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java
  37. 4
    0
      client/src/main/java/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java
  38. 48
    37
      client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java
  39. 8
    0
      client/src/main/java/com/vaadin/client/widget/escalator/RowContainer.java
  40. 4
    1
      client/src/main/java/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java
  41. 2
    0
      client/src/main/java/com/vaadin/client/widgets/ChildFocusAwareFlowPanel.java
  42. 36
    8
      client/src/main/java/com/vaadin/client/widgets/Escalator.java
  43. 21
    4
      client/src/main/java/com/vaadin/client/widgets/Grid.java
  44. 1
    1
      client/src/main/resources/com/vaadin/DefaultWidgetSet.gwt.xml
  45. 1
    1
      client/src/main/resources/com/vaadin/Vaadin.gwt.xml
  46. 1
    1
      compatibility-client-compiled/pom.xml
  47. 6
    23
      compatibility-client-compiled/src/main/java/com/vaadin/osgi/compatibility/widgetset/CompatibilityWidgetsetContribution.java
  48. 1
    1
      compatibility-client/pom.xml
  49. 58
    38
      compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java
  50. 65
    4
      compatibility-client/src/main/java/com/vaadin/v7/client/ui/VFilterSelect.java
  51. 16
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/RowContainer.java
  52. 84
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/events/SpacerVisibilityChangedEvent.java
  53. 36
    0
      compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/events/SpacerVisibilityChangedHandler.java
  54. 5
    16
      compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Escalator.java
  55. 225
    127
      compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Grid.java
  56. 1
    1
      compatibility-client/src/main/resources/com/vaadin/v7/Vaadin7WidgetSet.gwt.xml
  57. 1
    1
      compatibility-server-gae/pom.xml
  58. 13
    1
      compatibility-server/pom.xml
  59. 1
    1
      compatibility-server/src/main/java/com/vaadin/v7/data/util/AbstractInMemoryContainer.java
  60. 2
    1
      compatibility-server/src/main/java/com/vaadin/v7/ui/AbstractField.java
  61. 5
    0
      compatibility-server/src/test/java/com/vaadin/v7/tests/server/ClassesSerializableTest.java
  62. 1
    1
      compatibility-shared/pom.xml
  63. 0
    189
      compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/grid/DetailsConnectorChange.java
  64. 1
    1
      compatibility-themes/pom.xml
  65. 15
    23
      compatibility-themes/src/main/java/com/vaadin/osgi/compatibility/themes/LegacyThemeContributions.java
  66. 5
    6
      documentation/addons/addons-cval.asciidoc
  67. 5
    5
      documentation/addons/addons-maven.asciidoc
  68. BIN
      documentation/addons/img/cval-pro-licenses-3.png
  69. BIN
      documentation/addons/img/cval-pro-licenses-4.png
  70. BIN
      documentation/addons/img/cval-pro-licenses-code-2.png
  71. BIN
      documentation/addons/img/cval-pro-licenses-code.png
  72. 2
    2
      documentation/advanced/advanced-dragndrop.asciidoc
  73. 5
    0
      documentation/advanced/advanced-osgi.asciidoc
  74. 6
    7
      documentation/advanced/advanced-shortcuts.asciidoc
  75. 26
    2
      documentation/articles/LettingTheUserDownloadAFile.asciidoc
  76. 1
    1
      documentation/articles/SendingEmailFromJavaApplications.asciidoc
  77. 2
    2
      documentation/articles/UsingRPCFromJavaScript.asciidoc
  78. 1
    1
      documentation/articles/VaadinSpringTips.asciidoc
  79. 2
    2
      documentation/clientside/clientside-module.asciidoc
  80. 2
    2
      documentation/clientsideapp/clientsideapp-entrypoint.asciidoc
  81. 1
    1
      documentation/clientsideapp/clientsideapp-loading.asciidoc
  82. 1
    1
      documentation/clientsideapp/clientsideapp-overview.asciidoc
  83. 3
    3
      documentation/clientsidewidgets/clientsidewidgets-grid.asciidoc
  84. 1
    1
      documentation/clientsidewidgets/clientsidewidgets-vaadin.asciidoc
  85. 1
    2
      documentation/components/components-checkbox.asciidoc
  86. 11
    10
      documentation/components/components-grid.asciidoc
  87. 1
    1
      documentation/components/components-treegrid.asciidoc
  88. 5
    0
      documentation/components/components-twincolselect.asciidoc
  89. 1
    1
      documentation/gwt/gwt-connector.asciidoc
  90. 3
    3
      documentation/gwt/gwt-extension.asciidoc
  91. 3
    3
      documentation/gwt/gwt-rpc.asciidoc
  92. 1
    1
      documentation/gwt/gwt-server-side.asciidoc
  93. 14
    14
      documentation/gwt/gwt-shared-state.asciidoc
  94. 1
    1
      documentation/gwt/gwt-styling.asciidoc
  95. 9
    9
      documentation/portal/portal-osgi.asciidoc
  96. 2
    1
      documentation/portal/portal-ui.asciidoc
  97. 1
    1
      documentation/tutorial.adoc
  98. 1
    1
      liferay-integration/pom.xml
  99. 1
    1
      liferay/pom.xml
  100. 0
    0
      osgi-integration/pom.xml

+ 1
- 1
.github/stale.yml View File

@@ -13,7 +13,7 @@ closeComment: >
markComment: |
Hello there!
It looks like this issue hasn't progressed lately. There are so many issues that we just can't deal them all within a reasonable timeframe.
We are sorry that this issue hasn't progressed lately. We are prioritizing issues by severity and the number of customers we expect are experiencing this and haven't gotten around to fix this issue yet.
There are a couple of things you could help to get things rolling on this issue (this is an automated message, so expect that some of these are already in use):

+ 4
- 0
CONTRIBUTING.md View File

@@ -144,6 +144,10 @@ You should receive comments within a week or so; if that does not happen, make s

# Submitting the patches

## Source code auto-formatting

Before submitting changes to Github, run the command `mvn process-sources` from project's root. This maven goal automatically formats source code according to Vaadin standards. The same goal is run automatically if you invoke `mvn install` or `mvn compile`.

## Creating a pull request in GitHub

All our projects accept contributions as GitHub pull requests. The first time you create a pull request, you will be asked to electronically sign a contribution agreement.

+ 25
- 21
README-TESTS.md View File

@@ -2,30 +2,30 @@
## Project setup
The project currently supports running TestBench 3+ (java) tests. Each test consists of a Vaadin UI class and a TestBench script/java test.

All test UI classes go into uitest/src. These files are automatically packaged into a war file which is deployed to a Jetty server during the build process so that tests can open and interact with the UI:s. For development purposes, the Jetty server can be started in Eclipse, see running tests in Eclipse.
All test UI classes go into `uitest/src`. These files are automatically packaged into a war file which is deployed to a Jetty server during the build process so that tests can open and interact with the UI:s. For development purposes, the Jetty server can be started in Eclipse, see running tests in Eclipse.

The project is setup so that /run is mapped to a specialized servlet which allows you to add the UI you want to test to the URL, e.g. http://localhost:8888/run/com.vaadin.tests.component.label.LabelModes or just http://localhost:8888/run/LabelModes if there are no multiple classes named LabelModes. Because of caching, the ?restartApplication parameter is needed after the first run if you want to run multiple test classes.
The project is setup so that `/run` is mapped to a specialized servlet which allows you to add the UI you want to test to the URL, e.g. http://localhost:8888/run/com.vaadin.tests.component.label.LabelModes or just http://localhost:8888/run/LabelModes if there are no multiple classes named LabelModes. Because of caching, the ?restartApplication parameter is needed after the first run if you want to run multiple test classes.

## Creating a new test
Creating a new test involves two steps: Creating a test UI (typically this should be provided in the ticket) and creating a TestBench test for the UI.

## Creating a new test UI
Test UIs are created inside the uitest/src folder in the com.vaadin.tests package. For tests for a given component, use the com.vaadin.tests.components.<component> package. For other features, use a suitable existing com.vaadin.tests.<something> package or create a new one if no suitable exists.
Test UIs are created inside the `uitest/src` folder in the `com.vaadin.tests` package. For tests for a given component, use the `com.vaadin.tests.components.<component>` package. For other features, use a suitable existing com.vaadin.tests.<something> package or create a new one if no suitable exists.

The test should be named according to what it tests, e.g. EnsureFormTooltipWorks. Names should not refer to a ticket, e.g. Ticket1123 will automatically be rejected during code review as it is non-descriptive.

There are a couple of helper UI super classes which you can use for the test. You should never extend UI directly:
* AbstractTestUI
* `AbstractTestUI`
* Automatically sets up a VerticalLayout with a description label on the top. Use addComponent() to add components to the layout
* Supports ?transport=websocket/streaming/xhr parameter for setting push mode. This is for testing core push functionality, typically you should just add @Push to your test UI
* AbstractTestUIWithLog
* `AbstractTestUIWithLog`
* AbstractTestUI but adds a log at the top to which you can add rows using log(String). Handy for printing state information which the TB test can assert reliably.
* ~~AbstractTestCase, TestBase~~
* Old base classes for tests. Don’t use for any new tests. Extends LegacyApplication.
* AbstractComponentTest, AbstractFieldTest, ...
* `AbstractComponentTest`, `AbstractFieldTest`, ...
* Base classes for generic component tests. Generates test which have a menu on the top containing options for configuring the component. Classes follow the same component hierarchy as Vaadin component classes and this way automatically gets menu items for setting features the parent class supports.
* Gotcha: If you add a new feature to a menu you need to run and possibly (probably) fix all TB tests which use the class as they will click on the wrong item (fixable by implementing [http://dev.vaadin.com/ticket/11307](http://dev.vaadin.com/ticket/11307))

[Note] `AbstractTestCase` and `TestBase` are old base classes for tests. Don't use them for any new tests. They extend `LegacyApplication` which is a deprecated class.

## Creating a TestBench test for a UI
All new test for the projects must be created as TestBench3+ tests
### Test class naming
@@ -33,10 +33,10 @@ TestBench 3+ tests usually follow a naming convention which automatically maps t

### Super class
There are a couple of super classes you can use for a TB3+ test:
* MultiBrowserTest
* `MultiBrowserTest`
* Ensures the test is run on the browsers we support automatically
* **This is what you typically should use**
* WebsocketTest
* `WebsocketTest`
* Run only on browsers which supports websockets

### Creating the test
@@ -46,11 +46,11 @@ The actual test is one method in the test class created for the given UI. The me
public void testLabelModes() throws Exception {


“@Test” is needed for it to be run at all.
`@Test` is needed for it to be run at all.

“throws Exception” should usually be added to avoid catching exceptions inside the test, as most often an exception means the test has failed. Unhandled exceptions will always fail the test; if you use checked exceptions, you'll need to handle them somehow or decide they're automatically failures on exception.
`throws Exception` should usually be added to avoid catching exceptions inside the test, as most often an exception means the test has failed. Unhandled exceptions will always fail the test; if you use checked exceptions, you'll need to handle them somehow or decide they're automatically failures on exception.

The beginning of the test should request the UI using openTestURL();
The beginning of the test should request the UI using `openTestURL()`;

public void testLabelModes() throws Exception {
// Causes the test to be opened with the debug console open. Typically not needed
@@ -97,15 +97,15 @@ Use ids in your UI class. Define the IDs as constants in the UI class. Use the c

## Running the DevelopmentServerLauncher

The Jetty included in the project can be started in Eclipse by running the “Development Server (Vaadin)” launch configuration in /eclipse (right click -> Debug as -> Development Server (Vaadin) ). This deploys all the tests to localhost:8888 (runs on port 8888, don’t change that unless you want problems). Use /run/<uiclass> to open a test.
The Jetty included in the project can be started in Eclipse by running the “Development Server (Vaadin)” launch configuration in `/eclipse` (right click -> Debug as -> Development Server (Vaadin) ). This deploys all the tests to `localhost:8888` (runs on port 8888, don’t change that unless you want problems). Use `/run/<uiclass>` to open a test.

The DevelopmentServerLauncher has a built-in feature which ensures only one instance can be running at a time. There is therefore no need to first stop the old and and then start a new one. Start the server and the old one will be killed automatically.
## Setup before running any tests in Eclipse

Before running any tests in Eclipse you need to
1. copy uitest/eclipse-run-selected-test.properties to work/eclipse-run-selected-test.properties
2. edit work/eclipse-run-selected-test.properties
1. Define com.vaadin.testbench.screenshot.directory as the directory where you checked out the screenshots repository (this directory contains the “references” subdirectory)
1. copy `uitest/eclipse-run-selected-test.properties` to `work/eclipse-run-selected-test.properties`
2. edit `work/eclipse-run-selected-test.properties`
1. Define `com.vaadin.testbench.screenshot.directory` as the directory where you checked out the screenshots repository (this directory contains the “references” subdirectory)

## Running TB3+ tests

@@ -116,15 +116,19 @@ TB3+ tests are standard JUnit tests which can be run using the “Run as -> JUni
#### Debugging remotely
Running remotely on a single browser (as described above) can be used to debug issues with a given browser but with the downside that you cannot see what is happening with the browser. In theory this is possible if you figure out on what machine the test is run (no good way for this at the moment) and use VNC to connect to that.
#### Debugging locally
A better option is to run the test on a local browser instance. To do this you need to add a `@RunLocally` annotation to the test class. @RunLocally uses Firefox by default but also supports other browsers using `@RunLocally(CHROME)`, `@RunLocally(SAFARI)` and `@RunLocally(PHANTOMJS)`.
A better option is to run the test on a local browser instance. To do this you need to add a `@RunLocally` annotation to the test class. `@RunLocally` uses Firefox by default but also supports other browsers using `@RunLocally(CHROME)`, `@RunLocally(SAFARI)`, `@RunLocally(Browser.IE11)` and `@RunLocally(PHANTOMJS)`.

By default using `@RunLocally` annotation in Framework tests is not allowed. In order to run a test locally, you need to uncomment the line `com.vaadin.testbench.allowRunLocally=true` in `work/eclipse-run-selected-test.properties`.

Some local configuration is needed for certain browsers, especially if you did not install them in the “standard” locations.
Besides, some local configurations are needed for certain browsers, especially if you did not install them in the “standard” locations.

**PhantomJS**: PhantomJS is a headless browser, good especially for fast validation. Download it from the [PhantomJS site](http://phantomjs.org/download.html) and add the binary to your PATH.

**Firefox**: If you have Firefox in your PATH, this is everything you need. If Firefox cannot be started, add a **firefox.path** property to `/work/eclipse-run-selected-test.properties`, pointing to your Firefox binary (e.g.`firefox.path=/Applications/Firefox 17 ESR.app/Contents/MacOS/firefox`)
**Firefox**: If you have Firefox in your PATH, this is everything you need. If Firefox cannot be started, add a **firefox.path** property to `/work/eclipse-run-selected-test.properties`, pointing to your Firefox binary (e.g.`firefox.path=/Applications/Firefox 17 ESR.app/Contents/MacOS/firefox`).

**Chrome**: You need to [download ChromeDriver](http://chromedriver.storage.googleapis.com/index.html) and add a chrome.driver.path property to `/work/eclipse-run-selected-test.properties`, pointing to the ChromeDriver binary (NOT the Chrome binary).

**Chrome**: You need to [download ChromeDriver](http://chromedriver.storage.googleapis.com/index.html) and add a chrome.driver.path property to `/work/eclipse-run-selected-test.properties`, pointing to the ChromeDriver binary (NOT the Chrome binary)
**IE11**: You need to [download IEDriverServer according to the selenium version](http://selenium-release.storage.googleapis.com/index.html) and add a webdriver.ie.driver property to `/work/eclipse-run-selected-test.properties`, point to the IEDriveServer binary.

**Safari**: At least on Mac, no configuration should be needed.


+ 1
- 1
README.md View File

@@ -65,7 +65,7 @@ The following preferences need to be set to keep the project consistent. You nee

## Setting up IntelliJ IDEA to Develop Vaadin Framework 8

1. Intall and run IDEA. Ultimate Edition is better but Community Edition should also work.
1. Install and run IDEA. Ultimate Edition is better but Community Edition should also work.
1. Ensure if Git and Maven plugins are installed, properly configured and enabled.
1. Clone the repository, using menu VCS -> Checkout from Version Control -> Git -> Git Repository URL -> https://github.com/vaadin/framework.git.
When the repository is cloned, do **NOT** open it as a project.

+ 1
- 1
all/pom.xml View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-root</artifactId>
<version>8.5-SNAPSHOT</version>
<version>8.8-SNAPSHOT</version>
</parent>
<artifactId>vaadin-all</artifactId>
<name>vaadin-all</name>

+ 16
- 17
all/src/main/templates/release-notes.html View File

@@ -23,7 +23,7 @@

<body>
<div id="header">
<h1>Vaadin &ndash; thinking of U and I</h1>
<h1>Vaadin &ndash; Fight For Simplicity</h1>
<div id="version">
<strong>Version @version@</strong>
</div>
@@ -65,7 +65,7 @@
a number of new features and bug fixes, as listed in the <a
href="#enhancements">list of enhancements</a> and <a
href="#changelog">change log</a> below.
The API in this alpha version is not considered final and may change based on your feedback.
The API in this beta version is not considered final and may change based on your feedback.
</p>

<!-- ================================================================ -->
@@ -83,27 +83,26 @@
enhancements. Below is a list of the most notable changes:</p>

<ul>
<li></li>
</ul>

</p>

<p>
For enhancements introduced in Vaadin Framework 8.4, see the <a
href="http://vaadin.com/download/release/8.4/8.4.0/release-notes.html">Release
Notes for Vaadin Framework 8.4.0</a>.
For enhancements introduced in Vaadin Framework 8.7, see the <a
href="http://vaadin.com/download/release/8.7/8.7.0/release-notes.html">Release
Notes for Vaadin Framework 8.7.0</a>.
For migrating from previous framework versions, see <a href="#incompatible">the list of incompatible changes</a> and <a href="#migrating">how to migrate
to Vaadin Framework 8</a>.
</p>

<h2 id="incompatible">Incompatible or Behavior-altering Changes in @version-minor@</h2>

<li><tt>AbstractSingleSelect</tt> communication has been partially re-written. Some <tt>protected</tt> API was removed.</li>
<li><tt>setStyleName(String, boolean)</tt> has been moved from <tt>AbstractComponent</tt> to <tt>Component</tt> interface as a default method.</li>
<li><tt>Window</tt> closing animation disabled by default.</li>
<li><tt>FileTypeResolver</tt> icon features have been moved to a compatibility version of the class.</li>

<h2>For incompatible or behavior-altering changes in 8.4, please see <a href="https://vaadin.com/download/release/8.4/8.4.0/release-notes.html#incompatible">8.4 release notes</a></h2>
<ul>
<li></li>
</ul>

<h2>For incompatible or behavior-altering changes in 8.7, please see <a href="https://vaadin.com/download/release/8.7/8.7.0/release-notes.html#incompatible">8.7 release notes</a></h2>

<h3 id="knownissues">Known Issues and Limitations</h3>
<ul>
@@ -355,12 +354,12 @@
</p>

<ul id="supportedservers">
<li>Apache Tomcat 7-8</li>
<li>Apache Tomcat 7-9</li>
<li>Apache TomEE 1.7 and 7.0</li>
<li>Oracle WebLogic Server 12.2</li>
<li>IBM WebSphere Application Server 9</li>
<li>JBoss EAP 6</li>
<li>Wildfly 8-11</li>
<li>Wildfly 8-13</li>
<li>Jetty 8-9</li>
<li>Glassfish 4</li>
<li>Payara Server 164</li>
@@ -383,11 +382,11 @@
</p>

<ul>
<li>Mozilla Firefox (latest version, currently 54)</li>
<li>Mozilla Firefox ESR (latest version, currently 52 ESR)</li>
<li>Mozilla Firefox 54+</li>
<li>Mozilla Firefox ESR 52+</li>
<li>Internet Explorer 11, Edge (latest version)</li>
<li>Safari 9+</li>
<li>Google Chrome (latest version, currently 59)</li>
<li>Google Chrome 59+</li>
</ul>

<p>
@@ -438,7 +437,7 @@

<div id="footer">
<span class="slogan"><strong>vaadin <em>}></em>
</strong> thinking of U and I<span> <a href="#top">&uarr; Back
</strong> Fight For Simplicity</span> <a href="#top">&uarr; Back
to top</a>
</div>
<!-- /footer -->

+ 5
- 5
bom/pom.xml View File

@@ -11,16 +11,16 @@
<groupId>com.vaadin</groupId>
<artifactId>vaadin-bom</artifactId>
<packaging>pom</packaging>
<version>8.5-SNAPSHOT</version>
<version>8.8-SNAPSHOT</version>
<name>Vaadin Framework (Bill of Materials)</name>
<description>Vaadin Framework (Bill of Materials)</description>
<url>http://vaadin.com</url>

<properties>
<vaadin.spring.version>3.0.0</vaadin.spring.version>
<vaadin.testbench.version>5.1.2</vaadin.testbench.version>
<vaadin.cdi.version>3.0.0</vaadin.cdi.version>
<vaadin.context-menu.version>2.0.0</vaadin.context-menu.version>
<vaadin.spring.version>3.1.1</vaadin.spring.version>
<vaadin.testbench.version>5.2.0</vaadin.testbench.version>
<vaadin.cdi.version>3.0.1</vaadin.cdi.version>
<vaadin.context-menu.version>3.0.0</vaadin.context-menu.version>
</properties>

<repositories>

+ 1
- 1
client-compiled/pom.xml View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-root</artifactId>
<version>8.5-SNAPSHOT</version>
<version>8.8-SNAPSHOT</version>
</parent>
<!-- Needed by a plugin in release build -->
<groupId>com.vaadin</groupId>

+ 6
- 23
client-compiled/src/main/java/com/vaadin/osgi/widgetset/DefaultWidgetsetContribution.java View File

@@ -15,33 +15,16 @@
*/
package com.vaadin.osgi.widgetset;

import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.http.HttpService;

import com.vaadin.osgi.resources.OsgiVaadinResources;
import com.vaadin.osgi.resources.VaadinResourceService;

@Component(immediate = true)
public class DefaultWidgetsetContribution {
private HttpService httpService;
import com.vaadin.osgi.resources.OsgiVaadinWidgetset;

@Component
public class DefaultWidgetsetContribution implements OsgiVaadinWidgetset {
private static final String WIDGETSET_NAME = "com.vaadin.DefaultWidgetSet";

@Activate
void startup(ComponentContext context) throws Exception {
VaadinResourceService service = OsgiVaadinResources.getService();
service.publishWidgetset(WIDGETSET_NAME, httpService);
}

@Reference
void setHttpService(HttpService httpService) {
this.httpService = httpService;
}

void unsetHttpService(HttpService httpService) {
this.httpService = null;
@Override
public String getName() {
return WIDGETSET_NAME;
}
}

+ 1
- 1
client-compiler/pom.xml View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-root</artifactId>
<version>8.5-SNAPSHOT</version>
<version>8.8-SNAPSHOT</version>
</parent>
<artifactId>vaadin-client-compiler</artifactId>
<name>vaadin-client-compiler</name>

+ 1
- 1
client/pom.xml View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-root</artifactId>
<version>8.5-SNAPSHOT</version>
<version>8.8-SNAPSHOT</version>
</parent>
<!-- Needed by a plugin in release build -->
<groupId>com.vaadin</groupId>

+ 1
- 6
client/src/main/java/com/vaadin/client/ComponentConnector.java View File

@@ -28,7 +28,7 @@ import com.vaadin.shared.AbstractComponentState;
* Updates can be sent back to the server using the
* {@link ApplicationConnection#updateVariable()} methods.
*/
public interface ComponentConnector extends ServerConnector {
public interface ComponentConnector extends HasWidget {

/*
* (non-Javadoc)
@@ -38,11 +38,6 @@ public interface ComponentConnector extends ServerConnector {
@Override
public AbstractComponentState getState();

/**
* Returns the widget for this {@link ComponentConnector}.
*/
public Widget getWidget();

public LayoutManager getLayoutManager();

/**

+ 28
- 0
client/src/main/java/com/vaadin/client/HasWidget.java View File

@@ -0,0 +1,28 @@
/*
* Copyright 2000-2018 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.client;

import com.google.gwt.user.client.ui.Widget;

/**
* An interface used by client-side connectors which have widgets.
*/
public interface HasWidget extends ServerConnector {
/**
* Returns the widget for this {@link ServerConnector}.
*/
public Widget getWidget();
}

+ 2
- 0
client/src/main/java/com/vaadin/client/communication/Heartbeat.java View File

@@ -82,6 +82,8 @@ public class Heartbeat {

final RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, uri);

XhrConnection.addXsrfHeaderFromCookie(rb);

final RequestCallback callback = new RequestCallback() {

@Override

+ 14
- 0
client/src/main/java/com/vaadin/client/communication/XhrConnection.java View File

@@ -22,6 +22,7 @@ import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.vaadin.client.ApplicationConnection;
@@ -49,6 +50,9 @@ import elemental.json.JsonObject;
*/
public class XhrConnection {

private static final String XSRF_HEADER_NAME = "X-XSRF-TOKEN";
private static final String XSRF_COOKIE_NAME = "XSRF-TOKEN";

private ApplicationConnection connection;

/**
@@ -183,6 +187,9 @@ public class XhrConnection {
*/
public void send(JsonObject payload) {
RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, getUri());

addXsrfHeaderFromCookie(rb);

// TODO enable timeout
// rb.setTimeoutMillis(timeoutMillis);
// TODO this should be configurable
@@ -244,6 +251,13 @@ public class XhrConnection {
return connection.getMessageHandler();
}

public static void addXsrfHeaderFromCookie(RequestBuilder rb) {
String xsrfTokenVal = Cookies.getCookie(XSRF_COOKIE_NAME);
if (xsrfTokenVal != null && !xsrfTokenVal.isEmpty()) {
rb.setHeader(XSRF_HEADER_NAME, xsrfTokenVal);
}
}

private static native boolean resendRequest(Request request)
/*-{
var xhr = request.@com.google.gwt.http.client.Request::xmlHttpRequest

+ 60
- 1
client/src/main/java/com/vaadin/client/connectors/grid/ComponentRendererConnector.java View File

@@ -15,12 +15,20 @@
*/
package com.vaadin.client.connectors.grid;

import java.util.HashSet;
import java.util.Iterator;
import java.util.logging.Logger;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ConnectorMap;
import com.vaadin.client.renderers.Renderer;
import com.vaadin.client.renderers.WidgetRenderer;
import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.AbstractConnector;
import com.vaadin.client.widget.grid.RendererCellReference;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.grid.renderers.ComponentRendererState;
@@ -37,6 +45,9 @@ import com.vaadin.ui.renderers.ComponentRenderer;
public class ComponentRendererConnector
extends AbstractGridRendererConnector<String> {

private HashSet<String> knownConnectors = new HashSet<>();
private HandlerRegistration handlerRegistration;

@Override
protected Renderer<String> createRenderer() {
return new WidgetRenderer<String, SimplePanel>() {
@@ -51,12 +62,21 @@ public class ComponentRendererConnector
@Override
public void render(RendererCellReference cell, String connectorId,
SimplePanel widget) {
createConnectorHierarchyChangeHandler();
Widget connectorWidget = null;
if (connectorId != null) {
ComponentConnector connector = (ComponentConnector) ConnectorMap
.get(getConnection()).getConnector(connectorId);
widget.setWidget(connector.getWidget());
if (connector != null) {
connectorWidget = connector.getWidget();
knownConnectors.add(connectorId);
}
}
if (connectorWidget != null) {
widget.setWidget(connectorWidget);
} else if (widget.getWidget() != null) {
widget.remove(widget.getWidget());
knownConnectors.remove(connectorId);
}
}
};
@@ -66,4 +86,43 @@ public class ComponentRendererConnector
public ComponentRendererState getState() {
return (ComponentRendererState) super.getState();
}

@Override
public void onUnregister() {
unregisterHierarchyHandler();
super.onUnregister();
}

/**
* Adds a listener for grid hierarchy changes to find detached connectors
* previously handled by this renderer in order to detach from DOM their
* widgets before {@link AbstractComponentConnector#onUnregister()} is
* invoked otherwise an error message is logged.
*/
private void createConnectorHierarchyChangeHandler() {
if (handlerRegistration == null) {
handlerRegistration = getGridConnector()
.addConnectorHierarchyChangeHandler(event -> {
Iterator<String> iterator = knownConnectors.iterator();
while (iterator.hasNext()) {
ComponentConnector connector = (ComponentConnector) ConnectorMap
.get(getConnection())
.getConnector(iterator.next());
if (connector != null
&& connector.getParent() == null) {
connector.getWidget().removeFromParent();
iterator.remove();
}
}
});
}
}

private void unregisterHierarchyHandler() {
if (this.handlerRegistration != null) {
this.handlerRegistration.removeHandler();
this.handlerRegistration = null;
}
}

}

+ 16
- 3
client/src/main/java/com/vaadin/client/connectors/grid/EditorConnector.java View File

@@ -72,8 +72,11 @@ public class EditorConnector extends AbstractExtensionConnector {

@Override
public void cancel() {
serverInitiated = true;
getParent().getWidget().cancelEditor();
// Canceling an editor that is not open is a no-op.
if (getParent().getWidget().isEditorActive()) {
serverInitiated = true;
getParent().getWidget().cancelEditor();
}
}

@Override
@@ -194,7 +197,17 @@ public class EditorConnector extends AbstractExtensionConnector {

@OnStateChange("enabled")
void updateEnabled() {
getParent().getWidget().getEditor().setEnabled(getState().enabled);
boolean enabled = getState().enabled;

Scheduler.ScheduledCommand setEnabledCommand = () -> {
getParent().getWidget().getEditor().setEnabled(enabled);
};

if (!enabled) {
Scheduler.get().scheduleFinally(setEnabledCommand);
} else {
setEnabledCommand.execute();
}
}

@OnStateChange("saveCaption")

+ 19
- 0
client/src/main/java/com/vaadin/client/connectors/grid/GridDropTargetConnector.java View File

@@ -100,6 +100,25 @@ public class GridDropTargetConnector extends DropTargetExtensionConnector {
super.extend(target);
}

@Override
protected boolean isDropAllowedByCriteriaScript(NativeEvent event) {
final String criteriaScript = getState().criteriaScript;
if (criteriaScript == null) {
return true;
}
return executeScript(event,
getTargetElement(event.getEventTarget().cast()),
getDropLocation(getTargetElement(event.getEventTarget().cast()),
event).name(),
criteriaScript);
}

private native boolean executeScript(NativeEvent event,
Element targetElement, String dropLocation, String script)
/*-{
return new Function('event', 'targetElement', 'dropLocation', script)(event, targetElement, dropLocation);
}-*/;

/**
* Inspects whether the current drop would happen on the whole grid instead
* of specific row as the drop target. This is based on used drop mode,

+ 3
- 1
client/src/main/java/com/vaadin/client/data/AbstractRemoteDataSource.java View File

@@ -496,6 +496,9 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {

Range newUsefulData = partition[1];
if (!newUsefulData.isEmpty()) {
if (!cached.isEmpty())
discardStaleCacheEntries();

// Update the parts that are actually inside
int start = newUsefulData.getStart();
for (int i = start; i < newUsefulData.getEnd(); i++) {
@@ -515,7 +518,6 @@ public abstract class AbstractRemoteDataSource<T> implements DataSource<T> {
if (cached.isEmpty()) {
cached = newUsefulData;
} else {
discardStaleCacheEntries();

/*
* everything might've become stale so we need to re-check for

+ 2
- 2
client/src/main/java/com/vaadin/client/extensions/AbstractEventTriggerExtensionConnector.java View File

@@ -18,7 +18,7 @@ package com.vaadin.client.extensions;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.HandlerRegistration;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.HasWidget;
import com.vaadin.client.ServerConnector;
import com.vaadin.shared.extension.PartInformationState;

@@ -50,7 +50,7 @@ public abstract class AbstractEventTriggerExtensionConnector

@Override
protected void extend(ServerConnector target) {
Widget targetWidget = ((ComponentConnector) target).getWidget();
Widget targetWidget = ((HasWidget) target).getWidget();
if (targetWidget instanceof EventTrigger) {
String partInformation = getState().partInformation;
eventHandlerRegistration = ((EventTrigger) targetWidget)

+ 20
- 6
client/src/main/java/com/vaadin/client/extensions/DropTargetExtensionConnector.java View File

@@ -326,13 +326,8 @@ public class DropTargetExtensionConnector extends AbstractExtensionConnector {
// Currently Safari, Edge and IE don't follow the spec by allowing drop
// if those don't match

// Allow by default when criteria not set
boolean allowed = true;

// Execute criteria script
if (getState().criteriaScript != null) {
allowed = executeScript(event, getState().criteriaScript);
}
boolean allowed = isDropAllowedByCriteriaScript(event);

// Execute criterion defined via API
if (allowed && getState().criteria != null
@@ -365,6 +360,25 @@ public class DropTargetExtensionConnector extends AbstractExtensionConnector {
return allowed;
}

/**
* Checks if a criteria script exists and, if yes, executes it. This method
* is protected, so subclasses as e.g. GridDropTargetConnector can override
* it to add additional script parameters.
*
* @param event
* browser event (dragEnter, dragOver, drop) that should be
* evaluated by the criteria script
* @return {@code true} if no script was given or if the script returned
* true, {@code false} otherwise.
*/
protected boolean isDropAllowedByCriteriaScript(NativeEvent event) {
final String criteriaScript = getState().criteriaScript;
if (criteriaScript == null) {
return true;
}
return executeScript(event, criteriaScript);
}

/**
* Tells if the given array of types contains files.
* <p>

+ 9
- 0
client/src/main/java/com/vaadin/client/ui/VAbstractCalendarPanel.java View File

@@ -938,6 +938,15 @@ public abstract class VAbstractCalendarPanel<R extends Enum<R>>
renderCalendar(true);
}

/**
* Returns the value of initialRenderDone
*
* @since 8.7
*/
public boolean isInitialRenderDone() {
return initialRenderDone;
}

/**
* For internal use only. May be removed or replaced in the future.
*

+ 36
- 3
client/src/main/java/com/vaadin/client/ui/VCheckBox.java View File

@@ -16,7 +16,9 @@

package com.vaadin.client.ui;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.vaadin.client.ApplicationConnection;
@@ -81,20 +83,34 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox
* Gives access to the input element.
*
* @return Element of the CheckBox itself
* @since 8.7
*/
private Element getCheckBoxElement() {
public Element getInputElement() {
// public to allow CheckBoxState to access it.
// FIXME: Would love to use a better way to access the checkbox element
return getElement().getFirstChildElement();
}

/**
* Gives access to the label element.
*
* @return Element of the Label itself
* @since 8.7
*/
public Element getLabelElement() {
// public to allow CheckBoxState to access it.
// FIXME: Would love to use a better way to access the label element
return getInputElement().getNextSiblingElement();
}

@Override
public void setAriaRequired(boolean required) {
AriaHelper.handleInputRequired(getCheckBoxElement(), required);
AriaHelper.handleInputRequired(getInputElement(), required);
}

@Override
public void setAriaInvalid(boolean invalid) {
AriaHelper.handleInputInvalid(getCheckBoxElement(), invalid);
AriaHelper.handleInputInvalid(getInputElement(), invalid);
}

@Override
@@ -116,4 +132,21 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox
errorIndicatorElement = null;
}
}

@Override
protected void onAttach() {
super.onAttach();

if (BrowserInfo.get().isSafari()) {
/*
* Sometimes Safari does not render checkbox correctly when
* attaching. Setting the visibility to hidden and a bit later
* restoring will make everything just fine.
*/
getElement().getStyle().setVisibility(Visibility.HIDDEN);
Scheduler.get().scheduleFinally(() -> {
getElement().getStyle().setVisibility(Visibility.VISIBLE);
});
}
}
}

+ 14
- 1
client/src/main/java/com/vaadin/client/ui/VCheckBoxGroup.java View File

@@ -137,6 +137,7 @@ public class VCheckBoxGroup extends FocusableFlowPanelComposite
widget.setValue(
item.getBoolean(ListingJsonConstants.JSONKEY_ITEM_SELECTED));
setOptionEnabled(widget, item);
setOptionReadOnly(widget, item);
widget.setStyleName(CLASSNAME_OPTION_SELECTED, widget.getValue());

if (requireInitialization) {
@@ -197,6 +198,18 @@ public class VCheckBoxGroup extends FocusableFlowPanelComposite
!isEnabled() || !optionEnabled);
}

protected void setOptionReadOnly(VCheckBox checkBox, JsonObject item) {
if (isReadonly()) {
checkBox.addStyleName("v-readonly");
checkBox.setEnabled(false);
} else {
checkBox.removeStyleName("v-readonly");
boolean optionEnabled = !item
.getBoolean(ListingJsonConstants.JSONKEY_ITEM_DISABLED);
checkBox.setEnabled(isEnabled() && optionEnabled);
}
}

public boolean isHtmlContentAllowed() {
return htmlContentAllowed;
}
@@ -217,7 +230,7 @@ public class VCheckBoxGroup extends FocusableFlowPanelComposite
public void setReadonly(boolean readonly) {
if (this.readonly != readonly) {
this.readonly = readonly;
optionsToItems.forEach(this::setOptionEnabled);
optionsToItems.forEach(this::setOptionReadOnly);
}
}


+ 4
- 0
client/src/main/java/com/vaadin/client/ui/VComboBox.java View File

@@ -2361,9 +2361,13 @@ public class VComboBox extends Composite implements Field, KeyDownHandler,
case KeyCodes.KEY_ALT:
case KeyCodes.KEY_DOWN:
case KeyCodes.KEY_UP:
case KeyCodes.KEY_RIGHT:
case KeyCodes.KEY_LEFT:
case KeyCodes.KEY_PAGEDOWN:
case KeyCodes.KEY_PAGEUP:
case KeyCodes.KEY_ESCAPE:
case KeyCodes.KEY_HOME:
case KeyCodes.KEY_END:
// NOP
break;
default:

+ 3
- 3
client/src/main/java/com/vaadin/client/ui/VDateTimeCalendarPanel.java View File

@@ -119,6 +119,9 @@ public class VDateTimeCalendarPanel
sec.addChangeHandler(this);
}

// Update times
updateTimes();

final String delimiter = getDateTimeService().getClockDelimeter();
if (isReadonly()) {
int h = 0;
@@ -171,9 +174,6 @@ public class VDateTimeCalendarPanel
return;
}

// Update times
updateTimes();

ListBox lastDropDown = getLastDropDown();
lastDropDown.addKeyDownHandler(event -> {
boolean shiftKey = event.getNativeEvent().getShiftKey();

+ 61
- 15
client/src/main/java/com/vaadin/client/ui/VMenuBar.java View File

@@ -121,6 +121,8 @@ public class VMenuBar extends FocusableFlowPanel implements
/** For internal use only. May be removed or replaced in the future. */
public boolean htmlContentAllowed;

public boolean mouseDownPressed;

private Map<String, List<Command>> triggers = new HashMap<>();

public VMenuBar() {
@@ -225,13 +227,35 @@ public class VMenuBar extends FocusableFlowPanel implements
* For internal use only. May be removed or replaced in the future.
*/
public String buildItemHTML(UIDL item) {
return buildItemHTML(item.hasAttribute("separator"),
item.getChildCount() > 0, item.getStringAttribute("icon"),
item.getStringAttribute("text"));

}

/**
* Build the HTML content for a menu item.
* <p>
* For internal use only. May be removed or replaced in the future.
*
* @param separator
* the menu item is separator
* @param subMenu
* the menu item contains submenu
* @param iconUrl
* the menu item icon URL or {@code null}
* @param text
* the menu item text. May not be {@code null}
*/
public String buildItemHTML(boolean separator, boolean subMenu,
String iconUrl, String text) {
// Construct html from the text and the optional icon
StringBuilder itemHTML = new StringBuilder();
if (item.hasAttribute("separator")) {
if (separator) {
itemHTML.append("<span>---</span>");
} else {
// Add submenu indicator
if (item.getChildCount() > 0) {
if (subMenu) {
String bgStyle = "";
itemHTML.append("<span class=\"" + getStylePrimaryName()
+ "-submenu-indicator\"" + bgStyle
@@ -240,11 +264,11 @@ public class VMenuBar extends FocusableFlowPanel implements

itemHTML.append("<span class=\"" + getStylePrimaryName()
+ "-menuitem-caption\">");
Icon icon = client.getIcon(item.getStringAttribute("icon"));
Icon icon = client.getIcon(iconUrl);
if (icon != null) {
itemHTML.append(icon.getElement().getString());
}
String itemText = item.getStringAttribute("text");
String itemText = text;
if (!htmlContentAllowed) {
itemText = WidgetUtil.escapeHTML(itemText);
}
@@ -355,7 +379,6 @@ public class VMenuBar extends FocusableFlowPanel implements
@Override
public void onBrowserEvent(Event e) {
super.onBrowserEvent(e);

// Handle onload events (icon loaded, size changes)
if (DOM.eventGetType(e) == Event.ONLOAD) {
VMenuBar parent = getParentMenu();
@@ -379,20 +402,26 @@ public class VMenuBar extends FocusableFlowPanel implements
targetItem = item;
}
}

if (targetItem != null) {
switch (DOM.eventGetType(e)) {

case Event.ONMOUSEDOWN:
if (e.getButton() == Event.BUTTON_LEFT) {
if (isEnabled() && targetItem.isEnabled()) {
// Button is clicked, but not yet released
mouseDownPressed = true;
}
}
break;
case Event.ONCLICK:
if (isEnabled() && targetItem.isEnabled()) {
mouseDownPressed = false;
itemClick(targetItem);
}

break;

case Event.ONMOUSEOVER:
LazyCloser.cancelClosing();

if (isEnabled() && targetItem.isEnabled()) {
itemOver(targetItem);
}
@@ -701,9 +730,13 @@ public class VMenuBar extends FocusableFlowPanel implements
*/
@Override
public void onClose(CloseEvent<PopupPanel> event) {
hideChildren();
close(event, true);
}

protected void close(CloseEvent<PopupPanel> event, boolean animated) {
hideChildren(animated, animated);
if (event.isAutoClosed()) {
hideParents(true);
hideParents(true, animated);
menuVisible = false;
}
visibleChildMenu = null;
@@ -739,14 +772,18 @@ public class VMenuBar extends FocusableFlowPanel implements
* Recursively hide all parent menus.
*/
public void hideParents(boolean autoClosed) {
hideParents(autoClosed, true);
}

public void hideParents(boolean autoClosed, boolean animated) {
if (visibleChildMenu != null) {
popup.hide();
popup.hide(false, animated, animated);
setSelected(null);
menuVisible = false;
}

if (getParentMenu() != null) {
getParentMenu().hideParents(autoClosed);
getParentMenu().hideParents(autoClosed, animated);
}
}

@@ -873,6 +910,7 @@ public class VMenuBar extends FocusableFlowPanel implements
super.onLoad();
if (getParentMenu() != null
&& getParentMenu().getParentMenu() == null
&& getParentMenu().getItems().size() >= 1
&& getParentMenu().getItems().get(0).equals(this)) {
getElement().setAttribute("tabindex", "0");
} else {
@@ -949,7 +987,7 @@ public class VMenuBar extends FocusableFlowPanel implements
updateStyleNames();
}

protected void updateStyleNames() {
public void updateStyleNames() {
if (parentMenu == null) {
// Style names depend on the parent menu's primary style name so
// don't do updates until the item has a parent
@@ -1088,7 +1126,7 @@ public class VMenuBar extends FocusableFlowPanel implements
return enabled;
}

private void setSeparator(boolean separator) {
public void setSeparator(boolean separator) {
isSeparator = separator;
updateStyleNames();
if (!separator) {
@@ -1185,6 +1223,14 @@ public class VMenuBar extends FocusableFlowPanel implements
this.id = id;
}

public void setDescription(String description) {
this.description = description;
}

public void setDescriptionContentMode(
ContentMode descriptionContentMode) {
this.descriptionContentMode = descriptionContentMode;
}
}

/**
@@ -1906,7 +1952,7 @@ public class VMenuBar extends FocusableFlowPanel implements
LazyCloser.schedule();
}

private VMenuBar getRoot() {
protected VMenuBar getRoot() {
VMenuBar root = this;

while (root.getParentMenu() != null) {

+ 1
- 21
client/src/main/java/com/vaadin/client/ui/VNativeButton.java View File

@@ -24,11 +24,8 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Button;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.StyleConstants;
import com.vaadin.client.Util;
import com.vaadin.client.WidgetUtil.ErrorUtil;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.button.ButtonServerRpc;

public class VNativeButton extends Button
@@ -59,13 +56,10 @@ public class VNativeButton extends Button
* mouse while clicking it. In this case mouse leaves the button without
* moving.
*/
private boolean clickPending;
public boolean clickPending;

private boolean cancelNextClick = false;

/** For internal use only. May be removed or replaced in the future. */
public boolean disableOnClick = false;

public VNativeButton() {
setStyleName(CLASSNAME);

@@ -145,20 +139,6 @@ public class VNativeButton extends Button
// (#11854)
setFocus(true);
}
if (disableOnClick) {
setEnabled(false);
// FIXME: This should be moved to NativeButtonConnector along with
// buttonRpcProxy
addStyleName(StyleConstants.DISABLED);
buttonRpcProxy.disableOnClick();
}

// Add mouse details
MouseEventDetails details = MouseEventDetailsBuilder
.buildMouseEventDetails(event.getNativeEvent(), getElement());
buttonRpcProxy.click(details);

clickPending = false;
}

@Override

+ 25
- 1
client/src/main/java/com/vaadin/client/ui/VNativeSelect.java View File

@@ -29,6 +29,7 @@ import com.vaadin.shared.ui.nativeselect.NativeSelectState;
public class VNativeSelect extends FocusableFlowPanelComposite {

private final ListBox listBox = new ListBox();
private boolean emptySelectionAllowed = true;

/**
* Creates a new {@code VNativeSelect} instance.
@@ -55,7 +56,11 @@ public class VNativeSelect extends FocusableFlowPanelComposite {
*/
public void setSelectedItem(String value) {
if (value == null) {
getListBox().setSelectedIndex(-1);
if (emptySelectionAllowed) {
getListBox().setSelectedIndex(0);
} else {
getListBox().setSelectedIndex(-1);
}
} else {
for (int i = 0; i < getListBox().getItemCount(); i++) {
if (Objects.equals(value, getListBox().getValue(i))) {
@@ -132,4 +137,23 @@ public class VNativeSelect extends FocusableFlowPanelComposite {
return getListBox().getVisibleItemCount();
}

/**
* Returns true if empty selection is allowed.
*
* @since 8.7
* @return empty selection is allowed
*/
public boolean isEmptySelectionAllowed() {
return emptySelectionAllowed;
}

/**
* Sets true if empty selection is allowed.
*
* @since 8.7
* @param emptySelectionAllowed
*/
public void setEmptySelectionAllowed(boolean emptySelectionAllowed) {
this.emptySelectionAllowed = emptySelectionAllowed;
}
}

+ 11
- 9
client/src/main/java/com/vaadin/client/ui/VOverlay.java View File

@@ -65,15 +65,6 @@ public class VOverlay extends Overlay {
super(autoHide, modal);
}

/*
* A "thread local" of sorts, set temporarily so that VOverlayImpl knows
* which VOverlay is using it, so that it can be attached to the correct
* overlay container.
*
* TODO this is a strange pattern that we should get rid of when possible.
*/
protected static VOverlay current;

/**
* Get the {@link ApplicationConnection} that this overlay belongs to. If
* it's not set, {@link #getOwner()} is used to figure it out.
@@ -162,4 +153,15 @@ public class VOverlay extends Overlay {
overlayContainerLabel);
}

/**
* Sets the {@link ApplicationConnection} that this overlay belongs to.
*
* @see #getApplicationConnection()
*
* @param ac
* the connection
*/
public void setApplicationConnection(ApplicationConnection ac) {
this.ac = ac;
}
}

+ 128
- 15
client/src/main/java/com/vaadin/client/ui/VTabsheet.java View File

@@ -16,8 +16,10 @@

package com.vaadin.client.ui;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.google.gwt.aria.client.Id;
import com.google.gwt.aria.client.LiveValue;
@@ -272,6 +274,9 @@ public class VTabsheet extends VTabsheetBase

public void recalculateCaptionWidth() {
tabCaption.setWidth(tabCaption.getRequiredWidth() + "px");
if (isVisible()) {
tabBar.tabWidths.put(this, getOffsetWidth());
}
}

@Override
@@ -443,6 +448,9 @@ public class VTabsheet extends VTabsheetBase

private VTabsheet tabsheet;

/** For internal use only. May be removed or replaced in the future. */
private Map<Tab, Integer> tabWidths = new HashMap<Tab, Integer>();

TabBar(VTabsheet tabsheet) {
this.tabsheet = tabsheet;

@@ -502,6 +510,7 @@ public class VTabsheet extends VTabsheetBase
getTabsheet().selectionHandler.registerTab(t);

t.setCloseHandler(this);
tabWidths.put(t, t.getOffsetWidth());

return t;
}
@@ -522,6 +531,18 @@ public class VTabsheet extends VTabsheetBase
return (Tab) super.getWidget(index);
}

private int getTabIndex(Tab tab) {
if (tab == null) {
return -1;
}
for (int i = 0; i < getTabCount(); i++) {
if (tab.equals(getTab(i))) {
return i;
}
}
return -1;
}

private int getTabIndex(String tabId) {
if (tabId == null) {
return -1;
@@ -593,6 +614,7 @@ public class VTabsheet extends VTabsheetBase
}

remove(tab);
tabWidths.remove(tab);

/*
* If this widget was selected we need to unmark it as the last
@@ -616,6 +638,13 @@ public class VTabsheet extends VTabsheetBase
}
}

private int getLastKnownTabWidth(Tab tab) {
if (tabWidths.containsKey(tab)) {
return tabWidths.get(tab);
}
return 0;
}

private int selectNewShownTab(int oldPosition) {
// After removing a tab, find a new scroll position. In most
// cases the scroll position does not change, but if the tab
@@ -630,7 +659,7 @@ public class VTabsheet extends VTabsheetBase

for (int i = oldPosition - 1; i >= 0; i--) {
Tab tab = getTab(i);
if (!tab.isHiddenOnServer()) {
if (tab != null && !tab.isHiddenOnServer()) {
return i;
}
}
@@ -685,6 +714,13 @@ public class VTabsheet extends VTabsheetBase
}
}

/**
* Returns the index of the last visible tab on the server
*/
private int getLastVisibleTab() {
return getPreviousVisibleTab(getTabCount());
}

/**
* Find the previous visible tab. Returns -1 if none is found.
*
@@ -702,7 +738,7 @@ public class VTabsheet extends VTabsheetBase

public int scrollLeft(int currentFirstVisible) {
int prevVisible = getPreviousVisibleTab(currentFirstVisible);
if (prevVisible == -1) {
if (prevVisible < 0) {
return -1;
}

@@ -715,7 +751,7 @@ public class VTabsheet extends VTabsheetBase

public int scrollRight(int currentFirstVisible) {
int nextVisible = getNextVisibleTab(currentFirstVisible);
if (nextVisible == -1) {
if (nextVisible < 0) {
return -1;
}
Tab currentFirst = getTab(currentFirstVisible);
@@ -1335,14 +1371,44 @@ public class VTabsheet extends VTabsheetBase
scrollerIndex = tb.getNextVisibleTab(scrollerIndex);
}

TableCellElement spacerCell = ((TableElement) tb.getElement().cast())
.getRows().getItem(0).getCells().getItem(tb.getTabCount());
if (scroller.getStyle().getDisplay() != "none") {
spacerCell.getStyle().setPropertyPx("minWidth",
scroller.getOffsetWidth());
spacerCell.getStyle().setPropertyPx("minHeight", 1);
} else {
spacerCell.getStyle().setProperty("minWidth", "0");
spacerCell.getStyle().setProperty("minHeight", "0");
}

// check if hidden tabs need to be scrolled back into view
int firstVisibleIndex = tb.getFirstVisibleTabClient();
if (firstVisibleIndex != 0 && getTabCount() > 0
&& getLeftGap() + getRightGap() > 0) {
int hiddenCount = tb.getTabCount();
if (firstVisibleIndex > 0) {
hiddenCount -= firstVisibleIndex;
}
int counter = 0;
while ((getLeftGap() + getRightGap() > getFirstOutOfViewWidth())
&& counter < hiddenCount) {
tb.scrollLeft(tb.getFirstVisibleTabClient());
scrollerIndex = tb.getFirstVisibleTabClient();
++counter;
}
}

boolean scrolled = isScrolledTabs();
boolean clipped = isClippedTabs();
if (tb.getTabCount() > 0 && tb.isVisible() && (scrolled || clipped)) {
scroller.getStyle().clearDisplay();
DOM.setElementProperty(scrollerPrev, "className", SCROLLER_CLASSNAME
scrollerPrev.setPropertyString("className", SCROLLER_CLASSNAME
+ (scrolled ? "Prev" : PREV_SCROLLER_DISABLED_CLASSNAME));
DOM.setElementProperty(scrollerNext, "className",
SCROLLER_CLASSNAME + (clipped ? "Next" : "Next-disabled"));
scrollerNext.setPropertyString("className",
SCROLLER_CLASSNAME + (clipped
&& scrollerIndex != tb.getLastVisibleTab() ? "Next"
: "Next-disabled"));

// the active tab should be focusable if and only if it is visible
boolean isActiveTabVisible = scrollerIndex <= activeTabIndex
@@ -1367,6 +1433,48 @@ public class VTabsheet extends VTabsheetBase
}
}

private int getLeftGap() {
int firstVisibleIndex = tb.getFirstVisibleTabClient();
int gap;
if (firstVisibleIndex < 0) {
// no tabs are visible, the entire empty space is returned
// through getRightGap()
gap = 0;
} else {
Element tabContainer = tb.getElement().getParentElement();
Tab firstVisibleTab = tb.getTab(firstVisibleIndex);
gap = firstVisibleTab.getAbsoluteLeft()
- tabContainer.getAbsoluteLeft();
}
return gap > 0 ? gap : 0;
}

private int getRightGap() {
int lastVisibleIndex = tb.getLastVisibleTab();
Element tabContainer = tb.getElement().getParentElement();
int gap;
if (lastVisibleIndex < 0) {
// no tabs visible, return the whole available width
gap = getOffsetWidth() - scroller.getOffsetWidth();
} else {
Tab lastVisibleTab = tb.getTab(lastVisibleIndex);
gap = tabContainer.getAbsoluteRight()
- lastVisibleTab.getAbsoluteLeft()
- lastVisibleTab.getOffsetWidth()
- scroller.getOffsetWidth() - 2;
}
return gap > 0 ? gap : 0;
}

private int getFirstOutOfViewWidth() {
Tab firstTabOutOfView = tb.getTab(
tb.getPreviousVisibleTab(tb.getFirstVisibleTabClient()));
if (firstTabOutOfView != null) {
return tb.getLastKnownTabWidth(firstTabOutOfView);
}
return 0;
}

/** For internal use only. May be removed or replaced in the future. */
public void showAllTabs() {
scrollerIndex = tb.getFirstVisibleTab();
@@ -1385,10 +1493,8 @@ public class VTabsheet extends VTabsheetBase
}

private boolean isClippedTabs() {
return (tb.getOffsetWidth() - DOM.getElementPropertyInt(
(Element) tb.getContainerElement().getLastChild().cast(),
"offsetWidth")) > getOffsetWidth()
- (isScrolledTabs() ? scroller.getOffsetWidth() : 0);
return (tb.getOffsetWidth() - getSpacerWidth()) > getOffsetWidth()
- (isScrolledTabs() ? scroller.getOffsetWidth() : 0);
}

private boolean isClipped(Tab tab) {
@@ -1396,6 +1502,12 @@ public class VTabsheet extends VTabsheetBase
+ getOffsetWidth() - scroller.getOffsetWidth();
}

private int getSpacerWidth() {
int spacerWidth = ((Element) tb.getContainerElement().getLastChild()
.cast()).getPropertyInt("offsetWidth");
return spacerWidth;
}

@Override
protected void clearPaintables() {

@@ -1584,8 +1696,6 @@ public class VTabsheet extends VTabsheetBase
*
* @param blurSource
* the source.
* @param focusedTabProvider
* provides the current focused tab.
*/
public BlurCommand(Tab blurSource) {
this.blurSource = blurSource;
@@ -1936,13 +2046,16 @@ public class VTabsheet extends VTabsheetBase
// On IE8 a tab with false visibility would have the bounds of the
// full TabBar.
if (!tab.isVisible()) {
while (!tab.isVisible()) {
while (!tab.isVisible() && scrollerIndex > 0) {
scrollerIndex = tb.scrollLeft(scrollerIndex);
}
updateTabScroller();

} else if (isClipped(tab)) {
while (isClipped(tab) && scrollerIndex != -1) {
} else if (isClipped(tab)
&& scrollerIndex < tb.getLastVisibleTab()) {
int tabIndex = tb.getTabIndex(tab);
while (isClipped(tab) && scrollerIndex >= 0
&& scrollerIndex < tabIndex) {
scrollerIndex = tb.scrollRight(scrollerIndex);
}
updateTabScroller();

+ 9
- 0
client/src/main/java/com/vaadin/client/ui/VUpload.java View File

@@ -25,6 +25,7 @@ import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.FormElement;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.FileUpload;
@@ -405,4 +406,12 @@ public class VUpload extends SimplePanel {
private static Logger getLogger() {
return Logger.getLogger(VUpload.class.getName());
}

public void setAcceptMimeTypes(String acceptMimeTypes) {
if (acceptMimeTypes == null || acceptMimeTypes.isEmpty()) {
InputElement.as(fu.getElement()).setAccept(null);
} else {
InputElement.as(fu.getElement()).setAccept(acceptMimeTypes);
}
}
}

+ 45
- 0
client/src/main/java/com/vaadin/client/ui/checkbox/CheckBoxConnector.java View File

@@ -15,6 +15,10 @@
*/
package com.vaadin.client.ui.checkbox;

import java.util.List;

import com.google.gwt.core.client.JsArrayString;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.DOM;
@@ -30,6 +34,7 @@ import com.vaadin.client.ui.Icon;
import com.vaadin.client.ui.VCheckBox;
import com.vaadin.shared.EventId;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.ComponentStateUtil;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.checkbox.CheckBoxServerRpc;
import com.vaadin.shared.ui.checkbox.CheckBoxState;
@@ -45,6 +50,22 @@ import com.vaadin.ui.CheckBox;
public class CheckBoxConnector extends AbstractFieldConnector
implements ClickHandler {

/**
* The style names from getState().inputStyles which are currently applied
* to the checkbox.
*
* @since 8.7
*/
private JsArrayString inputStyleNames = JsArrayString.createArray().cast();

/**
* The style names from getState().labelStyles which are currently applied
* to the checkbox.
*
* @since 8.7
*/
private JsArrayString labelStyleNames = JsArrayString.createArray().cast();

@Override
public boolean delegateCaptionHandling() {
return false;
@@ -88,6 +109,12 @@ public class CheckBoxConnector extends AbstractFieldConnector
VCaption.setCaptionText(getWidget(), getState());

getWidget().setValue(getState().checked);

// Set styles for input and label
updateStyles(getWidget().getInputElement(), inputStyleNames,
getState().inputStyles);
updateStyles(getWidget().getLabelElement(), labelStyleNames,
getState().labelStyles);
}

@Override
@@ -134,4 +161,22 @@ public class CheckBoxConnector extends AbstractFieldConnector
contextEventSunk = true;
}
}

private void updateStyles(Element clientElement,
JsArrayString clientSideStyles, List<String> serverSideStyes) {
// Remove all old stylenames
for (int i = 0; i < clientSideStyles.length(); i++) {
clientElement.removeClassName(clientSideStyles.get(i));
}
clientSideStyles.setLength(0);

if (ComponentStateUtil.hasStyles(serverSideStyes)) {
// add new style names
for (String newStyle : serverSideStyes) {
clientElement.addClassName(newStyle);
clientSideStyles.push(newStyle);
}

}
}
}

+ 5
- 1
client/src/main/java/com/vaadin/client/ui/datefield/TextualDateConnector.java View File

@@ -117,7 +117,7 @@ public abstract class TextualDateConnector<PANEL extends VAbstractCalendarPanel<
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
String oldLocale = getWidget().getCurrentLocale();
boolean isReadOnly = getWidget().isReadonly();
getWidget().parsable = getState().parsable;

super.onStateChanged(stateChangeEvent);
@@ -159,6 +159,10 @@ public abstract class TextualDateConnector<PANEL extends VAbstractCalendarPanel<
} else {
getWidget().calendarToggle.removeStyleName(
VAbstractPopupCalendar.CLASSNAME + "-button-readonly");
if (getState().readOnly != isReadOnly
&& getWidget().calendar.isInitialRenderDone()) {
getWidget().calendar.renderCalendar();
}
}

getWidget().setDescriptionForAssistiveDevices(

+ 106
- 89
client/src/main/java/com/vaadin/client/ui/menubar/MenuBarConnector.java View File

@@ -21,6 +21,7 @@ import java.util.Stack;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Timer;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.Paintable;
import com.vaadin.client.TooltipInfo;
@@ -64,110 +65,126 @@ public class MenuBarConnector extends AbstractComponentConnector
// For future connections
widget.client = client;
widget.uidlId = uidl.getId();
Timer timer = new Timer() {

// Empty the menu every time it receives new information
if (!widget.getItems().isEmpty()) {
widget.clearItems();
}

UIDL options = uidl.getChildUIDL(0);

if (null != getState()
&& !ComponentStateUtil.isUndefinedWidth(getState())) {
UIDL moreItemUIDL = options.getChildUIDL(0);
StringBuilder itemHTML = new StringBuilder();

if (moreItemUIDL.hasAttribute("icon")) {
Icon icon = client
.getIcon(moreItemUIDL.getStringAttribute("icon"));
if (icon != null) {
itemHTML.append(icon.getElement().getString());
@Override
public void run() {
// Empty the menu every time it receives new information
if (!widget.getItems().isEmpty()) {
widget.clearItems();
}
}

String moreItemText = moreItemUIDL.getStringAttribute("text");
if ("".equals(moreItemText)) {
moreItemText = "&#x25BA;";
}
itemHTML.append(moreItemText);
UIDL options = uidl.getChildUIDL(0);

widget.moreItem = GWT.create(VMenuBar.CustomMenuItem.class);
widget.moreItem.setHTML(itemHTML.toString());
widget.moreItem.setCommand(VMenuBar.emptyCommand);
if (null != getState()
&& !ComponentStateUtil.isUndefinedWidth(getState())) {
UIDL moreItemUIDL = options.getChildUIDL(0);
StringBuilder itemHTML = new StringBuilder();

widget.collapsedRootItems = new VMenuBar(true, widget);
widget.moreItem.setSubMenu(widget.collapsedRootItems);
widget.moreItem.addStyleName(
widget.getStylePrimaryName() + "-more-menuitem");
}

UIDL uidlItems = uidl.getChildUIDL(1);
Iterator<Object> itr = uidlItems.iterator();
Stack<Iterator<Object>> iteratorStack = new Stack<>();
Stack<VMenuBar> menuStack = new Stack<>();
VMenuBar currentMenu = widget;

while (itr.hasNext()) {
UIDL item = (UIDL) itr.next();
VMenuBar.CustomMenuItem currentItem = null;

final int itemId = item.getIntAttribute("id");
if (moreItemUIDL.hasAttribute("icon")) {
Icon icon = client.getIcon(
moreItemUIDL.getStringAttribute("icon"));
if (icon != null) {
itemHTML.append(icon.getElement().getString());
}
}

boolean itemHasCommand = item.hasAttribute("command");
boolean itemIsCheckable = item
.hasAttribute(MenuBarConstants.ATTRIBUTE_CHECKED);
String moreItemText = moreItemUIDL
.getStringAttribute("text");
if ("".equals(moreItemText)) {
moreItemText = "&#x25BA;";
}
itemHTML.append(moreItemText);

String itemHTML = widget.buildItemHTML(item);
widget.moreItem = GWT.create(VMenuBar.CustomMenuItem.class);
widget.moreItem.setHTML(itemHTML.toString());
widget.moreItem.setCommand(VMenuBar.emptyCommand);

Command cmd = null;
if (!item.hasAttribute("separator")) {
if (itemHasCommand || itemIsCheckable) {
// Construct a command that fires onMenuClick(int) with the
// item's id-number
cmd = () -> widget.hostReference.onMenuClick(itemId);
widget.collapsedRootItems = new VMenuBar(true, widget);
widget.moreItem.setSubMenu(widget.collapsedRootItems);
widget.moreItem.addStyleName(
widget.getStylePrimaryName() + "-more-menuitem");
}
}

currentItem = currentMenu.addItem(itemHTML, cmd);
currentItem.setId("" + itemId);
currentItem.updateFromUIDL(item, client);

if (item.getChildCount() > 0) {
menuStack.push(currentMenu);
iteratorStack.push(itr);
itr = item.iterator();
currentMenu = new VMenuBar(true, currentMenu);
client.getVTooltip().connectHandlersToWidget(currentMenu);
// this is the top-level style that also propagates to items -
// any item specific styles are set above in
// currentItem.updateFromUIDL(item, client)
if (ComponentStateUtil.hasStyles(getState())) {
for (String style : getState().styles) {
currentMenu.addStyleDependentName(style);
UIDL uidlItems = uidl.getChildUIDL(1);
Iterator<Object> itr = uidlItems.iterator();
Stack<Iterator<Object>> iteratorStack = new Stack<>();
Stack<VMenuBar> menuStack = new Stack<>();
VMenuBar currentMenu = widget;

while (itr.hasNext()) {
UIDL item = (UIDL) itr.next();
VMenuBar.CustomMenuItem currentItem = null;

final int itemId = item.getIntAttribute("id");

boolean itemHasCommand = item.hasAttribute("command");
boolean itemIsCheckable = item
.hasAttribute(MenuBarConstants.ATTRIBUTE_CHECKED);

String itemHTML = widget.buildItemHTML(item);

Command cmd = null;
if (!item.hasAttribute("separator")) {
if (itemHasCommand || itemIsCheckable) {
// Construct a command that fires onMenuClick(int)
// with the
// item's id-number
cmd = () -> widget.hostReference
.onMenuClick(itemId);
}
}
}
currentItem.setSubMenu(currentMenu);
}

while (!itr.hasNext() && !iteratorStack.empty()) {
boolean hasCheckableItem = false;
for (VMenuBar.CustomMenuItem menuItem : currentMenu
.getItems()) {
hasCheckableItem = hasCheckableItem
|| menuItem.isCheckable();
}
if (hasCheckableItem) {
currentMenu.addStyleDependentName("check-column");
} else {
currentMenu.removeStyleDependentName("check-column");
}
currentItem = currentMenu.addItem(itemHTML, cmd);
currentItem.setId("" + itemId);
currentItem.updateFromUIDL(item, client);

if (item.getChildCount() > 0) {
menuStack.push(currentMenu);
iteratorStack.push(itr);
itr = item.iterator();
currentMenu = new VMenuBar(true, currentMenu);
client.getVTooltip()
.connectHandlersToWidget(currentMenu);
// this is the top-level style that also propagates to
// items -
// any item specific styles are set above in
// currentItem.updateFromUIDL(item, client)
if (ComponentStateUtil.hasStyles(getState())) {
for (String style : getState().styles) {
currentMenu.addStyleDependentName(style);
}
}
currentItem.setSubMenu(currentMenu);
}

itr = iteratorStack.pop();
currentMenu = menuStack.pop();
while (!itr.hasNext() && !iteratorStack.empty()) {
boolean hasCheckableItem = false;
for (VMenuBar.CustomMenuItem menuItem : currentMenu
.getItems()) {
hasCheckableItem = hasCheckableItem
|| menuItem.isCheckable();
}
if (hasCheckableItem) {
currentMenu.addStyleDependentName("check-column");
} else {
currentMenu
.removeStyleDependentName("check-column");
}

itr = iteratorStack.pop();
currentMenu = menuStack.pop();
}
}
}
};
getLayoutManager().setNeedsHorizontalLayout(MenuBarConnector.this);
if (widget.mouseDownPressed) {
timer.schedule(getState().delayMs);
widget.mouseDownPressed = false;
} else {
timer.run();
}

getLayoutManager().setNeedsHorizontalLayout(this);
}

@Override

+ 24
- 3
client/src/main/java/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java View File

@@ -15,19 +15,24 @@
*/
package com.vaadin.client.ui.nativebutton;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.VCaption;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.ConnectorFocusAndBlurHandler;
import com.vaadin.client.ui.Icon;
import com.vaadin.client.ui.VNativeButton;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.button.ButtonServerRpc;
import com.vaadin.shared.ui.button.NativeButtonState;
import com.vaadin.ui.NativeButton;

@Connect(NativeButton.class)
public class NativeButtonConnector extends AbstractComponentConnector {
public class NativeButtonConnector extends AbstractComponentConnector
implements ClickHandler {

@Override
public void init() {
@@ -37,6 +42,7 @@ public class NativeButtonConnector extends AbstractComponentConnector {
getWidget().client = getConnection();
getWidget().paintableId = getConnectorId();

getWidget().addClickHandler(this);
ConnectorFocusAndBlurHandler.addHandlers(this);
}

@@ -49,8 +55,6 @@ public class NativeButtonConnector extends AbstractComponentConnector {
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);

getWidget().disableOnClick = getState().disableOnClick;

// Set text
VCaption.setCaptionText(getWidget(), getState());

@@ -77,4 +81,21 @@ public class NativeButtonConnector extends AbstractComponentConnector {
public NativeButtonState getState() {
return (NativeButtonState) super.getState();
}

@Override
public void onClick(ClickEvent event) {
if (getState().disableOnClick) {
getState().enabled = false;
super.updateEnabledState(false);
getRpcProxy(ButtonServerRpc.class).disableOnClick();
}

// Add mouse details
MouseEventDetails details = MouseEventDetailsBuilder
.buildMouseEventDetails(event.getNativeEvent(),
getWidget().getElement());
getRpcProxy(ButtonServerRpc.class).click(details);

getWidget().clickPending = false;
}
}

+ 4
- 0
client/src/main/java/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java View File

@@ -95,10 +95,14 @@ public class NativeSelectConnector
ListBox listBox = getWidget().getListBox();
boolean hasEmptyItem = listBox.getItemCount() > 0
&& listBox.getValue(0).isEmpty();
getWidget().setEmptySelectionAllowed(getState().emptySelectionAllowed);
if (hasEmptyItem && getState().emptySelectionAllowed) {
listBox.setItemText(0, getState().emptySelectionCaption);
} else if (hasEmptyItem && !getState().emptySelectionAllowed) {
listBox.removeItem(0);
if (getWidget().getListBox().getSelectedIndex() == 0) {
getWidget().setSelectedItem(null);
}
} else if (!hasEmptyItem && getState().emptySelectionAllowed) {
listBox.insertItem(getState().emptySelectionCaption, 0);
listBox.setValue(0, "");

+ 48
- 37
client/src/main/java/com/vaadin/client/ui/ui/UIConnector.java View File

@@ -15,16 +15,6 @@
*/
package com.vaadin.client.ui.ui;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
@@ -101,9 +91,18 @@ import com.vaadin.shared.ui.ui.UIServerRpc;
import com.vaadin.shared.ui.ui.UIState;
import com.vaadin.shared.util.SharedUtil;
import com.vaadin.ui.UI;

import elemental.client.Browser;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

@Connect(value = UI.class, loadStyle = LoadStyle.EAGER)
public class UIConnector extends AbstractSingleComponentContainerConnector
implements Paintable, MayScrollChildren {
@@ -375,34 +374,18 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
if (uidl.hasAttribute("focused")) {
// set focused component when render phase is finished
Scheduler.get().scheduleDeferred(() -> {
ComponentConnector connector = (ComponentConnector) uidl
.getPaintableAttribute("focused", getConnection());
Timer timer = new Timer() {
@Override
public void run() {
ComponentConnector connector = (ComponentConnector) uidl
.getPaintableAttribute("focused",
getConnection());

if (connector == null) {
// Do not try to focus invisible components which not
// present in UIDL
return;
}
focus(connector);
}
};

final Widget toBeFocused = connector.getWidget();
/*
* Two types of Widgets can be focused, either implementing GWT
* Focusable of a thinner Vaadin specific Focusable interface.
*/
if (toBeFocused instanceof com.google.gwt.user.client.ui.Focusable) {
final com.google.gwt.user.client.ui.Focusable toBeFocusedWidget = (com.google.gwt.user.client.ui.Focusable) toBeFocused;
toBeFocusedWidget.setFocus(true);
} else if (toBeFocused instanceof Focusable) {
((Focusable) toBeFocused).focus();
} else {
getLogger().severe(
"Server is trying to set focus to the widget of connector "
+ Util.getConnectorString(connector)
+ " but it is not focusable. The widget should implement either "
+ com.google.gwt.user.client.ui.Focusable.class
.getName()
+ " or " + Focusable.class.getName());
}
timer.schedule(0);
});
}

@@ -437,6 +420,34 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
}
}

private void focus(ComponentConnector connector) {
if (connector == null) {
// Do not try to focus invisible components which not
// present in UIDL
return;
}

final Widget toBeFocused = connector.getWidget();
/*
* Two types of Widgets can be focused, either implementing GWT
* Focusable of a thinner Vaadin specific Focusable interface.
*/
if (toBeFocused instanceof com.google.gwt.user.client.ui.Focusable) {
final com.google.gwt.user.client.ui.Focusable toBeFocusedWidget = (com.google.gwt.user.client.ui.Focusable) toBeFocused;
toBeFocusedWidget.setFocus(true);
} else if (toBeFocused instanceof Focusable) {
((Focusable) toBeFocused).focus();
} else {
getLogger().severe(
"Server is trying to set focus to the widget of connector "
+ Util.getConnectorString(connector)
+ " but it is not focusable. The widget should implement either "
+ com.google.gwt.user.client.ui.Focusable.class
.getName()
+ " or " + Focusable.class.getName());
}
}

/**
* Reads CSS strings and resources injected by {@link Styles#inject} from
* the UIDL stream.

+ 8
- 0
client/src/main/java/com/vaadin/client/widget/escalator/RowContainer.java View File

@@ -235,6 +235,14 @@ public interface RowContainer {
*/
public int getRowCount();

/**
* For internal use only. May be removed or replaced in the future.
*
* @since 8.7
* @return {@code true} if row height calculations have been scheduled
*/
public boolean isAutodetectingRowHeightLater();

/**
* The default height of the rows in this RowContainer.
*

+ 4
- 1
client/src/main/java/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java View File

@@ -644,7 +644,10 @@ public class MultiSelectionRenderer<T>
checkBox.setValue(data, false);
// this should be a temp fix.
checkBox.setText("Selects row number " + getDOMRowIndex(cell) + ".");
checkBox.setEnabled(grid.isEnabled() && !grid.isEditorActive());
boolean editorOpen = grid.isEditorActive();
boolean editorBuffered = grid.isEditorBuffered();
checkBox.setEnabled(
grid.isEnabled() && !(editorOpen && editorBuffered));
}

private int getDOMRowIndex(RendererCellReference cell) {

+ 2
- 0
client/src/main/java/com/vaadin/client/widgets/ChildFocusAwareFlowPanel.java View File

@@ -90,6 +90,8 @@ public class ChildFocusAwareFlowPanel extends FocusableFlowPanel
public ChildFocusAwareFlowPanel() {
eventBus = new HandlerManager(this);
getElement().getStyle().setOutlineStyle(OutlineStyle.NONE);
// The panel itself should not be focused.
getElement().setTabIndex(-1);
super.addFocusHandler(handler);
super.addBlurHandler(handler);
}

+ 36
- 8
client/src/main/java/com/vaadin/client/widgets/Escalator.java View File

@@ -67,7 +67,6 @@ import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ComputedStyle;
import com.vaadin.client.DeferredWorker;
import com.vaadin.client.LayoutManager;
import com.vaadin.client.Profiler;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.ui.SubPartAware;
@@ -1275,6 +1274,8 @@ public class Escalator extends Widget

private boolean initialColumnSizesCalculated = false;

private boolean autodetectingRowHeightLater = false;

public AbstractRowContainer(
final TableSectionElement rowContainerElement) {
root = rowContainerElement;
@@ -2054,6 +2055,7 @@ public class Escalator extends Widget
defaultRowHeightShouldBeAutodetected = false;
defaultRowHeight = px;
reapplyDefaultRowHeights();
applyHeightByRows();
}

@Override
@@ -2115,14 +2117,21 @@ public class Escalator extends Widget
}

public void autodetectRowHeightLater() {
autodetectingRowHeightLater = true;
Scheduler.get().scheduleFinally(() -> {
if (defaultRowHeightShouldBeAutodetected && isAttached()) {
autodetectRowHeightNow();
defaultRowHeightShouldBeAutodetected = false;
}
autodetectingRowHeightLater = false;
});
}

@Override
public boolean isAutodetectingRowHeightLater() {
return autodetectingRowHeightLater;
}

private void fireRowHeightChangedEventFinally() {
if (!rowHeightChangedEventFired) {
rowHeightChangedEventFired = true;
@@ -2898,10 +2907,14 @@ public class Escalator extends Widget
*/
scroller.recalculateScrollbarsForVirtualViewport();

double spacerHeightsSumUntilIndex = spacerContainer
.getSpacerHeightsSumUntilIndex(index);
final boolean addedRowsAboveCurrentViewport = index
* getDefaultRowHeight() < getScrollTop();
* getDefaultRowHeight()
+ spacerHeightsSumUntilIndex < getScrollTop();
final boolean addedRowsBelowCurrentViewport = index
* getDefaultRowHeight() > getScrollTop()
* getDefaultRowHeight()
+ spacerHeightsSumUntilIndex > getScrollTop()
+ getHeightOfSection();

if (addedRowsAboveCurrentViewport) {
@@ -3895,6 +3908,7 @@ public class Escalator extends Widget
visualRowOrder.getLast()) + 1;
moveAndUpdateEscalatorRows(Range.withOnly(0),
visualRowOrder.size(), newLogicalIndex);
updateTopRowLogicalIndex(1);
}
}
}
@@ -3915,13 +3929,18 @@ public class Escalator extends Widget
Profiler.enter(
"Escalator.BodyRowContainer.reapplyDefaultRowHeights");

double spacerHeights = 0;

/* step 1: resize and reposition rows */
for (int i = 0; i < visualRowOrder.size(); i++) {
TableRowElement tr = visualRowOrder.get(i);
reapplyRowHeight(tr, getDefaultRowHeight());

final int logicalIndex = getTopRowLogicalIndex() + i;
setRowPosition(tr, 0, logicalIndex * getDefaultRowHeight());
setRowPosition(tr, 0,
logicalIndex * getDefaultRowHeight() + spacerHeights);

spacerHeights += spacerContainer.getSpacerHeight(logicalIndex);
}

/*
@@ -5587,10 +5606,19 @@ public class Escalator extends Widget
*/
public void shiftSpacersByRows(int index, int numberOfRows) {
final double pxDiff = numberOfRows * body.getDefaultRowHeight();
for (SpacerContainer.SpacerImpl spacer : getSpacersForRowAndAfter(
index)) {
spacer.setPositionDiff(0, pxDiff);
spacer.setRowIndex(spacer.getRow() + numberOfRows);
List<SpacerContainer.SpacerImpl> spacers = new ArrayList<>(
getSpacersForRowAndAfter(index));
if (numberOfRows < 0) {
for (SpacerContainer.SpacerImpl spacer : spacers) {
spacer.setPositionDiff(0, pxDiff);
spacer.setRowIndex(spacer.getRow() + numberOfRows);
}
} else {
for (int i = spacers.size() - 1; i >= 0; --i) {
SpacerContainer.SpacerImpl spacer = spacers.get(i);
spacer.setPositionDiff(0, pxDiff);
spacer.setRowIndex(spacer.getRow() + numberOfRows);
}
}
}


+ 21
- 4
client/src/main/java/com/vaadin/client/widgets/Grid.java View File

@@ -76,10 +76,7 @@ import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.ResizeComposite;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.DeferredWorker;
import com.vaadin.client.Focusable;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.*;
import com.vaadin.client.WidgetUtil.Reference;
import com.vaadin.client.data.DataChangeHandler;
import com.vaadin.client.data.DataSource;
@@ -3342,6 +3339,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
*/
private class AutoColumnWidthsRecalculator {
private double lastCalculatedInnerWidth = -1;
private double lastCalculatedInnerHeight = -1;

private final ScheduledCommand calculateCommand = new ScheduledCommand() {

@@ -3413,6 +3411,8 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,

// Make SelectAllCheckbox visible
getSelectionColumn().ifPresent(col -> {
if (getDefaultHeaderRow() == null)
return;
HeaderCell headerCell = getDefaultHeaderRow().getCell(col);
if (headerCell.getType().equals(GridStaticCellType.WIDGET)) {
// SelectAllCheckbox is present already
@@ -3434,6 +3434,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,

// Update latest width to prevent recalculate on height change.
lastCalculatedInnerWidth = escalator.getInnerWidth();
lastCalculatedInnerHeight = getEscalatorInnerHeight();
}

private boolean columnsAreGuaranteedToBeWiderThanGrid() {
@@ -9146,6 +9147,17 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
recalculateColumnWidths();
}

if (getEscalatorInnerHeight() != autoColumnWidthsRecalculator.lastCalculatedInnerHeight) {
Scheduler.get().scheduleFinally(() -> {
// Trigger re-calculation of all row positions.
RowContainer.BodyRowContainer body = getEscalator()
.getBody();
if (!body.isAutodetectingRowHeightLater()) {
body.setDefaultRowHeight(body.getDefaultRowHeight());
}
});
}

// Vertical resizing could make editor positioning invalid so it
// needs to be recalculated on resize
if (isEditorActive()) {
@@ -9159,6 +9171,11 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
});
}

private double getEscalatorInnerHeight() {
return new ComputedStyle(getEscalator().getTableWrapper())
.getHeightIncludingBorderPadding();
}

/**
* Grid does not support adding Widgets this way.
* <p>

+ 1
- 1
client/src/main/resources/com/vaadin/DefaultWidgetSet.gwt.xml View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.8.1//EN" "http://gwtproject.org/doctype/2.8.1/gwt-module.dtd">
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.8.2//EN" "http://www.gwtproject.org/doctype/2.8.2/gwt-module.dtd">
<module>
<!-- This GWT module defines the Vaadin DefaultWidgetSet. This is the module
you want to extend when creating an extended widget set, or when creating

+ 1
- 1
client/src/main/resources/com/vaadin/Vaadin.gwt.xml View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.8.1//EN" "http://gwtproject.org/doctype/2.8.1/gwt-module.dtd">
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.8.2//EN" "http://www.gwtproject.org/doctype/2.8.2/gwt-module.dtd">
<module>
<!-- This GWT module inherits all Vaadin client side functionality modules.
This is the module you want to inherit in your client side project to be

+ 1
- 1
compatibility-client-compiled/pom.xml View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-root</artifactId>
<version>8.5-SNAPSHOT</version>
<version>8.8-SNAPSHOT</version>
</parent>
<artifactId>vaadin-compatibility-client-compiled</artifactId>
<name>vaadin-compatibility-client-compiled</name>

+ 6
- 23
compatibility-client-compiled/src/main/java/com/vaadin/osgi/compatibility/widgetset/CompatibilityWidgetsetContribution.java View File

@@ -15,33 +15,16 @@
*/
package com.vaadin.osgi.compatibility.widgetset;

import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.http.HttpService;

import com.vaadin.osgi.resources.OsgiVaadinResources;
import com.vaadin.osgi.resources.VaadinResourceService;

@Component(immediate = true)
public class CompatibilityWidgetsetContribution {
private HttpService httpService;
import com.vaadin.osgi.resources.OsgiVaadinWidgetset;

@Component
public class CompatibilityWidgetsetContribution implements OsgiVaadinWidgetset {
private static final String WIDGETSET_NAME = "com.vaadin.v7.Vaadin7WidgetSet";

@Activate
void startup(ComponentContext context) throws Exception {
VaadinResourceService service = OsgiVaadinResources.getService();
service.publishWidgetset(WIDGETSET_NAME, httpService);
}

@Reference
void setHttpService(HttpService httpService) {
this.httpService = httpService;
}

void unsetHttpService(HttpService httpService) {
this.httpService = null;
@Override
public String getName() {
return WIDGETSET_NAME;
}
}

+ 1
- 1
compatibility-client/pom.xml View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-root</artifactId>
<version>8.5-SNAPSHOT</version>
<version>8.8-SNAPSHOT</version>
</parent>
<artifactId>vaadin-compatibility-client</artifactId>
<name>vaadin-compatibility-client</name>

+ 58
- 38
compatibility-client/src/main/java/com/vaadin/v7/client/connectors/GridConnector.java View File

@@ -176,6 +176,28 @@ public class GridConnector extends AbstractHasComponentsConnector
this.id = id;
}

/**
* Creates and initializes a custom grid column with attributes of given state.
*
* @param state with attributes to initialize the column.
*/
@SuppressWarnings("unchecked")
private CustomGridColumn(GridColumnState state) {
this(state.id, (AbstractGridRendererConnector<Object>) state.rendererConnector);
this.hidingToggleCaption = state.hidingToggleCaption;
this.hidden = state.hidden;
this.hidable = state.hidable;
this.resizable = state.resizable;
this.sortable = state.sortable;
this.headerCaption = state.headerCaption == null ? "" : state.headerCaption;
this.widthUser = state.width;
this.minimumWidthPx = state.minWidth;
this.maximumWidthPx = state.maxWidth;
this.expandRatio = state.expandRatio;
this.editable = state.editable;
setEditorConnector((AbstractComponentConnector) state.editorConnector);
}

/**
* Sets a new renderer for this column object
*
@@ -472,7 +494,8 @@ public class GridConnector extends AbstractHasComponentsConnector
} else {
getLogger().warning(
"Visibility changed for a unknown column type in Grid: "
+ column + ", type " + column.getClass());
+ column.toString() + ", type "
+ column.getClass());
}
}
}
@@ -544,9 +567,13 @@ public class GridConnector extends AbstractHasComponentsConnector
if (spacerCellBorderHeights != null
&& !getLayoutManager().isLayoutRunning()
&& hasDetailsOpen(rowIndex)) {
double height = getLayoutManager().getOuterHeightDouble(
element) + spacerCellBorderHeights;
getWidget().setDetailsHeight(rowIndex, height);
// Measure and set details height if element is visible
if (WidgetUtil.isDisplayed(element)) {
double height =
getLayoutManager().getOuterHeightDouble(
element) + spacerCellBorderHeights;
getWidget().setDetailsHeight(rowIndex, height);
}
}
}
};
@@ -890,13 +917,8 @@ public class GridConnector extends AbstractHasComponentsConnector
// Remove old columns
purgeRemovedColumns();

// Add new columns
for (GridColumnState state : getState().columns) {
if (!columnIdToColumn.containsKey(state.id)) {
addColumnFromStateChangeEvent(state);
}
updateColumnFromStateChangeEvent(state);
}
// Update all columns
updateColumnsFromState();
}

if (stateChangeEvent.hasPropertyChanged("columnOrder")) {
@@ -1099,37 +1121,33 @@ public class GridConnector extends AbstractHasComponentsConnector
cell.setStyleName(cellState.styleName);
}

/**
* Updates a column from a state change event.
*
* @param columnIndex
* The index of the column to update
*/
private void updateColumnFromStateChangeEvent(GridColumnState columnState) {
CustomGridColumn column = columnIdToColumn.get(columnState.id);

columnsUpdatedFromState = true;
updateColumnFromState(column, columnState);
columnsUpdatedFromState = false;
}

/**
* Adds a new column to the grid widget from a state change event
* Update columns from the current state.
*
* @param columnIndex
* The index of the column, according to how it
*/
private void addColumnFromStateChangeEvent(GridColumnState state) {
private void updateColumnsFromState() {
this.columnsUpdatedFromState = true;
final List<Column<?, JsonObject>> columns = new ArrayList<Column<?, JsonObject>>(getState().columns.size());
for (String columnId : getState().columnOrder) {
for (GridColumnState state : getState().columns) {
if (state.id.equals(columnId)) {
CustomGridColumn column = this.columnIdToColumn.get(state.id);
if (column == null) {
column = new CustomGridColumn(state);
this.columnIdToColumn.put(state.id, column);
this.columnOrder.add(state.id);
columns.add(column);
} else {
updateColumnFromState(column, state);
}
}
}
}
@SuppressWarnings("unchecked")
CustomGridColumn column = new CustomGridColumn(state.id,
((AbstractGridRendererConnector<Object>) state.rendererConnector));
columnIdToColumn.put(state.id, column);

/*
* Add column to grid. Reordering is handled as a separate problem.
*/
getWidget().addColumn(column);
columnOrder.add(state.id);
final Column<?, JsonObject>[] columnArray = columns.toArray(new Column[0]);
getWidget().addColumns(columnArray);
this.columnsUpdatedFromState = false;
}

/**
@@ -1148,7 +1166,8 @@ public class GridConnector extends AbstractHasComponentsConnector
column.setMaximumWidth(state.maxWidth);
column.setExpandRatio(state.expandRatio);

assert state.rendererConnector instanceof AbstractGridRendererConnector : "GridColumnState.rendererConnector is invalid (not subclass of AbstractGridRendererConnector)";
assert state.rendererConnector instanceof AbstractGridRendererConnector : "GridColumnState.rendererConnector is invalid (not subclass of "
+ "AbstractRendererConnector)";
column.setRenderer(
(AbstractGridRendererConnector<Object>) state.rendererConnector);

@@ -1322,6 +1341,7 @@ public class GridConnector extends AbstractHasComponentsConnector
info.setContentMode(contentMode);
return info;
}

@Override
protected void sendContextClickEvent(MouseEventDetails details,
EventTarget eventTarget) {

+ 65
- 4
compatibility-client/src/main/java/com/vaadin/v7/client/ui/VFilterSelect.java View File

@@ -25,6 +25,8 @@ import java.util.Locale;
import java.util.Set;
import java.util.logging.Logger;

import com.google.gwt.animation.client.AnimationScheduler;
import com.google.gwt.animation.client.AnimationScheduler.AnimationCallback;
import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.Scheduler;
@@ -56,6 +58,7 @@ import com.google.gwt.i18n.client.HasDirection.Direction;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Event.NativePreviewEvent;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
@@ -355,8 +358,10 @@ public class VFilterSelect extends Composite
private int popupOuterPadding = -1;

private int topPosition;
private int leftPosition;

private final MouseWheeler mouseWheeler = new MouseWheeler();
private boolean scrollPending = false;

/**
* Default constructor
@@ -444,12 +449,11 @@ public class VFilterSelect extends Composite
getElement().setId("VAADIN_COMBOBOX_OPTIONLIST");

menu.setSuggestions(currentSuggestions);
final int x = VFilterSelect.this.getAbsoluteLeft();
leftPosition = getDesiredLeftPosition();

topPosition = tb.getAbsoluteTop();
topPosition += tb.getOffsetHeight();
topPosition = getDesiredTopPosition();

setPopupPosition(x, topPosition);
setPopupPosition(leftPosition, topPosition);

int nullOffset = (nullSelectionAllowed
&& "".equals(lastFilter) ? 1 : 0);
@@ -496,6 +500,22 @@ public class VFilterSelect extends Composite
});
}

private native int toInt32(double val)
/*-{
return val | 0;
}-*/;

private int getDesiredTopPosition() {
return toInt32(WidgetUtil.getBoundingClientRect(tb.getElement())
.getBottom()) + Window.getScrollTop();
}

private int getDesiredLeftPosition() {
return toInt32(WidgetUtil
.getBoundingClientRect(VFilterSelect.this.getElement())
.getLeft());
}

/**
* Should the next page button be visible to the user?
*
@@ -682,6 +702,47 @@ public class VFilterSelect extends Composite
handleMouseDownEvent(event);
}

@Override
protected void onPreviewNativeEvent(NativePreviewEvent event) {
// Check all events outside the combobox to see if they scroll the
// page. We cannot use e.g. Window.addScrollListener() because the
// scrolled element can be at any level on the page.

// Normally this is only called when the popup is showing, but make
// sure we don't accidentally process all events when not showing.
if (!scrollPending && isShowing() && !DOM.isOrHasChild(
SuggestionPopup.this.getElement(),
Element.as(event.getNativeEvent().getEventTarget()))) {
if (getDesiredLeftPosition() != leftPosition
|| getDesiredTopPosition() != topPosition) {
updatePopupPositionOnScroll();
}
}

super.onPreviewNativeEvent(event);
}

/**
* Make the popup follow the position of the ComboBox when the page is
* scrolled.
*/
private void updatePopupPositionOnScroll() {
if (!scrollPending) {
AnimationScheduler.get()
.requestAnimationFrame(new AnimationCallback() {
public void execute(double timestamp) {
if (isShowing()) {
leftPosition = getDesiredLeftPosition();
topPosition = getDesiredTopPosition();
setPopupPosition(leftPosition, topPosition);
}
scrollPending = false;
}
});
scrollPending = true;
}
}

/**
* Should paging be enabled. If paging is enabled then only a certain
* amount of items are visible at a time and a scrollbar or buttons are

+ 16
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/RowContainer.java View File

@@ -220,6 +220,22 @@ public interface RowContainer {
*/
public int getRowCount();

/**
* This method calculates the current row count directly from the DOM.
* <p>
* While the container is stable, this value should equal to
* {@link #getRowCount()}, but while row counts are being updated, these two
* values might differ for a short while.
* <p>
* Any extra content, such as spacers for the body, should not be included
* in this count.
*
* @since 8.7
*
* @return the actual DOM count of rows
*/
public int getDomRowCount();

/**
* The default height of the rows in this RowContainer.
*

+ 84
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/events/SpacerVisibilityChangedEvent.java View File

@@ -0,0 +1,84 @@
/*
* Copyright 2000-2018 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.v7.client.widget.escalator.events;

import com.google.gwt.event.shared.GwtEvent;

/**
* Event fired when a spacer element is hidden or shown in Escalator.
*
* @author Vaadin Ltd
* @since 7.7.13
*/
public class SpacerVisibilityChangedEvent
extends GwtEvent<SpacerVisibilityChangedHandler> {

/**
* Handler type.
*/
public static final Type<SpacerVisibilityChangedHandler> TYPE = new Type<SpacerVisibilityChangedHandler>();

public static final Type<SpacerVisibilityChangedHandler> getType() {
return TYPE;
}

private final int rowIndex;
private final boolean visible;

/**
* Creates a spacer visibility changed event.
*
* @param rowIndex
* index of row to which the spacer belongs
* @param visible
* {@code true} if the spacer element is shown, {@code false} if the
* spacer element is hidden
*/
public SpacerVisibilityChangedEvent(int rowIndex, boolean visible) {
this.rowIndex = rowIndex;
this.visible = visible;
}

/**
* Gets the row index to which the spacer element belongs.
*
* @return the row index to which the spacer element belongs
*/
public int getRowIndex() {
return rowIndex;
}

/**
* Gets whether the spacer element is displayed.
*
* @return {@code true} if the spacer element is shown, {@code false} if the
* spacer element is hidden
*/
public boolean isVisible() {
return visible;
}

@Override
public Type<SpacerVisibilityChangedHandler> getAssociatedType() {
return TYPE;
}

@Override
protected void dispatch(SpacerVisibilityChangedHandler handler) {
handler.onSpacerVisibilityChanged(this);
}

}

+ 36
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/widget/escalator/events/SpacerVisibilityChangedHandler.java View File

@@ -0,0 +1,36 @@
/*
* Copyright 2000-2018 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.v7.client.widget.escalator.events;

import com.google.gwt.event.shared.EventHandler;

/**
* Event handler for a spacer visibility changed event.
*
* @author Vaadin Ltd
* @since 7.7.13
*/
public interface SpacerVisibilityChangedHandler extends EventHandler {

/**
* Called when a spacer visibility changed event is fired, when a spacer's
* visibility changes.
*
* @param event
* the spacer visibility changed event
*/
public void onSpacerVisibilityChanged(SpacerVisibilityChangedEvent event);
}

+ 5
- 16
compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Escalator.java View File

@@ -88,6 +88,7 @@ import com.vaadin.v7.client.widget.escalator.ScrollbarBundle.VerticalScrollbarBu
import com.vaadin.v7.client.widget.escalator.Spacer;
import com.vaadin.v7.client.widget.escalator.SpacerUpdater;
import com.vaadin.v7.client.widget.escalator.events.RowHeightChangedEvent;
import com.vaadin.v7.client.widget.escalator.events.SpacerVisibilityChangedEvent;
import com.vaadin.v7.client.widget.grid.events.ScrollEvent;
import com.vaadin.v7.client.widget.grid.events.ScrollHandler;
import com.vaadin.v7.client.widgets.Escalator.JsniUtil.TouchHandlerBundle;
@@ -1290,22 +1291,6 @@ public class Escalator extends Widget
return rows;
}

/**
* This method calculates the current row count directly from the DOM.
* <p>
* While Escalator is stable, this value should equal to
* {@link #getRowCount()}, but while row counts are being updated, these
* two values might differ for a short while.
* <p>
* Any extra content, such as spacers for the body, should not be
* included in this count.
*
* @since 7.5.0
*
* @return the actual DOM count of rows
*/
public abstract int getDomRowCount();

/**
* {@inheritDoc}
* <p>
@@ -4786,11 +4771,15 @@ public class Escalator extends Widget
public void show() {
getRootElement().getStyle().clearDisplay();
getDecoElement().getStyle().clearDisplay();
Escalator.this.fireEvent(
new SpacerVisibilityChangedEvent(getRow(), true));
}

public void hide() {
getRootElement().getStyle().setDisplay(Display.NONE);
getDecoElement().getStyle().setDisplay(Display.NONE);
Escalator.this.fireEvent(
new SpacerVisibilityChangedEvent(getRow(), false));
}

/**

+ 225
- 127
compatibility-client/src/main/java/com/vaadin/v7/client/widgets/Grid.java View File

@@ -114,6 +114,8 @@ import com.vaadin.v7.client.widget.escalator.Spacer;
import com.vaadin.v7.client.widget.escalator.SpacerUpdater;
import com.vaadin.v7.client.widget.escalator.events.RowHeightChangedEvent;
import com.vaadin.v7.client.widget.escalator.events.RowHeightChangedHandler;
import com.vaadin.v7.client.widget.escalator.events.SpacerVisibilityChangedEvent;
import com.vaadin.v7.client.widget.escalator.events.SpacerVisibilityChangedHandler;
import com.vaadin.v7.client.widget.grid.AutoScroller;
import com.vaadin.v7.client.widget.grid.AutoScroller.AutoScrollerCallback;
import com.vaadin.v7.client.widget.grid.AutoScroller.ScrollAxis;
@@ -1316,6 +1318,23 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
private static final String ERROR_CLASS_NAME = "error";
private static final String NOT_EDITABLE_CLASS_NAME = "not-editable";

ScheduledCommand fieldFocusCommand = new ScheduledCommand() {
private int count = 0;

@Override
public void execute() {
Element focusedElement = WidgetUtil.getFocusedElement();
if (focusedElement == grid.getElement()
|| focusedElement == Document.get().getBody()
|| count > 2) {
focusColumn(focusedColumnIndexDOM);
} else {
++count;
Scheduler.get().scheduleDeferred(this);
}
}
};

/**
* A handler for events related to the Grid editor. Responsible for
* opening, moving or closing the editor based on the received event.
@@ -1875,7 +1894,11 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
}

if (i == focusedColumnIndexDOM) {
focusColumn(focusedColumnIndexDOM);
if (BrowserInfo.get().isIE8()) {
Scheduler.get().scheduleDeferred(fieldFocusCommand);
} else {
focusColumn(focusedColumnIndexDOM);
}
}
} else {
cell.addClassName(NOT_EDITABLE_CLASS_NAME);
@@ -2116,8 +2139,20 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,

private void updateHorizontalScrollPosition() {
double scrollLeft = grid.getScrollLeft();
cellWrapper.getStyle().setLeft(
frozenCellWrapper.getOffsetWidth() - scrollLeft, Unit.PX);
int frozenWidth = frozenCellWrapper.getOffsetWidth();
double newLeft = frozenWidth - scrollLeft;
cellWrapper.getStyle().setLeft(newLeft, Unit.PX);

// sometimes focus handling twists the editor row out of alignment
// with the grid itself and the position needs to be compensated for
TableRowElement rowElement = grid.getEscalator().getBody()
.getRowElement(grid.getEditor().getRow());
int rowLeft = rowElement.getAbsoluteLeft();
int editorLeft = cellWrapper.getAbsoluteLeft();
if (editorLeft != rowLeft + frozenWidth) {
cellWrapper.getStyle().setLeft(newLeft + rowLeft - editorLeft,
Unit.PX);
}
}

/**
@@ -2326,7 +2361,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
if (!Element.is(target)) {
return null;
}
return WidgetUtil.findWidget(Element.as(target), Grid.class);
return WidgetUtil.findWidget(Element.as(target), Grid.class, false);
}

/**
@@ -2354,6 +2389,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
} else if (container == getGrid().escalator.getBody()) {
section = Section.BODY;
}

doDispatch(handler, section);
}
}
@@ -2392,7 +2428,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
if (!Element.is(target)) {
return null;
}
return WidgetUtil.findWidget(Element.as(target), Grid.class);
return WidgetUtil.findWidget(Element.as(target), Grid.class, false);
}

/**
@@ -3148,7 +3184,8 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,

if (!columns.contains(column)) {
throw new IllegalArgumentException(
"Given column is not a column in this grid. " + column);
"Given column is not a column in this grid. "
+ column.toString());
}

if (!column.isSortable()) {
@@ -3475,7 +3512,8 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
*/
final double widthPerRatio;
int leftOver = 0;
if (BrowserInfo.getBrowserString().contains("PhantomJS")) {
if (BrowserInfo.get().isIE8() || BrowserInfo.get().isIE9()
|| BrowserInfo.getBrowserString().contains("PhantomJS")) {
// These browsers report subpixels as integers. this usually
// results into issues..
widthPerRatio = (int) (pixelsToDistribute / totalRatios);
@@ -4047,7 +4085,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
}

private String createHTML(Column<?, T> column) {
final StringBuilder buf = new StringBuilder();
final StringBuffer buf = new StringBuffer();
buf.append("<span class=\"");
if (column.isHidden()) {
buf.append("v-off");
@@ -4114,7 +4152,6 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
* on initialization, but not after that.
*/
private DataSource<T> dataSource;
private Registration changeHandler;

/**
* Currently available row range in DataSource.
@@ -4330,10 +4367,12 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
&& rightBoundaryForDrag < dropMarkerLeft
&& dropMarkerLeft <= escalator.getInnerWidth()) {
dropMarkerLeft = rightBoundaryForDrag - dropMarkerWidthOffset;
} else if (
}

// Check if the drop marker shouldn't be shown at all
dropMarkerLeft < frozenColumnsWidth || dropMarkerLeft > Math
.min(rightBoundaryForDrag, escalator.getInnerWidth())
else if (dropMarkerLeft < frozenColumnsWidth
|| dropMarkerLeft > Math.min(rightBoundaryForDrag,
escalator.getInnerWidth())
|| dropMarkerLeft < 0) {
dropMarkerLeft = -10000000;
}
@@ -4482,8 +4521,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
if (focusedColumnIndex == draggedColumnIndex) {
// move with the dragged column
int adjustedDropIndex = latestColumnDropIndex > draggedColumnIndex
? latestColumnDropIndex - 1
: latestColumnDropIndex;
? latestColumnDropIndex - 1 : latestColumnDropIndex;
// remove hidden columns from indexing
adjustedDropIndex = getVisibleColumns()
.indexOf(getColumn(adjustedDropIndex));
@@ -4714,8 +4752,8 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
@Override
public void render(RendererCellReference cell, Object data) {
if (!warned && !(data instanceof String)) {
getLogger().warning(
Column.this + ": " + DEFAULT_RENDERER_WARNING);
getLogger().warning(Column.this.toString() + ": "
+ DEFAULT_RENDERER_WARNING);
warned = true;
}

@@ -4736,33 +4774,65 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
private Grid<T> grid;

/**
* Width of column in pixels as {@link #setWidth(double)} has been
* called
* Width of column in pixels as {@link #setWidth(double)} has been called.
*/
private double widthUser = GridConstants.DEFAULT_COLUMN_WIDTH_PX;
protected double widthUser = GridConstants.DEFAULT_COLUMN_WIDTH_PX;

/**
* Renderer for rendering a value into the cell
*/
private Renderer<? super C> bodyRenderer;

private boolean sortable = false;
/**
* The sortable state of this column.
*/
protected boolean sortable = false;

private boolean editable = true;
/**
* The editable state of this column.
*/
protected boolean editable = true;

private boolean resizable = true;
/**
* The resizable state of this column.
*/
protected boolean resizable = true;

private boolean hidden = false;
/**
* The hidden state of this column.
*/
protected boolean hidden = false;

private boolean hidable = false;
/**
* The hidable state of this column.
*/
protected boolean hidable = false;

private String headerCaption = "";
/**
* The header-caption of this column.
*/
protected String headerCaption = "";

private String hidingToggleCaption = null;
/**
* The hiding-toggle-caption of this column.
*/
protected String hidingToggleCaption = null;

/**
* The minimum width in pixels of this column.
*/
protected double minimumWidthPx = GridConstants.DEFAULT_MIN_WIDTH;

/**
* The maximum width in pixels of this column.
*/
protected double maximumWidthPx = GridConstants.DEFAULT_MAX_WIDTH;

/**
* The expand ratio of this column.
*/
protected int expandRatio = GridConstants.DEFAULT_EXPAND_RATIO;

private double minimumWidthPx = GridConstants.DEFAULT_MIN_WIDTH;
private double maximumWidthPx = GridConstants.DEFAULT_MAX_WIDTH;
private int expandRatio = GridConstants.DEFAULT_EXPAND_RATIO;

/**
* Constructs a new column with a simple TextRenderer.
@@ -5644,7 +5714,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
if (renderer instanceof WidgetRenderer) {
try {
Widget w = WidgetUtil.findWidget(
cell.getElement().getFirstChildElement(), null);
cell.getElement().getFirstChildElement());
if (w != null) {

// Logical detach
@@ -5863,7 +5933,16 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
dragEnded();

col.setWidth(width);
fireEvent(new ColumnResizeEvent<T>(col));

// Need to wait for column width recalculation
// scheduled by setWidth() before firing the event
Scheduler.get().scheduleDeferred(
new ScheduledCommand() {
@Override
public void execute() {
fireEvent(new ColumnResizeEvent<T>(col));
}
});
}
};

@@ -6201,29 +6280,6 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
fireEvent(new GridEnabledEvent(enabled));
}

@Override
public void setStylePrimaryName(String style) {
super.setStylePrimaryName(style);
escalator.setStylePrimaryName(style);
editor.setStylePrimaryName(style);
sidebar.setStylePrimaryName(style + "-sidebar");
sidebar.addStyleName("v-contextmenu");

String rowStyle = getStylePrimaryName() + "-row";
rowHasDataStyleName = rowStyle + "-has-data";
rowSelectedStyleName = rowStyle + "-selected";
rowStripeStyleName = rowStyle + "-stripe";

cellFocusStyleName = getStylePrimaryName() + "-cell-focused";
rowFocusStyleName = getStylePrimaryName() + "-row-focused";

if (isAttached()) {
refreshHeader();
refreshBody();
refreshFooter();
}
}

/**
* Sets the column resize mode to use. The default mode is
* {@link ColumnResizeMode.ANIMATED}.
@@ -6241,12 +6297,36 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
* {@link ColumnResizeMode.ANIMATED}.
*
* @return a ColumnResizeMode value
*
* @since 7.7.5
*/
public ColumnResizeMode getColumnResizeMode() {
return columnResizeMode;
}

@Override
public void setStylePrimaryName(String style) {
super.setStylePrimaryName(style);
escalator.setStylePrimaryName(style);
editor.setStylePrimaryName(style);
sidebar.setStylePrimaryName(style + "-sidebar");
sidebar.addStyleName("v-contextmenu");

String rowStyle = getStylePrimaryName() + "-row";
rowHasDataStyleName = rowStyle + "-has-data";
rowSelectedStyleName = rowStyle + "-selected";
rowStripeStyleName = rowStyle + "-stripe";

cellFocusStyleName = getStylePrimaryName() + "-cell-focused";
rowFocusStyleName = getStylePrimaryName() + "-row-focused";

if (isAttached()) {
refreshHeader();
refreshBody();
refreshFooter();
}
}

/**
* Creates the escalator updater used to update the header rows in this
* grid. The updater is invoked when header rows or columns are added or
@@ -6369,9 +6449,24 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
* the columns to add
*/
public void addColumns(Column<?, T>... columns) {
int count = getColumnCount();
final int count = getColumnCount();
for (Column<?, T> column : columns) {
addColumn(column, count++);
checkColumnIsValidToAdd(column, count);
}
addColumnsSkipSelectionColumnCheck(Arrays.asList(columns), count);
}


/**
* Checks the given column is valid to add at the given index.
*/
private void checkColumnIsValidToAdd(Column<?, T> column, int index) {
if (column == this.selectionColumn) {
throw new IllegalArgumentException(
"The selection column may not be added manually");
} else if (this.selectionColumn != null && index == 0) {
throw new IllegalStateException("A column cannot be inserted "
+ "before the selection column");
}
}

@@ -6401,53 +6496,56 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
* and {@code index} is 0.
*/
public <C extends Column<?, T>> C addColumn(C column, int index) {
if (column == selectionColumn) {
throw new IllegalArgumentException(
"The selection column many " + "not be added manually");
} else if (selectionColumn != null && index == 0) {
throw new IllegalStateException("A column cannot be inserted "
+ "before the selection column");
}

addColumnSkipSelectionColumnCheck(column, index);
checkColumnIsValidToAdd(column, index);
addColumnsSkipSelectionColumnCheck(Collections.singleton(column), index);
return column;
}

private void addColumnSkipSelectionColumnCheck(Column<?, T> column,
int index) {
// Register column with grid
columns.add(index, column);

header.addColumn(column);
footer.addColumn(column);
private <C extends Column<?, T>> void addColumnsSkipSelectionColumnCheck(Collection<C> columnCollection, int index) {
int visibleNewColumns = 0;
int currentIndex = index;

// Register this grid instance with the column
((Column<?, T>) column).setGrid(this);
//prevent updates of hiding toggles.
//it will be updated finally all at once.
this.columnHider.hidingColumn = true;

// Grid knows about hidden columns, Escalator only knows about what is
// visible so column indexes do not match
if (!column.isHidden()) {
int escalatorIndex = index;
for (int existingColumn = 0; existingColumn < index; existingColumn++) {
if (getColumn(existingColumn).isHidden()) {
escalatorIndex--;
}
for (final Column<?, T> column : columnCollection) {
// Register column with grid
this.columns.add(currentIndex++, column);
this.footer.addColumn(column);
this.header.addColumn(column);

// Register this grid instance with the column
column.setGrid(this);

if (!column.isHidden()) {
visibleNewColumns++;
}
escalator.getColumnConfiguration().insertColumns(escalatorIndex, 1);
}
if (visibleNewColumns > 0) {
final ColumnConfiguration columnConfiguration = this.escalator.getColumnConfiguration();
columnConfiguration.insertColumns(index, visibleNewColumns);
}

// Reapply column width
column.reapplyWidth();
// Sink all renderer events
Set<String> events = new HashSet<String>();
events.addAll(getConsumedEventsForRenderer(column.getRenderer()));
for (final Column<?, T> column : columnCollection) {
// Reapply column width
column.reapplyWidth();
// Sink all renderer events
final Set<String> events = new HashSet<String>();
events.addAll(getConsumedEventsForRenderer(column.getRenderer()));

if (column.isHidable()) {
columnHider.updateColumnHidable(column);
if (column.isHidable()) {
this.columnHider.updateColumnHidable(column);
}
sinkEvents(events);
}

sinkEvents(events);
//now we do the update of the hiding toggles.
this.columnHider.hidingColumn = false;
this.columnHider.updateTogglesOrder();
refreshHeader();
this.header.updateColSpans();
this.footer.updateColSpans();
}

private void sinkEvents(Collection<String> events) {
@@ -6925,41 +7023,33 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,

selectionModel.reset();

if (changeHandler != null) {
changeHandler.remove();
changeHandler = null;
if (this.dataSource != null) {
this.dataSource.addDataChangeHandler((DataChangeHandler) null);
}

this.dataSource = dataSource;
changeHandler = dataSource
.addDataChangeHandler(new DataChangeHandler() {
dataSource.addDataChangeHandler(new DataChangeHandler() {
@Override
public void dataUpdated(int firstIndex, int numberOfItems) {
escalator.getBody().refreshRows(firstIndex,
numberOfItems);
escalator.getBody().refreshRows(firstIndex, numberOfItems);
}

@Override
public void dataRemoved(int firstIndex, int numberOfItems) {
escalator.getBody().removeRows(firstIndex,
numberOfItems);
Range removed = Range.withLength(firstIndex,
numberOfItems);
escalator.getBody().removeRows(firstIndex, numberOfItems);
Range removed = Range.withLength(firstIndex, numberOfItems);
cellFocusHandler.rowsRemovedFromBody(removed);
}

@Override
public void dataAdded(int firstIndex, int numberOfItems) {
escalator.getBody().insertRows(firstIndex,
numberOfItems);
Range added = Range.withLength(firstIndex,
numberOfItems);
escalator.getBody().insertRows(firstIndex, numberOfItems);
Range added = Range.withLength(firstIndex, numberOfItems);
cellFocusHandler.rowsAddedToBody(added);
}

@Override
public void dataAvailable(int firstIndex,
int numberOfItems) {
public void dataAvailable(int firstIndex, int numberOfItems) {
currentDataAvailable = Range.withLength(firstIndex,
numberOfItems);
fireEvent(new DataAvailableEvent(currentDataAvailable));
@@ -6971,31 +7061,27 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
int oldSize = body.getRowCount();

// Hide all details.
Set<Integer> oldDetails = new HashSet<Integer>(
visibleDetails);
Set<Integer> oldDetails = new HashSet<Integer>(visibleDetails);
for (int i : oldDetails) {
setDetailsVisible(i, false);
}

if (newSize > oldSize) {
body.insertRows(oldSize, newSize - oldSize);
cellFocusHandler.rowsAddedToBody(Range
.withLength(oldSize, newSize - oldSize));
cellFocusHandler.rowsAddedToBody(
Range.withLength(oldSize, newSize - oldSize));
} else if (newSize < oldSize) {
body.removeRows(newSize, oldSize - newSize);
cellFocusHandler.rowsRemovedFromBody(Range
.withLength(newSize, oldSize - newSize));
cellFocusHandler.rowsRemovedFromBody(
Range.withLength(newSize, oldSize - newSize));
}

if (newSize > 0) {
Range visibleRowRange = escalator
.getVisibleRowRange();
dataSource.ensureAvailability(
visibleRowRange.getStart(),
Range visibleRowRange = escalator.getVisibleRowRange();
dataSource.ensureAvailability(visibleRowRange.getStart(),
visibleRowRange.length());
} else {
// We won't expect any data more data updates, so
// just make
// We won't expect any data more data updates, so just make
// the bookkeeping happy
dataAvailable(0, 0);
}
@@ -7466,7 +7552,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
}

private boolean isElementInChildWidget(Element e) {
Widget w = WidgetUtil.findWidget(e, null);
Widget w = WidgetUtil.findWidget(e);

if (w == this) {
return false;
@@ -7853,7 +7939,7 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
cellFocusHandler.offsetRangeBy(1);
selectionColumn = new SelectionColumn(selectColumnRenderer);

addColumnSkipSelectionColumnCheck(selectionColumn, 0);
addColumnsSkipSelectionColumnCheck(Collections.singleton(selectionColumn), 0);

selectionColumn.setEnabled(isEnabled());
selectionColumn.initDone();
@@ -8439,6 +8525,19 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
return escalator.addHandler(handler, RowHeightChangedEvent.TYPE);
}

/**
* Adds a spacer visibility changed handler to the underlying escalator.
*
* @param handler
* the handler to be called when a spacer's visibility changes
* @return the registration object with which the handler can be removed
* @since 7.7.13
*/
public HandlerRegistration addSpacerVisibilityChangedHandler(
SpacerVisibilityChangedHandler handler) {
return escalator.addHandler(handler, SpacerVisibilityChangedEvent.TYPE);
}

/**
* Adds a low-level DOM event handler to this Grid. The handler is inserted
* into the given position in the list of handlers. The handlers are invoked
@@ -8830,7 +8929,6 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
for (int row : details) {
setDetailsVisible(row, false);
}

super.onDetach();
}

@@ -8948,17 +9046,17 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>,
* @param parent
* The parent to set
*/
private static final native void setParent(Widget widget, Grid<?> parent)
private static native final void setParent(Widget widget, Grid<?> parent)
/*-{
widget.@com.google.gwt.user.client.ui.Widget::setParent(Lcom/google/gwt/user/client/ui/Widget;)(parent);
}-*/;

private static final native void onAttach(Widget widget)
private static native final void onAttach(Widget widget)
/*-{
widget.@Widget::onAttach()();
}-*/;

private static final native void onDetach(Widget widget)
private static native final void onDetach(Widget widget)
/*-{
widget.@Widget::onDetach()();
}-*/;

+ 1
- 1
compatibility-client/src/main/resources/com/vaadin/v7/Vaadin7WidgetSet.gwt.xml View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.8.1//EN" "http://gwtproject.org/doctype/2.8.1/gwt-module.dtd">
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.8.2//EN" "http://www.gwtproject.org/doctype/2.8.2/gwt-module.dtd">
<module>
<!-- Hint for WidgetSetBuilder not to automatically update the file -->
<!-- WS Compiler: manually edited -->

+ 1
- 1
compatibility-server-gae/pom.xml View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-root</artifactId>
<version>8.5-SNAPSHOT</version>
<version>8.8-SNAPSHOT</version>
</parent>
<artifactId>vaadin-compatibility-server-gae</artifactId>
<name>vaadin-compatibility-server-gae</name>

+ 13
- 1
compatibility-server/pom.xml View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-root</artifactId>
<version>8.5-SNAPSHOT</version>
<version>8.8-SNAPSHOT</version>
</parent>
<artifactId>vaadin-compatibility-server</artifactId>
<name>vaadin-compatibility-server</name>
@@ -52,6 +52,18 @@
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.portlet</groupId>
<artifactId>portlet-api</artifactId>
<version>${javax.portlet.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.vaadin.external.atmosphere</groupId>
<artifactId>atmosphere-runtime</artifactId>
<version>${atmosphere.runtime.version}</version>
<scope>test</scope>
</dependency>
<!-- Bean Validation API -->
<dependency>
<groupId>javax.validation</groupId>

+ 1
- 1
compatibility-server/src/main/java/com/vaadin/v7/data/util/AbstractInMemoryContainer.java View File

@@ -441,7 +441,7 @@ public abstract class AbstractInMemoryContainer<ITEMIDTYPE, PROPERTYIDCLASS, ITE
public boolean removeContainerProperty(Object propertyId)
throws UnsupportedOperationException {
throw new UnsupportedOperationException(
"Removing container properties not supported. Override the addContainerProperty() method if required.");
"Removing container properties not supported. Override the removeContainerProperty() method if required.");
}

// ItemSetChangeNotifier

+ 2
- 1
compatibility-server/src/main/java/com/vaadin/v7/ui/AbstractField.java View File

@@ -1551,7 +1551,8 @@ public abstract class AbstractField<T> extends AbstractLegacyComponent
* A ready-made {@link ShortcutListener} that focuses the given
* {@link Focusable} (usually a {@link Field}) when the keyboard shortcut is
* invoked.
*
*
* @deprecated Replaced in 8.0 with {@link com.vaadin.event.FocusShortcut}
*/
@Deprecated
public static class FocusShortcut extends ShortcutListener {

+ 5
- 0
compatibility-server/src/test/java/com/vaadin/v7/tests/server/ClassesSerializableTest.java View File

@@ -0,0 +1,5 @@
package com.vaadin.v7.tests.server;

public class ClassesSerializableTest extends com.vaadin.tests.server.ClassesSerializableTest {

}

+ 1
- 1
compatibility-shared/pom.xml View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-root</artifactId>
<version>8.5-SNAPSHOT</version>
<version>8.8-SNAPSHOT</version>
</parent>
<artifactId>vaadin-compatibility-shared</artifactId>
<name>vaadin-compatibility-shared</name>

+ 0
- 189
compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/grid/DetailsConnectorChange.java View File

@@ -1,189 +0,0 @@
/*
* Copyright 2000-2018 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.v7.shared.ui.grid;

import java.io.Serializable;
import java.util.Comparator;

import com.vaadin.shared.Connector;

/**
* A description of an indexing modification for a connector. This is used by
* Grid for internal bookkeeping updates.
*
* @since 7.5.0
* @author Vaadin Ltd
*/
public class DetailsConnectorChange implements Serializable {

public static final Comparator<DetailsConnectorChange> REMOVED_FIRST_COMPARATOR = new Comparator<DetailsConnectorChange>() {
@Override
public int compare(DetailsConnectorChange a, DetailsConnectorChange b) {
boolean deleteA = a.getNewIndex() == null;
boolean deleteB = b.getNewIndex() == null;
if (deleteA && !deleteB) {
return -1;
} else if (!deleteA && deleteB) {
return 1;
} else {
return 0;
}
}
};

private Connector connector;
private Integer oldIndex;
private Integer newIndex;
private boolean shouldStillBeVisible;

/** Create a new connector index change. */
public DetailsConnectorChange() {
}

/**
* Convenience constructor for setting all the fields in one line.
* <p>
* Calling this constructor will also assert that the state of the pojo is
* consistent by internal assumptions.
*
* @param connector
* the changed connector
* @param oldIndex
* the old index
* @param newIndex
* the new index
* @param shouldStillBeVisible
* details should be visible regardless of {@code connector}
*/
public DetailsConnectorChange(Connector connector, Integer oldIndex,
Integer newIndex, boolean shouldStillBeVisible) {
this.connector = connector;
this.oldIndex = oldIndex;
this.newIndex = newIndex;
this.shouldStillBeVisible = shouldStillBeVisible;

assert assertStateIsOk();
}

private boolean assertStateIsOk() {
boolean connectorAndNewIndexIsNotNull = connector != null
&& newIndex != null;
boolean connectorAndNewIndexIsNullThenOldIndexIsSet = connector == null
&& newIndex == null && oldIndex != null;

assert (connectorAndNewIndexIsNotNull
|| connectorAndNewIndexIsNullThenOldIndexIsSet) : "connector: "
+ nullityString(connector) + ", oldIndex: "
+ nullityString(oldIndex) + ", newIndex: "
+ nullityString(newIndex);
return true;
}

private static String nullityString(Object object) {
return object == null ? "null" : "non-null";
}

/**
* Gets the old index for the connector.
* <p>
* If <code>null</code>, the connector is recently added. This means that
* {@link #getConnector()} is expected not to return <code>null</code>.
*
* @return the old index for the connector
*/
public Integer getOldIndex() {
assert assertStateIsOk();
return oldIndex;
}

/**
* Gets the new index for the connector.
* <p>
* If <code>null</code>, the connector should be removed. This means that
* {@link #getConnector()} is expected to return <code>null</code> as well.
*
* @return the new index for the connector
*/
public Integer getNewIndex() {
assert assertStateIsOk();
return newIndex;
}

/**
* Gets the changed connector.
*
* @return the changed connector. Might be <code>null</code>
*/
public Connector getConnector() {
assert assertStateIsOk();
return connector;
}

/**
* Sets the changed connector.
*
* @param connector
* the changed connector. May be <code>null</code>
*/
public void setConnector(Connector connector) {
this.connector = connector;
}

/**
* Sets the old index.
*
* @param oldIndex
* the old index. May be <code>null</code> if a new connector is
* being inserted
*/
public void setOldIndex(Integer oldIndex) {
this.oldIndex = oldIndex;
}

/**
* Sets the new index.
*
* @param newIndex
* the new index. May be <code>null</code> if a connector is
* being removed
*/
public void setNewIndex(Integer newIndex) {
this.newIndex = newIndex;
}

/**
* Checks whether whether the details should remain open, even if connector
* might be <code>null</code>.
*
* @return <code>true</code> if the details should remain open, even if
* connector might be <code>null</code>
*/
public boolean isShouldStillBeVisible() {
return shouldStillBeVisible;
}

/**
* Sets whether the details should remain open, even if connector might be
* <code>null</code>.
*
* @param shouldStillBeVisible
* <code>true</code> if the details should remain open, even if
* connector might be <code>null</code>
*/
public void setShouldStillBeVisible(boolean shouldStillBeVisible) {
this.shouldStillBeVisible = shouldStillBeVisible;
}
}

+ 1
- 1
compatibility-themes/pom.xml View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-root</artifactId>
<version>8.5-SNAPSHOT</version>
<version>8.8-SNAPSHOT</version>
</parent>
<artifactId>vaadin-compatibility-themes</artifactId>
<name>vaadin-compatibility-themes</name>

+ 15
- 23
compatibility-themes/src/main/java/com/vaadin/osgi/compatibility/themes/LegacyThemeContributions.java View File

@@ -15,35 +15,27 @@
*/
package com.vaadin.osgi.compatibility.themes;

import org.osgi.service.component.annotations.Activate;
import java.util.ArrayList;
import java.util.List;

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.http.HttpService;

import com.vaadin.osgi.resources.OsgiVaadinResources;
import com.vaadin.osgi.resources.VaadinResourceService;
import com.vaadin.osgi.resources.OsgiVaadinContributor;
import com.vaadin.osgi.resources.OsgiVaadinResource;
import com.vaadin.osgi.resources.OsgiVaadinTheme;

@Component(immediate = true)
public class LegacyThemeContributions {
@Component
public class LegacyThemeContributions implements OsgiVaadinContributor {
private static final String[] LEGACY_THEMES = { "base", "chameleon",
"reindeer", "runo" };

private HttpService httpService;

@Activate
void startup() throws Exception {
VaadinResourceService service = OsgiVaadinResources.getService();
for (String themeName : LEGACY_THEMES) {
service.publishTheme(themeName, httpService);
@Override
public List<OsgiVaadinResource> getContributions() {
final List<OsgiVaadinResource> contributions = new ArrayList<>(
LEGACY_THEMES.length);
for (final String theme : LEGACY_THEMES) {
contributions.add(OsgiVaadinTheme.create(theme));
}
}

@Reference
void setHttpService(HttpService httpService) {
this.httpService = httpService;
}

void unsetHttpService(HttpService httpService) {
this.httpService = null;
return contributions;
}
}

+ 5
- 6
documentation/addons/addons-cval.asciidoc View File

@@ -20,14 +20,13 @@ need to register in the website to obtain a key.

You can get license keys from link:https://vaadin.com/pro/licenses[vaadin.com/pro/licenses].

. Select in the Vaadin website "My Account > Licenses" or directly
[menuchoice]#Licenses# if you are a Pro Tools subscriber.
. On the Vaadin website, click on your profile in the top right, then select "My Services > Licenses".
+
image::img/cval-pro-licenses-3.png[width=80%, scaledwidth=100%]
image::img/cval-pro-licenses-4.png[width=80%, scaledwidth=100%]

. Click on a license key to obtain the purchased or trial key.
+
image::img/cval-pro-licenses-code.png[width=80%, scaledwidth=100%]
image::img/cval-pro-licenses-code-2.png[width=80%, scaledwidth=100%]


[[addons.cval.installing]]
@@ -62,7 +61,7 @@ usually with a [literal]#++-D++# option. For example, on the command-line:
[prompt]#$# [command]#java# -Dvaadin.[replaceable]##<product>##.developer.license=[replaceable]#L1cen5e-c0de# ...
----

where the [literal]`<product>` is the product ID, such as `charts`, `spreadsheet`, `designer`, or `testbench`.
where the [literal]`<product>` is the product ID, such as `charts`, `spreadsheet`, or `testbench`.

[[addons.cval.systemproperty.environments]]
=== Passing License Key in Different Environments
@@ -105,7 +104,7 @@ Apache Maven:: If building the project with Apache Maven, you can pass the licen
[prompt]#$# [command]#mvn# -Dvaadin.[replaceable]##&lt;product&gt;##.developer.license=[replaceable]##L1cen5e-c0de## package
----
+
where the [literal]`<product>` is the product ID, such as `charts`, `spreadsheet`, `designer`, or `testbench`.
where the [literal]`<product>` is the product ID, such as `charts`, `spreadsheet`, or `testbench`.

Continuous Integration Systems:: In CIS systems, you can pass the license key to build runners as a system
property in the build configuration. However, this only passes it to a runner.

+ 5
- 5
documentation/addons/addons-maven.asciidoc View File

@@ -78,14 +78,14 @@ image::img/directory-activate.png[width=50%, scaledwidth=70%]
+
For official Vaadin add-ons, see <<addons-cval#addons.cval, "Installing Commercial Vaadin Add-on License">> for more information.

. _In Vaadin 7.6 and older_: You need to compile the widget set as described in <<addons.maven.compiling>>.
. _In Vaadin 7.6 and older_: You need to configure the widget set as described in <<addons.maven.compiling>>.

[[addons.maven.compiling]]
== Compiling the Application Widget Set
== Configuring the Application Widget Set

[NOTE]
====
The widget set is automatically compiled in Vaadin 7.7 and later.
The widget set is automatically configured in Vaadin 7.7 and later.
The plugin will attempt to detect any add-ons that need the widget set to be compiled.

Just note that it can take a bit time to compile.
@@ -94,10 +94,10 @@ To speed up, instead of compiling it locally, you can also use a public cloud se
See <<addons.maven.modes>> for instructions.
====

In projects that use Vaadin 7.6 or older, you need to manually compile the widget set as follows.
In projects that use Vaadin 7.6 or older, you need to manually configure the widget set as follows.

[[addons.maven.widgetset]]
=== Enabling Widget Set Compilation
=== Configuring Widget Set Compilation

Compiling the widget set in Maven projects requires the Vaadin Maven plugin.
It is included in Maven projects created with a current Vaadin archetype.

BIN
documentation/addons/img/cval-pro-licenses-3.png View File


BIN
documentation/addons/img/cval-pro-licenses-4.png View File


BIN
documentation/addons/img/cval-pro-licenses-code-2.png View File


BIN
documentation/addons/img/cval-pro-licenses-code.png View File


+ 2
- 2
documentation/advanced/advanced-dragndrop.asciidoc View File

@@ -183,7 +183,7 @@ compatible browser, such as Mozilla Firefox 3.6 or newer.
== Mobile Drag And Drop Support

The HTML 5 Drag and Drop API is not yet supported by mobile browsers. To enable HTML5 DnD support on mobile devices, we have included
an link:https://github.com/timruffles/ios-html5-drag-drop-shim/tree/rewrite:[external Polyfill]. Please note that this Polyfill is under the BSD 2 License.
an link:https://github.com/timruffles/mobile-drag-drop[external Polyfill]. Please note that this Polyfill is under the BSD 2 License.

By default, the mobile DnD support is disabled, but you can enable it any time for a [classname]#UI#. Starting from the request where the support was enabled, all the added [classname]#DragSourceExtension#, [classname]#DropTargetExtension# and their subclasses will also work on mobile devices for that UI. The Polyfill is only loaded when the user is using a touch device.

@@ -420,7 +420,7 @@ When dropping on top of the grid's header or footer, the drop location will be `
A drop target Grid's body has the style name `v-grid-body-droptarget` to indicate that it is a potential target for data to be dropped.

When dragging data over a drop target Grid's row, depending on the drop mode and the mouse position relative to the row, a style name is applied to the row or to the grid body to indicate the drop location.
When dragging on top of a row, `v-grid-row-drag-center` indicates ON_TOP, `v-grid-row-drag-top` indicates ABOVE and `v-grid-row-drag-bottom` indicates BELOW locations. When dragging on top of an empty grid, or when the drop location is ON_TOP and dragged below the last row in grid (and there is empty space visible), the `v-grid-body-body-drag-top` style is applied to the `v-grid-tablewrapper` element which surrounds the grid header, body and footer.
When dragging on top of a row, `v-grid-row-drag-center` indicates ON_TOP, `v-grid-row-drag-top` indicates ABOVE and `v-grid-row-drag-bottom` indicates BELOW locations. When dragging on top of an empty grid, or when the drop location is ON_TOP and dragged below the last row in grid (and there is empty space visible), the `v-grid-body-drag-top` style is applied to the `v-grid-tablewrapper` element which surrounds the grid header, body and footer.

(((range="endofrange", startref="term.advanced.dragndrop")))


+ 5
- 0
documentation/advanced/advanced-osgi.asciidoc View File

@@ -21,11 +21,13 @@ Vaadin application for OSGi should be a valid bundle, i.e. it should be packaged
The easiest way to convert regular maven-based Vaadin application into a valid OSGi bundle consists of five steps:

* Change packaging type to `jar` in your `pom.xml`:

[source, xml]
----
<packaging>jar</packaging>
----
* Change the scope for all vaadin dependencies from default to `provided`, like this:

[source, xml]
----
<dependency>
@@ -35,6 +37,7 @@ The easiest way to convert regular maven-based Vaadin application into a valid O
</dependency>
----
* Add OSGi-related dependencies to the project

[source, xml]
----
<groupId>com.vaadin</groupId>
@@ -62,6 +65,7 @@ The easiest way to convert regular maven-based Vaadin application into a valid O
</dependency>
----
* Setup necessary plugins for building the project:

[source, xml]
----
<build>
@@ -93,6 +97,7 @@ The easiest way to convert regular maven-based Vaadin application into a valid O
</build>
----
* Add bundle script (`bnd.bnd`) into the project root folder:

[source, text]
----
Bundle-Name: ${project.name}

+ 6
- 7
documentation/advanced/advanced-shortcuts.asciidoc View File

@@ -50,11 +50,10 @@ image::img/shortcut-defaultbutton.png[]
[[advanced.shortcuts.focus]]
== Field Focus Shortcuts

You can define a shortcut key that sets the focus to a field component (any
component that inherits [classname]#AbstractField#) by adding a
[classname]#FocusShortcut# as a shortcut listener to the field.
You can define a shortcut key that sets the focus to any focusable component (implements [interface]#Focusable#), usually field components, by adding a
[interface]#FocusShortcut# as a shortcut listener to the component.

The constructor of the [classname]#FocusShortcut# takes the field component as
The constructor of the [classname]#FocusShortcut# takes the focusable component as
its first parameter, followed by the key code, and an optional list of modifier
keys, as listed in <<advanced.shortcuts.keycodes>>.

@@ -64,7 +63,7 @@ keys, as listed in <<advanced.shortcuts.keycodes>>.
// A field with Alt+N bound to it
TextField name = new TextField("Name (Alt+N)");
name.addShortcutListener(
new AbstractField.FocusShortcut(name, KeyCode.N,
new FocusShortcut(name, KeyCode.N,
ModifierKey.ALT));
layout.addComponent(name);
----
@@ -78,7 +77,7 @@ key is indicated with an ampersand ( [literal]#++&++#).
// A field with Alt+A bound to it, using shorthand notation
TextField address = new TextField("Address (Alt+A)");
address.addShortcutListener(
new AbstractField.FocusShortcut(address, "&Address"));
new FocusShortcut(address, "&Address"));
----

This is especially useful for internationalization, so that you can determine
@@ -269,7 +268,7 @@ following defines a kbd:[Ctrl+Shift+N] key combination for a shortcut.
----
TextField name = new TextField("Name (Ctrl+Shift+N)");
name.addShortcutListener(
new AbstractField.FocusShortcut(name, KeyCode.N,
new FocusShortcut(name, KeyCode.N,
ModifierKey.CTRL,
ModifierKey.SHIFT));
----

+ 26
- 2
documentation/articles/LettingTheUserDownloadAFile.asciidoc View File

@@ -62,8 +62,7 @@ along with the file to ensure the browser doesn't try to open the file
even if it's is a file type that the browser knows how to deal with.

[[lazily-determine-the-content-and-the-name-of-the-file-being-server]]
Lazily determine the content and the name of the file being server
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
==== Lazily determine the content and the name of the file being server

One can lazily determine the content of the file using a
`StreamResource`. Yet the name of the file that is going to be
@@ -110,3 +109,28 @@ public class OnDemandFileDownloader extends FileDownloader {
}
}
....

[[lazily-determine-the-content-and-the-name-of-the-file-being-server]]
==== Cancelled downloads

Since downloadable files may be quite big, and the download process may take time, the user might decide to
cancel the download process. In this case `IOException` may be thrown by the web server. That
does not mean something went wrong with the application, but the user pressed `Cancel` button during download. To prevent the exception to be logged, you can catch and ignore it as here:

```java
public class IgnoreCancelDownloader extends FileDownloader {

...

@Override
public boolean handleConnectorRequest(final VaadinRequest request, final VaadinResponse response, final String path) {
try {
return super.handleConnectorRequest(request, response, path);
} catch (final IOException ignored) {
return true;
}
}
}

```
Note that the exception is a sublclass of `IOException`, but the particular class depends on the web container.

+ 1
- 1
documentation/articles/SendingEmailFromJavaApplications.asciidoc View File

@@ -134,7 +134,7 @@ follows:
HtmlEmail email = new HtmlEmail();
email.setHostName("localhost");
email.setSmtpPort(9090);
email.setAuthentication()"sender@test.com", "password");
email.setAuthentication("sender@test.com", "password");
....
 
Or if you want to use Gmail:

+ 2
- 2
documentation/articles/UsingRPCFromJavaScript.asciidoc View File

@@ -8,8 +8,8 @@ layout: page
= Using RPC from JavaScript

This tutorial continues where
link:IntegratingAJavaScriptComponent.asciidoc[Integrating a JavaScript
component] ended. We will now add RPC functionality to the JavaScript
<<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.


+ 1
- 1
documentation/articles/VaadinSpringTips.asciidoc View File

@@ -22,4 +22,4 @@ example which can be configured:
* `vaadin.servlet.closeIdleSessions=true`

For full list of available properties, see
https://github.com/vaadin/spring/blob/master/vaadin-spring-boot/src/main/java/com/vaadin/spring/boot/internal/VaadinServletConfigurationProperties.java[VaadinServletConfigurationProperties].
https://github.com/vaadin/spring/blob/3.0/vaadin-spring-boot/src/main/java/com/vaadin/spring/boot/internal/VaadinServletConfigurationProperties.java[VaadinServletConfigurationProperties].

+ 2
- 2
documentation/clientside/clientside-module.asciidoc View File

@@ -20,8 +20,8 @@ widget set, you should normally inherit the [classname]#DefaultWidgetSet#.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC
"-//Google Inc.//DTD Google Web Toolkit 2.8.1//EN"
"http://gwtproject.org/doctype/2.8.1/gwt-module.dtd">
"-//Google Inc.//DTD Google Web Toolkit 2.8.2//EN"
"http://www.gwtproject.org/doctype/2.8.2/gwt-module.dtd">

<module>
<!-- Inherit the default widget set -->

+ 2
- 2
documentation/clientsideapp/clientsideapp-entrypoint.asciidoc View File

@@ -12,7 +12,7 @@ starts, much like the [methodname]#init()# method in server-side Vaadin UIs.

Consider the following application:

[source, java]
----
package com.example.myapp.client;

@@ -51,7 +51,7 @@ configuration, in a client-side module descriptor, described in
Module Descriptor">>. The descriptor is an XML file with suffix
[filename]#.gwt.xml#.

[source, xml]
----
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC

+ 1
- 1
documentation/clientsideapp/clientsideapp-loading.asciidoc View File

@@ -11,7 +11,7 @@ You can load the JavaScript code of a client-side application in an HTML __host
page__ by including it with a [literal]#++<script>++# tag, for example as
follows:

[source, html]
----
<html xmlns="http://www.w3.org/1999/xhtml">
<head>

+ 1
- 1
documentation/clientsideapp/clientsideapp-overview.asciidoc View File

@@ -30,7 +30,7 @@ the JavaScript of the compiled module is loaded in the browser.

Consider the following client-side application:

[source, java]
----
public class HelloWorld implements EntryPoint {
@Override

+ 3
- 3
documentation/clientsidewidgets/clientsidewidgets-grid.asciidoc View File

@@ -29,7 +29,7 @@ modify the element as needed.

For example, [classname]#TextRenderer# is implemented simply as follows:

[source, java]
----
public class TextRenderer implements Renderer<String> {
@Override
@@ -44,7 +44,7 @@ The server-side renderer API should extend [classname]#AbstractRenderer# or
[classname]#ClickableRenderer# with the data type accepted by the renderer. The
data type also must be given for the superclass constructor.

[source, java]
----
public class TextRenderer extends AbstractRenderer<String> {
public TextRenderer() {
@@ -56,7 +56,7 @@ public class TextRenderer extends AbstractRenderer<String> {
The client-side and server-side renderer need to be connected with a connector
extending from [classname]#AbstractRendererConnector#.

[source, java]
----
@Connect(com.vaadin.ui.renderer.TextRenderer.class)
public class TextRendererConnector

+ 1
- 1
documentation/clientsidewidgets/clientsidewidgets-vaadin.asciidoc View File

@@ -13,7 +13,7 @@ widgets have somewhat different feature set from the GWT widgets and are
foremost intended for integration with the server-side components, but some may
prove useful for client-side applications as well.

[source, java]
----
public class MyEntryPoint implements EntryPoint {
@Override

+ 1
- 2
documentation/components/components-checkbox.asciidoc View File

@@ -55,5 +55,4 @@ image::img/checkbox-example1.png[width=35%, scaledwidth=50%]

The top-level element of a [classname]#CheckBox# has the
[literal]#++v-checkbox++# style. It contains two sub-elements: the actual check
box [literal]#++input++# element and the [literal]#++label++# element. If you
want to have the label on the left, you can change the positions with "[literal]#++direction: rtl++#" for the top element.
box [literal]#++input++# element and the [literal]#++label++# element.

+ 11
- 10
documentation/components/components-grid.asciidoc View File

@@ -533,18 +533,19 @@ Formats a column with the [classname]#LocalDate# type.
The renderer can be constructed with a [classname]#DateTimeFormatter#, or with a custom pattern string.
The locale is either given explicitly with the pattern, resolved from the given [classname]#DateTimeFormatter# or from the grid the renderer is attached to, if neither of the previous are given.
For the pattern string syntax, refer to the following documentation: link:https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#patterns[docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#patterns].

Note we should use `SerializableProvider&lt;DateTimeFormatter&gt;` or lambda in the first case, because
`DateTimeFormatter` is not serializable, and that may lead to problems in certain cases, for instance in a cluster environment.
+
[source, java]
----
DateTimeFormatter formatter = DateTimeFormatter
LocalDateRenderer renderer = new LocalDateRenderer(() -> DateTimeFormatter
.ofLocalizedDate(FormatStyle.LONG)
.withLocale(Locale.ENGLISH);
.withLocale(Locale.ENGLISH));

Column<Person, LocalDate> bornColumn =
grid.addColumn(
Person::getBirthDate,
new LocalDateRenderer(formatter));
renderer);

// Alternatively, with a custom pattern:
Column<Person, LocalDate> bornColumn =
@@ -559,14 +560,14 @@ Otherwise the same as [classname]#LocalDateRenderer#, except for the [classname]
+
[source, java]
----
DateTimeFormatter formatter = DateTimeFormatter
.ofLocalizedDate(FormatStyle.LONG, FormatStyle.SHORT)
.withLocale(Locale.ENGLISH);
LocalDateTimeRenderer renderer = new LocalDateTimeRenderer(
() -> DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.LONG, FormatStyle.SHORT)
.withLocale(Locale.ENGLISH));

Column<Person, LocalDateTime> bornColumn =
grid.addColumn(
Person::getBirthDateAndTime,
new LocalDateTimeRenderer(formatter));
grid.addColumn(Person::getBirthDateAndTime, renderer);


// Alternatively, with a custom pattern:
Column<Person, LocalDateTime> bornColumn =

+ 1
- 1
documentation/components/components-treegrid.asciidoc View File

@@ -56,7 +56,7 @@ an [classname]#TreeDataProvider# with [classname]#TreeData# is used. If at any t
----
TreeDataProvider<Project> dataProvider = (TreeDataProvider<Project>) treeGrid.getDataProvider();

TreeData<Project> data = dataProvider.getData();
TreeData<Project> data = dataProvider.getTreeData();
// add new items
data.addItem(null, newProject);
data.addItems(newProject, newProject.getChildren());

+ 5
- 0
documentation/components/components-twincolselect.asciidoc View File

@@ -59,6 +59,11 @@ The [methodname]#setRows()# method sets the height of the component by the
number of visible items in the selection boxes. Setting the height with
[methodname]#setHeight()# to a defined value overrides the rows setting.

[WARNING]
The [classname]#TwinColSelect# does not provide lazy loading mechanism.
Hence it will slow down significantly if used with large itemsets.
The lazy loading feature could be implemented using two single column Grids instead.

Common selection component features are described in
<<dummy/../../../framework/components/components-selection#components.selection,"Selection
Components">>.

+ 1
- 1
documentation/gwt/gwt-connector.asciidoc View File

@@ -23,7 +23,7 @@ The basic tasks of a connector is to hook up to the widget and handle events
from user interaction and changes received from the server. A connector also has
a number of routine infrastructure methods which need to be implemented.

[source,java]
----
@Connect(MyComponent.class)
public class MyComponentConnector

+ 3
- 3
documentation/gwt/gwt-extension.asciidoc View File

@@ -34,7 +34,7 @@ extended component or UI as a parameter and passes it to __super.extend()__.
For example, let us have a trivial example with an extension that takes no
special parameters, and illustrates the three alternative APIs:

[source,java]
----
public class CapsLockWarning extends AbstractExtension {
// You could pass it in the constructor
@@ -56,7 +56,7 @@ public class CapsLockWarning extends AbstractExtension {

The extension could then be added to a component as follows:

[source,java]
----
PasswordField password = new PasswordField("Give it");

@@ -96,7 +96,7 @@ In the following example, we implement a "Caps Lock warning" extension. It
listens for changes in Caps Lock state and displays a floating warning element
over the extended component if the Caps Lock is on.

[source,java]
----
@Connect(CapsLockWarning.class)
public class CapsLockWarningConnector

+ 3
- 3
documentation/gwt/gwt-rpc.asciidoc View File

@@ -28,7 +28,7 @@ interface simply defines any methods that can be called through the interface.

For example:

[source,java]
----
public interface MyComponentServerRpc extends ServerRpc {
public void clicked(String buttonName);
@@ -54,7 +54,7 @@ Before making a call, you need to instantiate the server RPC object with
[methodname]#RpcProxy.create()#. This is usually done transparently by using [methodname]#getRpcProxy()#. After that, you can make calls through the
server RPC interface that you defined, for example as follows:

[source,java]
----
@Connect(MyComponent.class)
public class MyComponentConnector
@@ -87,7 +87,7 @@ RPC calls are handled in a server-side implementation of the server RPC
interface. The call and its parameters are serialized and passed to the server
in an RPC request transparently.

[source,java]
----
public class MyComponent extends AbstractComponent {
private MyComponentServerRpc rpc =

+ 1
- 1
documentation/gwt/gwt-server-side.asciidoc View File

@@ -19,7 +19,7 @@ The component state is usually managed by a __shared state__, described later in
<<dummy/../../../framework/gwt/gwt-shared-state#gwt.shared-state,"Shared
State">>.

[source, java]
----
public class MyComponent extends AbstractComponent {
public MyComponent() {

+ 14
- 14
documentation/gwt/gwt-shared-state.asciidoc View File

@@ -16,7 +16,7 @@ A shared state object simply needs to extend the
[classname]#AbstractComponentState#. The member variables should normally be
declared as public.

[source, java]
----
public class MyComponentState extends AbstractComponentState {
public String text;
@@ -42,7 +42,7 @@ and other classes needed by shared-state or RPC communication.
For example, you could have the following definitions in the
[filename]#.gwt.xml# descriptor:

[source, xml]
----
<source path="client" />
<source path="shared" />
@@ -59,7 +59,7 @@ A server-side component can access the shared state with the
implementation with one that returns the shared state object cast to the proper
type, as follows:

[source, java]
----
@Override
public MyComponentState getState() {
@@ -70,7 +70,7 @@ public MyComponentState getState() {
You can then use the [methodname]#getState()# to access the shared state object
with the proper type.

[source, java]
----
public MyComponent() {
getState().setText("This is the initial state");
@@ -86,7 +86,7 @@ A connector can access a shared state with the [methodname]#getState()# method.
The access should be read-only. It is required that you override the base
implementation with one that returns the proper shared state type, as follows:

[source, java]
----
@Override
public MyComponentState getState() {
@@ -99,7 +99,7 @@ client-side. When a state change occurs, the [methodname]#onStateChanged()#
method in the connector is called. You should always call the superclass
method before anything else to handle changes to common component properties.

[source, java]
----
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
@@ -141,7 +141,7 @@ separately in arbitrary order.
We can replace the [methodname]#onStateChange()# method in the earlier connector
example with the following:

[source, java]
----
@OnStateChange("text")
void updateText() {
@@ -164,7 +164,7 @@ defines automatic delegation of the property value to the corresponding widget
property of the same name and type, by calling the respective setter for the
property in the widget.

[source, java]
----
public class MyComponentState extends AbstractComponentState {
@DelegateToWidget
@@ -178,7 +178,7 @@ example in <<gwt.shared-state.onstatechange>>.
If you want to delegate a shared state property to a widget property of another
name, you can give the property name as a string parameter for the annotation.

[source, java]
----
public class MyComponentState extends AbstractComponentState {
@DelegateToWidget("description")
@@ -196,7 +196,7 @@ only refer to a server-side component, while on the client-side you only have
widgets. References to components can be made by referring to their connectors
(all server-side components implement the [interfacename]#Connector# interface).

[source, java]
----
public class MyComponentState extends AbstractComponentState {
public Connector otherComponent;
@@ -205,7 +205,7 @@ public class MyComponentState extends AbstractComponentState {

You could then access the component on the server-side as follows:

[source, java]
----
public class MyComponent {
public void MyComponent(Component otherComponent) {
@@ -241,7 +241,7 @@ serialized to the client-side separately.

Let us begin with the server-side API:

[source, java]
----
public class MyComponent extends AbstractComponent {
...
@@ -259,7 +259,7 @@ public class MyComponent extends AbstractComponent {
On the client-side, you can then get the URL of the resource with
[methodname]#getResourceUrl()#.

[source, java]
----
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
@@ -273,7 +273,7 @@ public void onStateChanged(StateChangeEvent stateChangeEvent) {

The widget could then use the URL, for example, as follows:

[source, java]
----
public class MyWidget extends Label {
...

+ 1
- 1
documentation/gwt/gwt-styling.asciidoc View File

@@ -22,7 +22,7 @@ sub-elements as it desires.
For example, you could style a composite widget with an overall style and with
separate styles for the sub-widgets as follows:

[source, java]
----
public class MyPickerWidget extends ComplexPanel {
public static final String CLASSNAME = "mypicker";

+ 9
- 9
documentation/portal/portal-osgi.asciidoc View File

@@ -77,20 +77,20 @@ link:https://github.com/elmot/liferay-7-solid-portlet-example/[]
== Deployment a Portlet With OSGi (Maven)
An OSGi portlet should be packaged as a JAR with a proper OSGi bundle
manifest, and deployed to a portal that has its required bundles installed.
The maven archetype `com.vaadin:vaadin-archetype-liferay-portlet:8.1.0` is a good starting point to build an OSGi portlet application.
The maven archetype `com.vaadin:vaadin-archetype-liferay-portlet` is a good starting point to build an OSGi portlet application.
The required bundles (and the application as well) can be installed using link:https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/blade-cli[blade client].
The latest client binary can be downloaded from the link: link:https://releases.liferay.com/tools/blade-cli/latest/blade.jar[]

Here is an example script for doing that:
Here is an example script for doing that (be sure to check the versions required by your project using *mvn dependency:list* ):
[source, shell]
----
java -jar blade.jar sh start https://repo1.maven.org/maven2/org/jsoup/jsoup/1.11.0/jsoup-1.11.0.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/org/jsoup/jsoup/1.11.2/jsoup-1.11.2.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/com/vaadin/external/gentyref/1.2.0.vaadin1/gentyref-1.2.0.vaadin1.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/com/vaadin/vaadin-shared/8.3.2/vaadin-shared-8.3.2.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/com/vaadin/vaadin-server/8.3.2/vaadin-server-8.3.2.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/com/vaadin/vaadin-osgi-integration/8.3.2/vaadin-osgi-integration-8.3.2.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/com/vaadin/vaadin-client-compiled/8.3.2/vaadin-client-compiled-8.3.2.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/com/vaadin/vaadin-themes/8.3.2/vaadin-themes-8.3.2.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/com/vaadin/vaadin-liferay-integration/8.3.2/vaadin-liferay-integration-8.3.2.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/com/vaadin/vaadin-shared/8.6.3/vaadin-shared-8.6.3.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/com/vaadin/vaadin-server/8.6.3/vaadin-server-8.6.3.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/com/vaadin/vaadin-osgi-integration/8.6.3/vaadin-osgi-integration-8.6.3.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/com/vaadin/vaadin-client-compiled/8.6.3/vaadin-client-compiled-8.6.3.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/com/vaadin/vaadin-themes/8.6.3/vaadin-themes-8.6.3.jar
java -jar blade.jar sh start https://repo1.maven.org/maven2/com/vaadin/vaadin-liferay-integration/8.6.3/vaadin-liferay-integration-8.6.3.jar
java -jar blade.jar sh start file:<path_to_liferay_portlet.jar>
----

+ 2
- 1
documentation/portal/portal-ui.asciidoc View File

@@ -10,7 +10,7 @@ layout: page
A portlet UI is just like in a regular Vaadin application, a class that extends
[classname]#com.vaadin.ui.UI#.

[source, java]
----
@Theme("myportlet")
public class MyportletUI extends UI {
@@ -72,6 +72,7 @@ the Project">>.

Otherwise, the following snippet can be used.

[source, java]
----
@WebServlet(value = "/*", asyncSupported = true)
@VaadinServletConfiguration(productionMode = false,

+ 1
- 1
documentation/tutorial.adoc View File

@@ -900,7 +900,7 @@ delete.addClickListener(e -> this.delete());
----

TIP: For a truly re-usable form component in a real life project, you'd want to
introduce an interface to replace the myUI field or, event better, use an event
introduce an interface to replace the myUI field or, even better, use an event
system like https://vaadin.com/wiki/-/wiki/main/Events+and+contexts[CDI events]
to completely decouple the components. We'll leave that out of this tutorial for
simplicity.

+ 1
- 1
liferay-integration/pom.xml View File

@@ -9,7 +9,7 @@
<parent>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-root</artifactId>
<version>8.5-SNAPSHOT</version>
<version>8.8-SNAPSHOT</version>
</parent>

<properties>

+ 1
- 1
liferay/pom.xml View File

@@ -5,7 +5,7 @@
<parent>
<groupId>com.vaadin</groupId>
<artifactId>vaadin-root</artifactId>
<version>8.5-SNAPSHOT</version>
<version>8.8-SNAPSHOT</version>
</parent>
<artifactId>vaadin-liferay</artifactId>
<name>vaadin-liferay</name>

+ 0
- 0
osgi-integration/pom.xml View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save