From 66c3c1216e5eae9f6bff9e4048df78061f51a1d5 Mon Sep 17 00:00:00 2001 From: miki Date: Mon, 4 May 2020 23:11:33 +0300 Subject: [PATCH 01/66] #100 development branch with snapshot version set up --- demo-v14/pom.xml | 6 +++--- pom.xml | 2 +- superfields/pom.xml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/demo-v14/pom.xml b/demo-v14/pom.xml index e0d44b68..6a6a562e 100644 --- a/demo-v14/pom.xml +++ b/demo-v14/pom.xml @@ -4,11 +4,11 @@ superfields-parent org.vaadin.miki - 0.6.0 + 0.6.66-SNAPSHOT superfields-demo-v14 - 0.6.0 + 0.6.66-SNAPSHOT V14 demo app for SuperFields Showcase application for V14 and SuperFields. war @@ -23,7 +23,7 @@ org.vaadin.miki superfields - 0.6.0 + 0.6.66-SNAPSHOT javax.servlet diff --git a/pom.xml b/pom.xml index 914f8f10..448112a9 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.vaadin.miki superfields-parent - 0.6.0 + 0.6.66-SNAPSHOT superfields demo-v14 diff --git a/superfields/pom.xml b/superfields/pom.xml index 620fea3c..1d6dd8ea 100644 --- a/superfields/pom.xml +++ b/superfields/pom.xml @@ -8,7 +8,7 @@ superfields SuperFields Code for various V14+ fields and other components. - 0.6.0 + 0.6.66-SNAPSHOT 10 From d50a6070b343633548e667bf0203f356f658fa42 Mon Sep 17 00:00:00 2001 From: Miki Date: Thu, 7 May 2020 12:41:30 +0300 Subject: [PATCH 02/66] #100 ready (#101) there is an automated workflow that sets a version number one a branch `release-X.Y.Z` is made --- .github/workflows/maven.yml | 9 +++++---- .github/workflows/mavenpublish.yml | 3 ++- .github/workflows/setversion.yml | 29 +++++++++++++++++++++++++++++ README.md | 9 ++++++--- 4 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/setversion.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 08afac21..e0a87645 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -1,18 +1,19 @@ # This workflow will build a Java project with Maven # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven -name: Java CI with Maven +name: Build (Java 10) on: push: - branches: [ master ] + branches: [ master, development ] pull_request: - branches: [ master ] + branches: [ master, development ] jobs: - build: + package: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/mavenpublish.yml b/.github/workflows/mavenpublish.yml index 2aadfd45..0f4b2017 100644 --- a/.github/workflows/mavenpublish.yml +++ b/.github/workflows/mavenpublish.yml @@ -8,9 +8,10 @@ on: types: [created] jobs: - build: + publish: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/setversion.yml b/.github/workflows/setversion.yml new file mode 100644 index 00000000..4a416949 --- /dev/null +++ b/.github/workflows/setversion.yml @@ -0,0 +1,29 @@ +name: Set Version + +on: create + +jobs: + set_version: + if: ${{ (github.event.ref_type == 'branch') && startsWith(github.event.ref, 'release-') }} + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 10 + uses: actions/setup-java@v1 + with: + java-version: 10 + server-id: github # Value of the distributionManagement/repository/id field of the pom.xml + settings-path: ${{ github.workspace }} # location for the settings.xml file + - name: Set version + run: | + export VERSION="`echo ${{ github.event.ref }} | sed -e s/release-//g`" + mvn versions:set -DnewVersion=$VERSION --file pom.xml + mvn versions:set -DnewVersion=$VERSION --file superfields/pom.xml + sed -i -e s/{VERSION}/$VERSION/g ./README.md + - name: Push changes + uses: stefanzweifel/git-auto-commit-action@v4.1.6 + with: + commit_message: "(bot) setting version for branch ${{ github.event.ref }}" + branch: ${{ github.event.ref }} diff --git a/README.md b/README.md index b0b97532..fbb87b4d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Welcome to SuperFields! ## Overview + This is a collection of hopefully useful Vaadin 14 components, grouped into several sub-projects: * `superfields` are various input components; * `demo-v14` contains an app for Vaadin 14 that shows all components - [see the demo online](https://superfields.herokuapp.com/) on Heroku @@ -18,7 +19,7 @@ This is the relevant dependency: org.vaadin.miki superfields - 0.6.0 + {VERSION} ``` @@ -38,11 +39,13 @@ All releases are available: ### Java 8 -Some versions compatible with Java 8 may be released only to the Vaadin Directory. The repository has a branch `java-8`. The most recent version that supports Java 8 is `0.6.0.java8`. +Some versions compatible with Java 8 are available in the Vaadin Directory. They are marked with `.java8` suffix in the version, e.g. `0.6.0.java8`. Their functionality is identical to the official release. + +This repository has a branch `java-8` which contains the most recent release compatible with Java 8. ## Contribution guidelines -You are more than welcome to contribute. Feel free to make PRs, submit issues, etc. +You are more than welcome to contribute. Feel free to make PRs, submit issues, ideas etc. ## Small print From 85009d59cb02ea65e345bd7497b58f3498c1cf57 Mon Sep 17 00:00:00 2001 From: Miki Date: Thu, 7 May 2020 16:44:01 +0300 Subject: [PATCH 03/66] #105 fixed --- .../superfields/dates/DatePatternHelper.java | 49 +++++++++++++++---- .../superfields/dates/SuperDatePicker.java | 17 ++++--- .../dates/SuperDateTimePicker.java | 17 ++++--- 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternHelper.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternHelper.java index 82431830..556cd364 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternHelper.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternHelper.java @@ -1,5 +1,6 @@ package org.vaadin.miki.superfields.dates; +import com.vaadin.flow.component.AttachEvent; import com.vaadin.flow.component.Component; /** @@ -9,7 +10,7 @@ * @author miki * @since 2020-05-02 */ -final class DatePatternHelper { +final class DatePatternHelper { /** * Returns the pattern descriptor string expected by the client-side code. @@ -52,20 +53,48 @@ private static String convertDatePatternToClientPattern(DatePattern pattern) { } } + private final C source; + /** - * Does magic and sets the display pattern on the client side. - * Requires the client-side connector to have a {@code setDisplayPattern} method. - * @param source Source component. - * @param pattern Pattern to set. + * Creates a helper for a given source object. + * The client-side representation should have mixed in methods from {@code date-pattern-mixin.js}. + * @param source Source to use. + */ + DatePatternHelper(C source) { + this.source = source; + this.source.addAttachListener(this::onAttached); + } + + /** + * Class client-side method {@code initPatternSetting()} that, well, inits pattern setting. + * In general, client-side code overrides a few methods to make sure pattern displaying and parsing works properly with custom patterns. */ - static void setClientSidePattern(Component source, DatePattern pattern) { - source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(source, context -> - source.getElement().callJsFunction("setDisplayPattern", source.getElement(), convertDatePatternToClientPattern(pattern)) + protected void initPatternSetting() { + this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> + this.source.getElement().callJsFunction("initPatternSetting", this.source) )); } - private DatePatternHelper() { - // instances not allowed + /** + * Callback when onAttach() is called. + * @param event An {@link AttachEvent}. + */ + protected void onAttached(AttachEvent event) { + this.initPatternSetting(); + this.updateClientSidePattern(); + } + + /** + * Does magic and sets the display pattern on the client side. + * Requires the client-side connector to have a {@code setDisplayPattern} method. + */ + protected void updateClientSidePattern() { + this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> + this.source.getElement().callJsFunction( + "setDisplayPattern", + this.source.getElement(), convertDatePatternToClientPattern(this.source.getDatePattern()) + ) + )); } } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java index 346b6b57..f8a8f264 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java @@ -30,6 +30,8 @@ public class SuperDatePicker extends DatePicker WithValueMixin, LocalDate, SuperDatePicker>, WithIdMixin { + private final DatePatternHelper delegate = new DatePatternHelper<>(this); + private DatePattern datePattern; public SuperDatePicker() { @@ -77,22 +79,25 @@ public SuperDatePicker(String label, LocalDate initialDate, ValueChangeListener< } public SuperDatePicker(LocalDate initialDate, Locale locale) { - super(initialDate, locale); + super(initialDate); + this.setLocale(locale); } @Override public final void setLocale(Locale locale) { - this.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this, context -> - this.getElement().callJsFunction("initPatternSetting", this.getElement()) - )); - SuperDatePickerI18nHelper.updateI18N(locale, this::getI18n, this::setI18n); + // there is a call for setting locale from the superclass' constructor + // and when that happens, the field is not yet initialised + if(this.delegate != null) { + this.delegate.initPatternSetting(); + SuperDatePickerI18nHelper.updateI18N(locale, this::getI18n, this::setI18n); + } super.setLocale(locale); } @Override public void setDatePattern(DatePattern datePattern) { this.datePattern = datePattern; - DatePatternHelper.setClientSidePattern(this, datePattern); + this.delegate.updateClientSidePattern(); } @Override diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java index b724ba4c..dce504f9 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java @@ -36,6 +36,8 @@ public class SuperDateTimePicker extends DateTimePicker private static final String INTERNAL_DATE_PICKER_FIELD_NAME = "datePicker"; private static final String INTERNAL_TIME_PICKER_FIELD_NAME = "timePicker"; + private final DatePatternHelper delegate = new DatePatternHelper<>(this); + private DatePattern datePattern; public SuperDateTimePicker() { @@ -89,11 +91,12 @@ public SuperDateTimePicker(LocalDateTime initialDateTime, Locale locale) { @Override public void setLocale(Locale locale) { - this.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this, context -> - this.getElement().callJsFunction("initPatternSetting", this) - )) - ; - SuperDatePickerI18nHelper.updateI18N(locale, this::getDatePickerI18n, this::setDatePickerI18n); + // this method is called from the constructor of the superclass + // which means that first time it gets called, the delegate is not yet initialised + if(this.delegate != null) { + this.delegate.initPatternSetting(); + SuperDatePickerI18nHelper.updateI18N(locale, this::getDatePickerI18n, this::setDatePickerI18n); + } super.setLocale(locale); } @@ -101,7 +104,7 @@ public void setLocale(Locale locale) { * Exposes an internal {@link DatePicker}, if it was successfully obtained through reflection. * @return A {@link DatePicker} used by this component, if possible. */ - public Optional getDatePicker() { + public Optional getInternalDatePicker() { return ReflectTools.getValueOfField(this, DatePicker.class, INTERNAL_DATE_PICKER_FIELD_NAME); } @@ -116,7 +119,7 @@ public Optional getInternalTimePicker() { @Override public void setDatePattern(DatePattern pattern) { this.datePattern = pattern; - DatePatternHelper.setClientSidePattern(this, pattern); + this.delegate.updateClientSidePattern(); } @Override From 2ce9a587f289cc068b73ccd6289d0280fd6405ef Mon Sep 17 00:00:00 2001 From: Miki Date: Tue, 12 May 2020 12:56:09 +0300 Subject: [PATCH 04/66] #108 set up in a separate profile (#109) #108 done code quality will be triggered on each pull request to development and master separate maven profile is created, requires a login token (which is available in GitHub) --- .github/workflows/codequality.yml | 21 +++++++++++++++++++++ superfields/pom.xml | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 .github/workflows/codequality.yml diff --git a/.github/workflows/codequality.yml b/.github/workflows/codequality.yml new file mode 100644 index 00000000..d4343578 --- /dev/null +++ b/.github/workflows/codequality.yml @@ -0,0 +1,21 @@ +name: Code Quality + +on: + pull_request: + branches: [master, development] + +jobs: + code_scan: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 10 + uses: actions/setup-java@v1 + with: + java-version: 10 + - name: Scan on SonarCloud.io + run: mvn verify sonar:sonar -Psonar --file superfields/pom.xml + env: + SONAR_TOKEN: ${{ secrets.SONARCLOUD_IO_LOGIN_KEY }} diff --git a/superfields/pom.xml b/superfields/pom.xml index 1d6dd8ea..4f38ce08 100644 --- a/superfields/pom.xml +++ b/superfields/pom.xml @@ -204,6 +204,27 @@ + + + sonar + + vaadin-miki_super-fields + vaadin-miki + https://sonarcloud.io + + + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 3.7.0.1746 + + + + + + directory From ac137aa005d4948b16a69e64621dd106e793693a Mon Sep 17 00:00:00 2001 From: Miki Date: Tue, 12 May 2020 23:44:08 +0300 Subject: [PATCH 05/66] automated release notes (#110) #107 done workflow files now update release notes when a release branch is created --- .github/workflows/setversion.yml | 36 +++++++++++++++--- superfields/release-notes.md | 65 ++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 superfields/release-notes.md diff --git a/.github/workflows/setversion.yml b/.github/workflows/setversion.yml index 4a416949..b3eceec5 100644 --- a/.github/workflows/setversion.yml +++ b/.github/workflows/setversion.yml @@ -1,13 +1,12 @@ -name: Set Version +name: Version and Release Notes on: create jobs: - set_version: + set-version: if: ${{ (github.event.ref_type == 'branch') && startsWith(github.event.ref, 'release-') }} runs-on: ubuntu-latest - timeout-minutes: 5 - + timeout-minutes: 15 steps: - uses: actions/checkout@v2 - name: Set up JDK 10 @@ -16,14 +15,39 @@ jobs: java-version: 10 server-id: github # Value of the distributionManagement/repository/id field of the pom.xml settings-path: ${{ github.workspace }} # location for the settings.xml file - - name: Set version + - id: what-version + name: Determine version run: | + set -x export VERSION="`echo ${{ github.event.ref }} | sed -e s/release-//g`" + echo "::set-output name=version::$VERSION" + - name: Set version and update readme + run: | + set -x + export VERSION="${{ steps.what-version.outputs.version }}" mvn versions:set -DnewVersion=$VERSION --file pom.xml mvn versions:set -DnewVersion=$VERSION --file superfields/pom.xml sed -i -e s/{VERSION}/$VERSION/g ./README.md + - name: Create milestone notes + uses: UnforgivenPL/milestone-notes@v1 + with: + match-milestone: "^${{ steps.what-version.outputs.version }} " + repository: ${{ github.repository }} + labels: "enhancement, api, bug" + - name: Format milestone notes + run: | + sed -i -e "s/## enhancement/## New features and enhancements/g" milestone-notes.md + sed -i -e "s/## api/## Changes to API/g" milestone-notes.md + sed -i -e "s/## bug/## Bug fixes/g" milestone-notes.md + sed -i -e "s/^$/(nothing reported)/g" milestone-notes.md + - name: Update release notes + run: | + echo -e "\n" | cat milestone-notes.md - superfields/release-notes.md > superfields/release-notes.md.new + mv superfields/release-notes.md.new superfields/release-notes.md + - name: Remove milestone notes + run: rm milestone-notes.md - name: Push changes uses: stefanzweifel/git-auto-commit-action@v4.1.6 with: - commit_message: "(bot) setting version for branch ${{ github.event.ref }}" + commit_message: "(bot) version and release notes updated to ${{ steps.what-version.outputs.version }}" branch: ${{ github.event.ref }} diff --git a/superfields/release-notes.md b/superfields/release-notes.md new file mode 100644 index 00000000..dd64dd71 --- /dev/null +++ b/superfields/release-notes.md @@ -0,0 +1,65 @@ +# 0.6 - ComponentObserver and UnloadObserver +## New features and enhancements +* \#66 - [A field that changes value on becoming shown and hidden](https://api.github.com/repos/vaadin-miki/super-fields/issues/66) +* \#69 - [ComponentObserver - reusing client-side IntersectionObserver as a server-side component](https://api.github.com/repos/vaadin-miki/super-fields/issues/69) +* \#75 - [Component for encapsulating beforeunload events](https://api.github.com/repos/vaadin-miki/super-fields/issues/75) +* \#80 - [Expand SuperTabs to work also with removing tab contents](https://api.github.com/repos/vaadin-miki/super-fields/issues/80) +* \#82 - [Allow overriding default container in SuperTabs](https://api.github.com/repos/vaadin-miki/super-fields/issues/82) +## Changes to API +* \#76 - [Make Vaadin dependencies not transitive](https://api.github.com/repos/vaadin-miki/super-fields/issues/76) +* \#85 - [Add WithItems also to ItemGrid](https://api.github.com/repos/vaadin-miki/super-fields/issues/85) +* \#86 - [Create WithValue to allow chaining setValue calls](https://api.github.com/repos/vaadin-miki/super-fields/issues/86) +* \#89 - [Expose DatePicker and TimePicker in SuperDateTimePicker](https://api.github.com/repos/vaadin-miki/super-fields/issues/89) +* \#92 - [Add WithIdMixin to all components](https://api.github.com/repos/vaadin-miki/super-fields/issues/92) +## Bug fixes +* \#81 - [Setting date display pattern does not work out-of-the-box](https://api.github.com/repos/vaadin-miki/super-fields/issues/81) +* \#83 - [SuperTabs should implement HasItems](https://api.github.com/repos/vaadin-miki/super-fields/issues/83) +* \#90 - [SuperTabs should be using removing handler by default](https://api.github.com/repos/vaadin-miki/super-fields/issues/90) +* \#93 - ["this.observer is undefined" after ObservedField is removed from dom and added again](https://api.github.com/repos/vaadin-miki/super-fields/issues/93) +* \#98 - [Vaadin production mode not included](https://api.github.com/repos/vaadin-miki/super-fields/issues/98) +# 0.5.1 - Fix maven dependencies +## New features and enhancements +(nothing reported) +## Changes to API +(nothing reported) +## Bug fixes +* \#70 - [Parent pom unavailable for Directory downloads](https://api.github.com/repos/vaadin-miki/super-fields/issues/70) +# 0.5 - LazyLoad +## New features and enhancements +* \#50 - [Investigate lazy loading for ItemGrid](https://api.github.com/repos/vaadin-miki/super-fields/issues/50) +* \#51 - [Custom date formatting for date components](https://api.github.com/repos/vaadin-miki/super-fields/issues/51) +## Changes to API +(nothing reported) +## Bug fixes +* \#56 - [Set width to full in number fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/56) +# 0.4 - ItemGrid +## New features and enhancements +* \#34 - [Basic version of `ItemGrid`](https://api.github.com/repos/vaadin-miki/super-fields/issues/34) +## Changes to API +(nothing reported) +## Bug fixes +(nothing reported) +# 0.3 - SuperTabs +## New features and enhancements +* \#26 - [SuperTabs](https://api.github.com/repos/vaadin-miki/super-fields/issues/26) +## Changes to API +* \#30 - [Add .withXYZ methods to all fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/30) +## Bug fixes +(nothing reported) +# 0.2 - Date components +## New features and enhancements +* \#12 - [SuperDatePicker](https://api.github.com/repos/vaadin-miki/super-fields/issues/12) +* \#20 - [SuperDateTimePicker](https://api.github.com/repos/vaadin-miki/super-fields/issues/20) +## Changes to API +(nothing reported) +## Bug fixes +(nothing reported) +# 0.1 - Number fields +## New features and enhancements +* \#2 - [SuperDoubleField](https://api.github.com/repos/vaadin-miki/super-fields/issues/2) +* \#4 - [SuperIntegerField and SuperLongField](https://api.github.com/repos/vaadin-miki/super-fields/issues/4) +* \#5 - [SuperBigDecimalField](https://api.github.com/repos/vaadin-miki/super-fields/issues/5) +## Changes to API +(nothing reported) +## Bug fixes +* \#10 - [Max integer length does not work if it is a multiplication of grouping size](https://api.github.com/repos/vaadin-miki/super-fields/issues/10) \ No newline at end of file From 5a61be57e1dff404c246d910e9fc6315ccc33a56 Mon Sep 17 00:00:00 2001 From: Miki Date: Tue, 12 May 2020 23:47:29 +0300 Subject: [PATCH 06/66] #111 done --- .github/workflows/codequality.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/codequality.yml b/.github/workflows/codequality.yml index d4343578..4ae637b4 100644 --- a/.github/workflows/codequality.yml +++ b/.github/workflows/codequality.yml @@ -3,6 +3,8 @@ name: Code Quality on: pull_request: branches: [master, development] + push: + branches: [master, development, java-8] jobs: code_scan: From aa302b53fb573e25a8877c8d09df34fd51b2a117 Mon Sep 17 00:00:00 2001 From: Miki Date: Wed, 13 May 2020 00:10:03 +0300 Subject: [PATCH 07/66] #113 done --- .github/workflows/codequality.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/codequality.yml b/.github/workflows/codequality.yml index 4ae637b4..9b83f09c 100644 --- a/.github/workflows/codequality.yml +++ b/.github/workflows/codequality.yml @@ -21,3 +21,4 @@ jobs: run: mvn verify sonar:sonar -Psonar --file superfields/pom.xml env: SONAR_TOKEN: ${{ secrets.SONARCLOUD_IO_LOGIN_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From bfcb333da89e59b6a58e58afac1088000b3508c2 Mon Sep 17 00:00:00 2001 From: Miki Date: Wed, 13 May 2020 00:21:16 +0300 Subject: [PATCH 08/66] #115 done --- .github/workflows/codequality.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/codequality.yml b/.github/workflows/codequality.yml index 9b83f09c..6091ad33 100644 --- a/.github/workflows/codequality.yml +++ b/.github/workflows/codequality.yml @@ -13,6 +13,8 @@ jobs: steps: - uses: actions/checkout@v2 + with: + fetch-depth: 0 - name: Set up JDK 10 uses: actions/setup-java@v1 with: From b62bf69df9aa91e7faa939350ba3add2a222480b Mon Sep 17 00:00:00 2001 From: Miki Date: Wed, 13 May 2020 19:41:54 +0300 Subject: [PATCH 09/66] #117 done workflow should in theory figure out version number (used for tag), release title and release notes from release-notes.md --- .github/workflows/makerelease.yml | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/makerelease.yml diff --git a/.github/workflows/makerelease.yml b/.github/workflows/makerelease.yml new file mode 100644 index 00000000..a6beb2a8 --- /dev/null +++ b/.github/workflows/makerelease.yml @@ -0,0 +1,34 @@ +name: Make Release + +on: + push: + branches: [master] + +jobs: + create-release: + runs-on: ubuntu-latest + timeout-minutes: 30 + + steps: + - uses: actions/checkout@v2 + - id: variables + run: | + echo "::set-output name=version::`head -1 superfields/release-notes.md | cut -d' ' -f2`" + echo "::set-output name=title::`head -1 superfields/release-notes.md | sed -n -e 's/^.* - //p'`" + export NOTES=`cat superfields/release-notes.md | sed -e '0,/^# /d;/^# /,$d'` + export NOTES="${NOTES//'%'/'%25'}" + export NOTES="${NOTES//$'\n'/'%0A'}" + export NOTES="${NOTES//$'\r'/'%0D'}" + echo "::set-output name=notes::$NOTES" + - name: Create Release + uses: fleskesvor/create-release@feature/support-target-commitish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: "v${{ steps.variables.outputs.version }}" + commitish: "master" + release_name: "${{ steps.variables.outputs.version }} - ${{ steps.variables.outputs.title }}" + body: | + ${{ steps.variables.outputs.notes }} + draft: false + prerelease: false \ No newline at end of file From 82bbb44ef27d8fb00864fd5711b7967bc564f226 Mon Sep 17 00:00:00 2001 From: Miki Date: Mon, 25 May 2020 22:17:06 +0300 Subject: [PATCH 10/66] #119 hopefully done, needs merging and testing (#120) #119 hopefully done, needs merging and testing --- .github/workflows/releasebranch.yml | 22 ++++++++++++++++++++++ .github/workflows/setversion.yml | 10 ++++++++++ 2 files changed, 32 insertions(+) create mode 100644 .github/workflows/releasebranch.yml diff --git a/.github/workflows/releasebranch.yml b/.github/workflows/releasebranch.yml new file mode 100644 index 00000000..fc67f869 --- /dev/null +++ b/.github/workflows/releasebranch.yml @@ -0,0 +1,22 @@ +name: Release branch on milestone close + +on: + milestone: + types: [closed] + +jobs: + make-branch: + runs-on: ubuntu-latest + if: ${{ startsWith(github.event.milestone.title, '0.') || startsWith(github.event.milestone.title, '1.') || startsWith(github.event.milestone.title, '2.') || startsWith(github.event.milestone.title, '3.') || startsWith(github.event.milestone.title, '4.') || startsWith(github.event.milestone.title, '5.') || startsWith(github.event.milestone.title, '6.') || startsWith(github.event.milestone.title, '7.') || startsWith(github.event.milestone.title, '8.') || startsWith(github.event.milestone.title, '9.') }} + steps: + - id: version + run: | + set -x + echo "::set-output name=version::`echo '${{ github.event.milestone.title }}' | cut -d' ' -f1`" + - name: Push release branch + uses: UnforgivenPL/push-branch@v2 + with: + repository: ${{ github.repository }} + token: ${{ secrets.ACTIONS_PAT }} + source: development + target: release-${{ steps.version.outputs.version }} diff --git a/.github/workflows/setversion.yml b/.github/workflows/setversion.yml index b3eceec5..74525957 100644 --- a/.github/workflows/setversion.yml +++ b/.github/workflows/setversion.yml @@ -51,3 +51,13 @@ jobs: with: commit_message: "(bot) version and release notes updated to ${{ steps.what-version.outputs.version }}" branch: ${{ github.event.ref }} + - name: Create PR + uses: UnforgivenPL/pull-request@v1 + with: + source: ${{ github.event.ref }} + target: master + repository: ${{ github.repository }} + token: ${{ secrets.ACTIONS_PAT }} + pr-title: Release ${{ steps.what-version.outputs.version }} ready + pr-body: Automatically created release ${{ steps.what-version.outputs.version }}. + pr-assignees: ${{ github.actor }} From 8cb6b86f544baf5180490c280fb3c3d09c686353 Mon Sep 17 00:00:00 2001 From: Miki Date: Mon, 25 May 2020 23:51:35 +0300 Subject: [PATCH 11/66] #22 and #124 done (#125) code uses Vaadin 14.2.0 --- demo-v14/package-lock.json | 2541 +++++++++++++++++++-------------- demo-v14/package.json | 112 +- demo-v14/pom.xml | 4 - demo-v14/webpack.generated.js | 120 +- pom.xml | 2 +- superfields/pom.xml | 37 +- 6 files changed, 1698 insertions(+), 1118 deletions(-) diff --git a/demo-v14/package-lock.json b/demo-v14/package-lock.json index 39a3559f..97778083 100644 --- a/demo-v14/package-lock.json +++ b/demo-v14/package-lock.json @@ -20,12 +20,80 @@ "source-map": "^0.5.0" }, "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "optional": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, "commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, "make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -36,6 +104,18 @@ "semver": "^5.6.0" } }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -66,12 +146,12 @@ } }, "@babel/compat-data": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.9.0.tgz", - "integrity": "sha512-zeFQrr+284Ekvd9e7KAX954LkapWiOmQtsfHirhxqfdlX6MEC32iRE+pqUGlYIBchdevaCwvzxWGSy/YBNI85g==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.9.6.tgz", + "integrity": "sha512-5QPTrNen2bm7RBc7dsOmcA5hbrS4O2Vhmk5XOL4zWW/zD/hV0iinpefDlkm+tBBy8kDtFaaeEvmAqt+nURAV2g==", "dev": true, "requires": { - "browserslist": "^4.9.1", + "browserslist": "^4.11.1", "invariant": "^2.2.4", "semver": "^5.5.0" }, @@ -85,19 +165,19 @@ } }, "@babel/core": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", - "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.6.tgz", + "integrity": "sha512-nD3deLvbsApbHAHttzIssYqgb883yU/d9roe4RZymBCDaZryMJDbptVpEpeQuRh4BJ+SYI8le9YGxKvFEvl1Wg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.0", + "@babel/generator": "^7.9.6", "@babel/helper-module-transforms": "^7.9.0", - "@babel/helpers": "^7.9.0", - "@babel/parser": "^7.9.0", + "@babel/helpers": "^7.9.6", + "@babel/parser": "^7.9.6", "@babel/template": "^7.8.6", - "@babel/traverse": "^7.9.0", - "@babel/types": "^7.9.0", + "@babel/traverse": "^7.9.6", + "@babel/types": "^7.9.6", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.1", @@ -147,12 +227,12 @@ } }, "@babel/generator": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz", - "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.6.tgz", + "integrity": "sha512-+htwWKJbH2bL72HRluF8zumBxzuX0ZZUFl3JLNyoUjM/Ho8wnVpPXM6aUz8cfKDqQ/h7zHqKt4xzJteUosckqQ==", "dev": true, "requires": { - "@babel/types": "^7.9.5", + "@babel/types": "^7.9.6", "jsesc": "^2.5.1", "lodash": "^4.17.13", "source-map": "^0.5.0" @@ -186,13 +266,13 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.8.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz", - "integrity": "sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.9.6.tgz", + "integrity": "sha512-x2Nvu0igO0ejXzx09B/1fGBxY9NXQlBW2kZsSxCJft+KHN8t9XWzIvFxtPHnBOAXpVsdxZKZFbRUC8TsNKajMw==", "dev": true, "requires": { - "@babel/compat-data": "^7.8.6", - "browserslist": "^4.9.1", + "@babel/compat-data": "^7.9.6", + "browserslist": "^4.11.1", "invariant": "^2.2.4", "levenary": "^1.1.1", "semver": "^5.5.0" @@ -338,15 +418,15 @@ } }, "@babel/helper-replace-supers": { - "version": "7.8.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz", - "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.9.6.tgz", + "integrity": "sha512-qX+chbxkbArLyCImk3bWV+jB5gTNU/rsze+JlcF6Nf8tVTigPJSI1o1oBow/9Resa1yehUO9lIipsmu9oG4RzA==", "dev": true, "requires": { "@babel/helper-member-expression-to-functions": "^7.8.3", "@babel/helper-optimise-call-expression": "^7.8.3", - "@babel/traverse": "^7.8.6", - "@babel/types": "^7.8.6" + "@babel/traverse": "^7.9.6", + "@babel/types": "^7.9.6" } }, "@babel/helper-simple-access": { @@ -387,14 +467,14 @@ } }, "@babel/helpers": { - "version": "7.9.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.2.tgz", - "integrity": "sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.6.tgz", + "integrity": "sha512-tI4bUbldloLcHWoRUMAj4g1bF313M/o6fBKhIsb3QnGVPwRm9JsNf/gqMkQ7zjqReABiffPV6RWj7hEglID5Iw==", "dev": true, "requires": { "@babel/template": "^7.8.3", - "@babel/traverse": "^7.9.0", - "@babel/types": "^7.9.0" + "@babel/traverse": "^7.9.6", + "@babel/types": "^7.9.6" } }, "@babel/highlight": { @@ -409,9 +489,9 @@ } }, "@babel/parser": { - "version": "7.9.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", - "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.6.tgz", + "integrity": "sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q==", "dev": true }, "@babel/plugin-proposal-async-generator-functions": { @@ -466,9 +546,9 @@ } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.5.tgz", - "integrity": "sha512-VP2oXvAf7KCYTthbUHwBlewbl1Iq059f6seJGsxMizaCdgHIeczOr7FBqELhSqfkIl04Fi8okzWzl63UKbQmmg==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.6.tgz", + "integrity": "sha512-Ga6/fhGqA9Hj+y6whNpPv8psyaK5xzrQwSPsGPloVkvmH+PqW1ixdnfJ9uIO06OjQNYol3PMnfmJ8vfZtkzF+A==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.8.3", @@ -727,38 +807,38 @@ } }, "@babel/plugin-transform-modules-amd": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz", - "integrity": "sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.6.tgz", + "integrity": "sha512-zoT0kgC3EixAyIAU+9vfaUVKTv9IxBDSabgHoUCBP6FqEJ+iNiN7ip7NBKcYqbfUDfuC2mFCbM7vbu4qJgOnDw==", "dev": true, "requires": { "@babel/helper-module-transforms": "^7.9.0", "@babel/helper-plugin-utils": "^7.8.3", - "babel-plugin-dynamic-import-node": "^2.3.0" + "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz", - "integrity": "sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.6.tgz", + "integrity": "sha512-7H25fSlLcn+iYimmsNe3uK1at79IE6SKW9q0/QeEHTMC9MdOZ+4bA+T1VFB5fgOqBWoqlifXRzYD0JPdmIrgSQ==", "dev": true, "requires": { "@babel/helper-module-transforms": "^7.9.0", "@babel/helper-plugin-utils": "^7.8.3", "@babel/helper-simple-access": "^7.8.3", - "babel-plugin-dynamic-import-node": "^2.3.0" + "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz", - "integrity": "sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.6.tgz", + "integrity": "sha512-NW5XQuW3N2tTHim8e1b7qGy7s0kZ2OH3m5octc49K1SdAKGxYxeIx7hiIz05kS1R2R+hOWcsr1eYwcGhrdHsrg==", "dev": true, "requires": { "@babel/helper-hoist-variables": "^7.8.3", "@babel/helper-module-transforms": "^7.9.0", "@babel/helper-plugin-utils": "^7.8.3", - "babel-plugin-dynamic-import-node": "^2.3.0" + "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-umd": { @@ -837,9 +917,9 @@ } }, "@babel/plugin-transform-runtime": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz", - "integrity": "sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.6.tgz", + "integrity": "sha512-qcmiECD0mYOjOIt8YHNsAP1SxPooC/rDmfmiSK9BNY72EitdSc7l44WTEklaWuFtbOEBjNhWWyph/kOImbNJ4w==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.8.3", @@ -914,13 +994,13 @@ } }, "@babel/preset-env": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.9.5.tgz", - "integrity": "sha512-eWGYeADTlPJH+wq1F0wNfPbVS1w1wtmMJiYk55Td5Yu28AsdR9AsC97sZ0Qq8fHqQuslVSIYSGJMcblr345GfQ==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.9.6.tgz", + "integrity": "sha512-0gQJ9RTzO0heXOhzftog+a/WyOuqMrAIugVYxMYf83gh1CQaQDjMtsOpqOwXyDL/5JcWsrCm8l4ju8QC97O7EQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.9.0", - "@babel/helper-compilation-targets": "^7.8.7", + "@babel/compat-data": "^7.9.6", + "@babel/helper-compilation-targets": "^7.9.6", "@babel/helper-module-imports": "^7.8.3", "@babel/helper-plugin-utils": "^7.8.3", "@babel/plugin-proposal-async-generator-functions": "^7.8.3", @@ -928,7 +1008,7 @@ "@babel/plugin-proposal-json-strings": "^7.8.3", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-proposal-numeric-separator": "^7.8.3", - "@babel/plugin-proposal-object-rest-spread": "^7.9.5", + "@babel/plugin-proposal-object-rest-spread": "^7.9.6", "@babel/plugin-proposal-optional-catch-binding": "^7.8.3", "@babel/plugin-proposal-optional-chaining": "^7.9.0", "@babel/plugin-proposal-unicode-property-regex": "^7.8.3", @@ -955,9 +1035,9 @@ "@babel/plugin-transform-function-name": "^7.8.3", "@babel/plugin-transform-literals": "^7.8.3", "@babel/plugin-transform-member-expression-literals": "^7.8.3", - "@babel/plugin-transform-modules-amd": "^7.9.0", - "@babel/plugin-transform-modules-commonjs": "^7.9.0", - "@babel/plugin-transform-modules-systemjs": "^7.9.0", + "@babel/plugin-transform-modules-amd": "^7.9.6", + "@babel/plugin-transform-modules-commonjs": "^7.9.6", + "@babel/plugin-transform-modules-systemjs": "^7.9.6", "@babel/plugin-transform-modules-umd": "^7.9.0", "@babel/plugin-transform-named-capturing-groups-regex": "^7.8.3", "@babel/plugin-transform-new-target": "^7.8.3", @@ -973,8 +1053,8 @@ "@babel/plugin-transform-typeof-symbol": "^7.8.4", "@babel/plugin-transform-unicode-regex": "^7.8.3", "@babel/preset-modules": "^0.1.3", - "@babel/types": "^7.9.5", - "browserslist": "^4.9.1", + "@babel/types": "^7.9.6", + "browserslist": "^4.11.1", "core-js-compat": "^3.6.2", "invariant": "^2.2.2", "levenary": "^1.1.1", @@ -1003,9 +1083,9 @@ } }, "@babel/runtime": { - "version": "7.9.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz", - "integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.6.tgz", + "integrity": "sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ==", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" @@ -1023,17 +1103,17 @@ } }, "@babel/traverse": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz", - "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.6.tgz", + "integrity": "sha512-b3rAHSjbxy6VEAvlxM8OV/0X4XrG72zoxme6q1MOoe2vd0bEc+TwayhuC1+Dfgqh1QEG+pj7atQqvUprHIccsg==", "dev": true, "requires": { "@babel/code-frame": "^7.8.3", - "@babel/generator": "^7.9.5", + "@babel/generator": "^7.9.6", "@babel/helper-function-name": "^7.9.5", "@babel/helper-split-export-declaration": "^7.8.3", - "@babel/parser": "^7.9.0", - "@babel/types": "^7.9.5", + "@babel/parser": "^7.9.6", + "@babel/types": "^7.9.6", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.13" @@ -1057,9 +1137,9 @@ } }, "@babel/types": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz", - "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.6.tgz", + "integrity": "sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.9.5", @@ -1185,56 +1265,10 @@ "dev": true }, "@types/node": { - "version": "13.13.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.2.tgz", - "integrity": "sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A==", - "dev": true - }, - "@vaadin/flow-deps": { - "version": "file:target/frontend", - "requires": { - "@polymer/iron-icon": "3.0.1", - "@polymer/iron-list": "3.0.2", - "@vaadin/vaadin-accordion": "1.0.1", - "@vaadin/vaadin-app-layout": "2.0.5", - "@vaadin/vaadin-board": "2.1.1", - "@vaadin/vaadin-button": "2.2.2", - "@vaadin/vaadin-charts": "6.2.4", - "@vaadin/vaadin-checkbox": "2.2.13", - "@vaadin/vaadin-combo-box": "5.0.11", - "@vaadin/vaadin-confirm-dialog": "1.1.6", - "@vaadin/vaadin-context-menu": "4.3.15", - "@vaadin/vaadin-cookie-consent": "1.1.2", - "@vaadin/vaadin-core-shrinkwrap": "14.1.25", - "@vaadin/vaadin-crud": "1.1.0", - "@vaadin/vaadin-custom-field": "1.0.11", - "@vaadin/vaadin-date-picker": "4.0.8", - "@vaadin/vaadin-date-time-picker": "1.0.0-alpha6", - "@vaadin/vaadin-details": "1.0.1", - "@vaadin/vaadin-dialog": "2.2.1", - "@vaadin/vaadin-form-layout": "2.1.7", - "@vaadin/vaadin-grid": "5.5.2", - "@vaadin/vaadin-grid-pro": "2.0.7", - "@vaadin/vaadin-icons": "4.3.1", - "@vaadin/vaadin-item": "2.1.1", - "@vaadin/vaadin-list-box": "1.2.0", - "@vaadin/vaadin-login": "1.0.1", - "@vaadin/vaadin-lumo-styles": "1.5.0", - "@vaadin/vaadin-material-styles": "1.2.3", - "@vaadin/vaadin-menu-bar": "1.0.3", - "@vaadin/vaadin-notification": "1.4.0", - "@vaadin/vaadin-ordered-layout": "1.1.0", - "@vaadin/vaadin-progress-bar": "1.1.2", - "@vaadin/vaadin-radio-button": "1.2.6", - "@vaadin/vaadin-rich-text-editor": "1.1.1", - "@vaadin/vaadin-select": "2.1.7", - "@vaadin/vaadin-shrinkwrap": "14.1.25", - "@vaadin/vaadin-split-layout": "4.1.1", - "@vaadin/vaadin-tabs": "3.0.5", - "@vaadin/vaadin-text-field": "2.5.5", - "@vaadin/vaadin-time-picker": "2.0.7", - "@vaadin/vaadin-upload": "4.2.2" - } + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.5.tgz", + "integrity": "sha512-90hiq6/VqtQgX8Sp0EzeIsv3r+ellbGj4URKj5j30tLlZvRUpnAe9YbYnjl3pJM93GyXU0tghHhvXHq+5rnCKA==", + "dev": true }, "@vaadin/vaadin-accordion": { "version": "1.0.1", @@ -1364,9 +1398,9 @@ } }, "@vaadin/vaadin-control-state-mixin": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-control-state-mixin/-/vaadin-control-state-mixin-2.2.1.tgz", - "integrity": "sha512-Y/y2aRXiQqa7sqQM2f5DkXK2U+sHEyGql67SXaXljGIMiFT0H7rfJZ+5TcXucpsUb2z+R0oCq8Q3+GES9YP9Fg==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-control-state-mixin/-/vaadin-control-state-mixin-2.2.2.tgz", + "integrity": "sha512-e9WTmVPsUKlsm6FoITQEAWN6yHqy6MWiS0/m1+DXrKmboXeKS7mVyf/+Bdp1PGh7Ml6U2GzdPCIi7Yt41fJAhw==", "requires": { "@polymer/polymer": "^3.0.0" } @@ -1386,9 +1420,9 @@ } }, "@vaadin/vaadin-core-shrinkwrap": { - "version": "14.1.25", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-core-shrinkwrap/-/vaadin-core-shrinkwrap-14.1.25.tgz", - "integrity": "sha512-fMH5Cbzlum3gwGoAqBDPxlbEuYCtJpS629pj1H7xhSghsOltR1HbkVXeOE7Lnpo6GLQUPqub9XxfKfz6bTpDpA==", + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-core-shrinkwrap/-/vaadin-core-shrinkwrap-14.2.0.tgz", + "integrity": "sha512-Y+cvLsvn7AwD9OW9u340a3bddqFFTAjJQMw5dU+5PtfMedJKpUXHjhOmfmxYmHk9v0h8KZLxpayXOobP6iQV2Q==", "requires": { "@polymer/iron-a11y-announcer": "^3.0.2", "@polymer/iron-a11y-keys-behavior": "^3.0.1", @@ -1411,12 +1445,13 @@ "@vaadin/vaadin-control-state-mixin": "^2.1.3", "@vaadin/vaadin-custom-field": "^1.0.11", "@vaadin/vaadin-date-picker": "^4.0.8", + "@vaadin/vaadin-date-time-picker": "^1.0.0", "@vaadin/vaadin-details": "^1.0.1", "@vaadin/vaadin-development-mode-detector": "^2.0.4", - "@vaadin/vaadin-dialog": "^2.2.1", + "@vaadin/vaadin-dialog": "^2.3.0", "@vaadin/vaadin-element-mixin": "^2.2.0", "@vaadin/vaadin-form-layout": "^2.1.7", - "@vaadin/vaadin-grid": "^5.5.2", + "@vaadin/vaadin-grid": "^5.5.3", "@vaadin/vaadin-icons": "^4.3.1", "@vaadin/vaadin-item": "^2.1.1", "@vaadin/vaadin-list-box": "^1.2.0", @@ -1424,10 +1459,10 @@ "@vaadin/vaadin-login": "^1.0.1", "@vaadin/vaadin-lumo-styles": "^1.5.0", "@vaadin/vaadin-material-styles": "^1.2.3", - "@vaadin/vaadin-menu-bar": "^1.0.3", + "@vaadin/vaadin-menu-bar": "^1.0.5", "@vaadin/vaadin-notification": "^1.4.0", - "@vaadin/vaadin-ordered-layout": "^1.1.0", - "@vaadin/vaadin-overlay": "^3.2.19", + "@vaadin/vaadin-ordered-layout": "^1.2.0", + "@vaadin/vaadin-overlay": "^3.3.1", "@vaadin/vaadin-progress-bar": "^1.1.2", "@vaadin/vaadin-radio-button": "^1.2.6", "@vaadin/vaadin-select": "^2.1.7", @@ -1682,6 +1717,157 @@ "@vaadin/vaadin-themable-mixin": "^1.3.2" } }, + "@vaadin/vaadin-date-time-picker": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-date-time-picker/-/vaadin-date-time-picker-1.1.0.tgz", + "integrity": "sha512-uCTIOouRlaNdXV9vUrFI4Dckv1w6i1YJdtI+n2qT4Irh32mFwdTNljJZQW3MnFoBDY4eGtMRNbrc/FK6LHj4rw==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-custom-field": "^1.1.0", + "@vaadin/vaadin-date-picker": "^4.1.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-themable-mixin": "^1.3.2", + "@vaadin/vaadin-time-picker": "^2.1.0" + }, + "dependencies": { + "@vaadin/vaadin-button": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-button/-/vaadin-button-2.3.0.tgz", + "integrity": "sha512-FnKvsxwBQhXWV/kW+PNY+vFF+V6cQE6IiSH32LZ6rlZ+aqsvpRLEF4yNr3sg39yBsdWfeU1J+44Ne4chPbcizA==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.0.0", + "@vaadin/vaadin-lumo-styles": "^1.3.3", + "@vaadin/vaadin-material-styles": "^1.2.0", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + }, + "@vaadin/vaadin-combo-box": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-combo-box/-/vaadin-combo-box-5.1.0.tgz", + "integrity": "sha512-7EBfTP+oAt7m1Hx1JffcNix95IJbM4weOg9LOQWrD2+Ei+NePcJIl1v3nHzErIPhdh/M+LkFcRo7dV5HT/A6Lw==", + "requires": { + "@polymer/iron-a11y-announcer": "^3.0.0", + "@polymer/iron-a11y-keys-behavior": "^3.0.0", + "@polymer/iron-list": "^3.0.0", + "@polymer/iron-resizable-behavior": "^3.0.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-item": "^2.2.0-alpha1", + "@vaadin/vaadin-lumo-styles": "^1.1.1", + "@vaadin/vaadin-material-styles": "^1.1.2", + "@vaadin/vaadin-overlay": "^3.4.0", + "@vaadin/vaadin-text-field": "^2.6.0", + "@vaadin/vaadin-themable-mixin": "^1.5.2" + } + }, + "@vaadin/vaadin-custom-field": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-custom-field/-/vaadin-custom-field-1.1.0.tgz", + "integrity": "sha512-fPaIJFjYO6UO4HMUA2Ps3GRPE1/gNPLvGSwy7x9L1vGk6iPW5PX0GObj+LE14PIzvJGW/9UcbaSSPhFrK6FL1g==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-themable-mixin": "^1.5.2" + } + }, + "@vaadin/vaadin-date-picker": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-date-picker/-/vaadin-date-picker-4.1.1.tgz", + "integrity": "sha512-L+Wq4BrTeVNwsJRf+QH8OUBsBS9fTekHznmFlqv6ux4vuAmGqTbtHnM0QGy7Ijx1TvfFLOLaxa8yAMW9xmlhsA==", + "requires": { + "@polymer/iron-a11y-announcer": "^3.0.0", + "@polymer/iron-a11y-keys-behavior": "^3.0.0", + "@polymer/iron-media-query": "^3.0.0", + "@polymer/iron-resizable-behavior": "^3.0.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-button": "^2.3.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.3.1", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-overlay": "^3.4.0", + "@vaadin/vaadin-text-field": "^2.6.0", + "@vaadin/vaadin-themable-mixin": "^1.5.2" + } + }, + "@vaadin/vaadin-element-mixin": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-element-mixin/-/vaadin-element-mixin-2.4.1.tgz", + "integrity": "sha512-Ie7fwcOmg1C71UFuRwcuo2GKS+HbKvLedfs3hGdICiuwJ56cQvQsbIlxa4utKWWCVlf6yuSvMrny8efPPenfTA==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-development-mode-detector": "^2.0.0", + "@vaadin/vaadin-usage-statistics": "^2.1.0" + } + }, + "@vaadin/vaadin-item": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-item/-/vaadin-item-2.2.0.tgz", + "integrity": "sha512-Yvpd2fiTwvfJA18lfjYsj33L+yr/YfHg3WZNp+v8OghfacfMdD5JofJpK6s0cJIuNTg+TC6hG1UwzcEC9jNMFw==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.1.0", + "@vaadin/vaadin-material-styles": "^1.1.0", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + }, + "@vaadin/vaadin-lumo-styles": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-lumo-styles/-/vaadin-lumo-styles-1.6.0.tgz", + "integrity": "sha512-MTJ2JssEVF3Go5b+zIe86Jw8nNtaN91wHmO2Ic1eI27PEJ5dRRGcLWX9CjTEx/8Zu9+3Fk4YeVP9ABWhiZZGUw==", + "requires": { + "@polymer/iron-icon": "^3.0.0", + "@polymer/iron-iconset-svg": "^3.0.0", + "@polymer/polymer": "^3.0.0" + } + }, + "@vaadin/vaadin-material-styles": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-material-styles/-/vaadin-material-styles-1.3.2.tgz", + "integrity": "sha512-EFrvGScoxhLNrPnWtT2Ia77whjF2TD4jrcyeh1jv9joCA2n5SUba+4XJciVSGmopqqQato6lwRnZSvMLJX7cyw==", + "requires": { + "@polymer/polymer": "^3.0.0" + } + }, + "@vaadin/vaadin-text-field": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-text-field/-/vaadin-text-field-2.6.0.tgz", + "integrity": "sha512-ErwPR67Fq1Zw9VWdj1ZHPk5JuNR0n+lMQk2wH7JmH1xibzXC20t2qkgaJUDnT5YpJ4Ap+7ZypUxBKWcbDu9D3A==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + }, + "@vaadin/vaadin-time-picker": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-time-picker/-/vaadin-time-picker-2.1.0.tgz", + "integrity": "sha512-t27xrcOr2fq7OKViMatLpw6ICVoDeZJkeH2wZtghNIbpVEiTM/tEwmmVjP2tWjON44Xt6siCIM3K/bHGYgzlIA==", + "requires": { + "@polymer/iron-a11y-keys-behavior": "^3.0.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-combo-box": "^5.1.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-text-field": "^2.6.0", + "@vaadin/vaadin-themable-mixin": "^1.3.2" + } + } + } + }, "@vaadin/vaadin-details": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@vaadin/vaadin-details/-/vaadin-details-1.0.1.tgz", @@ -1701,15 +1887,16 @@ "integrity": "sha512-S+PaFrZpK8uBIOnIHxjntTrgumd5ztuCnZww96ydGKXgo9whXfZsbMwDuD/102a/IuPUMyF+dh/n3PbWzJ6igA==" }, "@vaadin/vaadin-dialog": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-dialog/-/vaadin-dialog-2.2.1.tgz", - "integrity": "sha512-OPaXsCdVYWm8wR0c/kJ822SnjHwSi69kpp2zywB9SwvxauHnS/88ZHnJyHT5JunKw1otsHYmEa0Uqc1WYhIkQw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-dialog/-/vaadin-dialog-2.3.0.tgz", + "integrity": "sha512-Pbd65c4JOYps0Xa+ZpXnqQ8F3zlrCF0EJ2xG/IQEwQEJ5/K2TmNFkJyeDvquCiRM/GWl0c3YVK955WTvGU4QOQ==", "requires": { + "@polymer/iron-resizable-behavior": "^3.0.0", "@polymer/polymer": "^3.0.0", "@vaadin/vaadin-element-mixin": "^2.0.0", "@vaadin/vaadin-lumo-styles": "^1.1.0", "@vaadin/vaadin-material-styles": "^1.1.0", - "@vaadin/vaadin-overlay": "^3.2.0", + "@vaadin/vaadin-overlay": "^3.3.0", "@vaadin/vaadin-themable-mixin": "^1.3.2" } }, @@ -1737,21 +1924,77 @@ } }, "@vaadin/vaadin-grid": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-grid/-/vaadin-grid-5.5.2.tgz", - "integrity": "sha512-0wMc60baLoyLgjmrvrBLIDamLC3ANSeWFbdZV77dATyC12xo3WFgd97tPWerPKf/9b4EIwWVjRowq2rz+9beNg==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-grid/-/vaadin-grid-5.6.1.tgz", + "integrity": "sha512-tn7TbBMIsED1vKIJS8jn6Wb17zh2xS5R6pXrlENJc2RT0eMbWpqAjmZryNdOvXZf44JKcfH0omENTlCkQjbXxQ==", "requires": { "@polymer/iron-a11y-announcer": "^3.0.0", "@polymer/iron-a11y-keys-behavior": "^3.0.0", "@polymer/iron-resizable-behavior": "^3.0.0", "@polymer/iron-scroll-target-behavior": "^3.0.0", "@polymer/polymer": "^3.0.0", - "@vaadin/vaadin-checkbox": "^2.2.1", - "@vaadin/vaadin-element-mixin": "^2.1.1", - "@vaadin/vaadin-lumo-styles": "^1.1.1", - "@vaadin/vaadin-material-styles": "^1.1.1", - "@vaadin/vaadin-text-field": "^2.1.1", - "@vaadin/vaadin-themable-mixin": "^1.2.1" + "@vaadin/vaadin-checkbox": "^2.3.0", + "@vaadin/vaadin-element-mixin": "^2.3.2", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-text-field": "^2.6.0", + "@vaadin/vaadin-themable-mixin": "^1.5.2" + }, + "dependencies": { + "@vaadin/vaadin-checkbox": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-checkbox/-/vaadin-checkbox-2.3.0.tgz", + "integrity": "sha512-f3yyBBTj58gZDudYh8nGn2ZNOrubg2e05mp7d7roI7xEVcfwT/Y4a/D9bHeBcOgI8LvwN8fToxIIFBt5b8UA6g==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.4.1", + "@vaadin/vaadin-material-styles": "^1.2.0", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + }, + "@vaadin/vaadin-element-mixin": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-element-mixin/-/vaadin-element-mixin-2.4.1.tgz", + "integrity": "sha512-Ie7fwcOmg1C71UFuRwcuo2GKS+HbKvLedfs3hGdICiuwJ56cQvQsbIlxa4utKWWCVlf6yuSvMrny8efPPenfTA==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-development-mode-detector": "^2.0.0", + "@vaadin/vaadin-usage-statistics": "^2.1.0" + } + }, + "@vaadin/vaadin-lumo-styles": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-lumo-styles/-/vaadin-lumo-styles-1.6.0.tgz", + "integrity": "sha512-MTJ2JssEVF3Go5b+zIe86Jw8nNtaN91wHmO2Ic1eI27PEJ5dRRGcLWX9CjTEx/8Zu9+3Fk4YeVP9ABWhiZZGUw==", + "requires": { + "@polymer/iron-icon": "^3.0.0", + "@polymer/iron-iconset-svg": "^3.0.0", + "@polymer/polymer": "^3.0.0" + } + }, + "@vaadin/vaadin-material-styles": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-material-styles/-/vaadin-material-styles-1.3.2.tgz", + "integrity": "sha512-EFrvGScoxhLNrPnWtT2Ia77whjF2TD4jrcyeh1jv9joCA2n5SUba+4XJciVSGmopqqQato6lwRnZSvMLJX7cyw==", + "requires": { + "@polymer/polymer": "^3.0.0" + } + }, + "@vaadin/vaadin-text-field": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-text-field/-/vaadin-text-field-2.6.0.tgz", + "integrity": "sha512-ErwPR67Fq1Zw9VWdj1ZHPk5JuNR0n+lMQk2wH7JmH1xibzXC20t2qkgaJUDnT5YpJ4Ap+7ZypUxBKWcbDu9D3A==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + } } }, "@vaadin/vaadin-icons": { @@ -1831,18 +2074,112 @@ } }, "@vaadin/vaadin-menu-bar": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-menu-bar/-/vaadin-menu-bar-1.0.3.tgz", - "integrity": "sha512-VsCt5yqNWzSc3bzrwK8CZHMdArsTQNvoR+4oYDLr1+DvBSnRYuDD6dQiuhxjCNcx9qtcmuH6eTXTFfczD/jFqw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-menu-bar/-/vaadin-menu-bar-1.1.0.tgz", + "integrity": "sha512-4CgN12YJdYDsqENa73JaxSw+5hKAeM54b80HYBe5QVa0skIt1pSJZnUhGZ9Gkw/cW2xjtnwXI2lYcOglyUt4WA==", "requires": { "@polymer/iron-resizable-behavior": "^3.0.0", "@polymer/polymer": "^3.0.0", - "@vaadin/vaadin-button": "^2.1.4", - "@vaadin/vaadin-context-menu": "^4.3.8", - "@vaadin/vaadin-element-mixin": "^2.0.0", - "@vaadin/vaadin-lumo-styles": "^1.4.1", - "@vaadin/vaadin-material-styles": "^1.2.2", - "@vaadin/vaadin-themable-mixin": "^1.2.0" + "@vaadin/vaadin-button": "^2.3.0", + "@vaadin/vaadin-context-menu": "^4.4.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-themable-mixin": "^1.5.0" + }, + "dependencies": { + "@vaadin/vaadin-button": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-button/-/vaadin-button-2.3.0.tgz", + "integrity": "sha512-FnKvsxwBQhXWV/kW+PNY+vFF+V6cQE6IiSH32LZ6rlZ+aqsvpRLEF4yNr3sg39yBsdWfeU1J+44Ne4chPbcizA==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.0.0", + "@vaadin/vaadin-lumo-styles": "^1.3.3", + "@vaadin/vaadin-material-styles": "^1.2.0", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + }, + "@vaadin/vaadin-context-menu": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-context-menu/-/vaadin-context-menu-4.4.0.tgz", + "integrity": "sha512-q6S7UkNkuf5/dEDoV4UHq79j0+R9I79znDqO6gVk4cPv7Iy4cl79AnJHGqS4ippuVv4P7/3VUDz+SGNbXDk36A==", + "requires": { + "@polymer/iron-media-query": "^3.0.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.3.1", + "@vaadin/vaadin-item": "^2.2.0", + "@vaadin/vaadin-list-box": "^1.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-overlay": "^3.4.0", + "@vaadin/vaadin-themable-mixin": "^1.5.2" + } + }, + "@vaadin/vaadin-element-mixin": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-element-mixin/-/vaadin-element-mixin-2.4.1.tgz", + "integrity": "sha512-Ie7fwcOmg1C71UFuRwcuo2GKS+HbKvLedfs3hGdICiuwJ56cQvQsbIlxa4utKWWCVlf6yuSvMrny8efPPenfTA==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-development-mode-detector": "^2.0.0", + "@vaadin/vaadin-usage-statistics": "^2.1.0" + } + }, + "@vaadin/vaadin-item": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-item/-/vaadin-item-2.2.0.tgz", + "integrity": "sha512-Yvpd2fiTwvfJA18lfjYsj33L+yr/YfHg3WZNp+v8OghfacfMdD5JofJpK6s0cJIuNTg+TC6hG1UwzcEC9jNMFw==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.1.0", + "@vaadin/vaadin-material-styles": "^1.1.0", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + }, + "@vaadin/vaadin-list-box": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-list-box/-/vaadin-list-box-1.3.0.tgz", + "integrity": "sha512-SETW+VwFa31STfKog7Fb9uN42KvbCpFoEoD1UhJaQLzgOPq/DdYhNKzFeuMZcbsLGx8BBL9ycoqKIDZCTk1y1w==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-item": "^2.2.0", + "@vaadin/vaadin-list-mixin": "^2.4.0", + "@vaadin/vaadin-lumo-styles": "^1.1.0", + "@vaadin/vaadin-material-styles": "^1.1.0", + "@vaadin/vaadin-themable-mixin": "^1.5.2" + } + }, + "@vaadin/vaadin-list-mixin": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-list-mixin/-/vaadin-list-mixin-2.5.0.tgz", + "integrity": "sha512-NyQMJZ4sQ35gQxCOdoeBbGW2ou+MfqZRc9DSWotVgJheusRCV7wMHqUmKU/KyFa/IQ8ZoxWbVPdap8I9hyMKfA==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.4.1" + } + }, + "@vaadin/vaadin-lumo-styles": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-lumo-styles/-/vaadin-lumo-styles-1.6.0.tgz", + "integrity": "sha512-MTJ2JssEVF3Go5b+zIe86Jw8nNtaN91wHmO2Ic1eI27PEJ5dRRGcLWX9CjTEx/8Zu9+3Fk4YeVP9ABWhiZZGUw==", + "requires": { + "@polymer/iron-icon": "^3.0.0", + "@polymer/iron-iconset-svg": "^3.0.0", + "@polymer/polymer": "^3.0.0" + } + }, + "@vaadin/vaadin-material-styles": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-material-styles/-/vaadin-material-styles-1.3.2.tgz", + "integrity": "sha512-EFrvGScoxhLNrPnWtT2Ia77whjF2TD4jrcyeh1jv9joCA2n5SUba+4XJciVSGmopqqQato6lwRnZSvMLJX7cyw==", + "requires": { + "@polymer/polymer": "^3.0.0" + } + } } }, "@vaadin/vaadin-notification": { @@ -1858,9 +2195,9 @@ } }, "@vaadin/vaadin-ordered-layout": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-ordered-layout/-/vaadin-ordered-layout-1.1.0.tgz", - "integrity": "sha512-ln3dXms/JmKCYu4sTc/xANxF13V8S6A1f/0xKvohYOEU5fRvq7suc8SR7GesyfXouF40kbFJ49sqTquK9TP95A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-ordered-layout/-/vaadin-ordered-layout-1.2.0.tgz", + "integrity": "sha512-srumEsOO599PmVX1L5oszNEz7sRHAhwn6LIDOFD+i9niGkFCq7Eijj2sGJ4KPWPA38XlzD2lo/zsM1wegf9o2Q==", "requires": { "@polymer/polymer": "^3.0.0", "@vaadin/vaadin-element-mixin": "^2.0.0", @@ -1870,14 +2207,27 @@ } }, "@vaadin/vaadin-overlay": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-overlay/-/vaadin-overlay-3.3.1.tgz", - "integrity": "sha512-O/ROYmShZoNFtHPxp/kNLQZy5r0wExg+m2G4AuHVDbw76EZaOpLGdxD6e/PoBT3f7+XxLb3X+LfZqBdew5iZvA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-overlay/-/vaadin-overlay-3.4.0.tgz", + "integrity": "sha512-796BtX3irl3HzEqXmvBzfUb5/WljD7x8hRnH+9OAW8jWAXg+mtPnxZEyGyhJF0s9D55Uliwj1ErkR4EHZ97How==", "requires": { "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", "@vaadin/vaadin-lumo-styles": "^1.3.0", "@vaadin/vaadin-material-styles": "^1.2.0", "@vaadin/vaadin-themable-mixin": "^1.2.1" + }, + "dependencies": { + "@vaadin/vaadin-element-mixin": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-element-mixin/-/vaadin-element-mixin-2.3.0.tgz", + "integrity": "sha512-9gQb6Y3c/KlkJkITr+JncBZQ3iAjLpU/B6Ykeis+AHjPn6p+f4x3xsJ09IJKtb5YqD5wy9Zu7ANdM++97abQ2g==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-development-mode-detector": "^2.0.0", + "@vaadin/vaadin-usage-statistics": "^2.1.0" + } + } } }, "@vaadin/vaadin-progress-bar": { @@ -2086,9 +2436,9 @@ } }, "@vaadin/vaadin-date-time-picker": { - "version": "1.0.0-alpha6", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-date-time-picker/-/vaadin-date-time-picker-1.0.0-alpha6.tgz", - "integrity": "sha512-8mf91N4iPc2PplBfHXfvtZ0YeAgwQYOle15d3kjYSA5w/nBpIcXKL5IGokD1z309rC3kHSDOR4QlgiRvzP4yqQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-date-time-picker/-/vaadin-date-time-picker-1.0.0.tgz", + "integrity": "sha512-83FmKSrHOTlp4sSX4rmcYV1kxoDmu76KDi0nh2LsskBTdF43vdjp76SmCjVsNhousjB2OTIMnZpDF8mI/0wWMw==", "requires": { "@polymer/polymer": "^3.0.0", "@vaadin/vaadin-custom-field": "^1.0.11", @@ -2119,22 +2469,23 @@ "integrity": "sha512-S+PaFrZpK8uBIOnIHxjntTrgumd5ztuCnZww96ydGKXgo9whXfZsbMwDuD/102a/IuPUMyF+dh/n3PbWzJ6igA==" }, "@vaadin/vaadin-dialog": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-dialog/-/vaadin-dialog-2.2.1.tgz", - "integrity": "sha512-OPaXsCdVYWm8wR0c/kJ822SnjHwSi69kpp2zywB9SwvxauHnS/88ZHnJyHT5JunKw1otsHYmEa0Uqc1WYhIkQw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-dialog/-/vaadin-dialog-2.3.0.tgz", + "integrity": "sha512-Pbd65c4JOYps0Xa+ZpXnqQ8F3zlrCF0EJ2xG/IQEwQEJ5/K2TmNFkJyeDvquCiRM/GWl0c3YVK955WTvGU4QOQ==", "requires": { + "@polymer/iron-resizable-behavior": "^3.0.0", "@polymer/polymer": "^3.0.0", "@vaadin/vaadin-element-mixin": "^2.0.0", "@vaadin/vaadin-lumo-styles": "^1.1.0", "@vaadin/vaadin-material-styles": "^1.1.0", - "@vaadin/vaadin-overlay": "^3.2.0", + "@vaadin/vaadin-overlay": "^3.3.0", "@vaadin/vaadin-themable-mixin": "^1.3.2" } }, "@vaadin/vaadin-element-mixin": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-element-mixin/-/vaadin-element-mixin-2.4.0.tgz", - "integrity": "sha512-5iTKcoW++uPKDZId0g1r9tlr5dC1KPCEYqWBtbne+AvUnEzpcnZRQ2bZTK4Nv49GiAAhlfe5pmNIibGaQKRpZQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-element-mixin/-/vaadin-element-mixin-2.4.1.tgz", + "integrity": "sha512-Ie7fwcOmg1C71UFuRwcuo2GKS+HbKvLedfs3hGdICiuwJ56cQvQsbIlxa4utKWWCVlf6yuSvMrny8efPPenfTA==", "requires": { "@polymer/polymer": "^3.0.0", "@vaadin/vaadin-development-mode-detector": "^2.0.0", @@ -2155,9 +2506,9 @@ } }, "@vaadin/vaadin-grid": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-grid/-/vaadin-grid-5.5.2.tgz", - "integrity": "sha512-0wMc60baLoyLgjmrvrBLIDamLC3ANSeWFbdZV77dATyC12xo3WFgd97tPWerPKf/9b4EIwWVjRowq2rz+9beNg==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-grid/-/vaadin-grid-5.5.3.tgz", + "integrity": "sha512-/VRJw+ReWrPT/mzx2cgV2/g/4qbB7fzHfT4SWvfVhYX2M4Pi2JrZEPfHWRzexif4iaRJ6v0i+00BuLcmoCdgiA==", "requires": { "@polymer/iron-a11y-announcer": "^3.0.0", "@polymer/iron-a11y-keys-behavior": "^3.0.0", @@ -2235,11 +2586,12 @@ } }, "@vaadin/vaadin-list-mixin": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-list-mixin/-/vaadin-list-mixin-2.3.1.tgz", - "integrity": "sha512-b6VIzGfmUKcynlZ1OBvryzv9/5WFmaE1gGbNCnvB4bv6Vqvh5ZOI8eBAAKYZ3DgnB2hq1cTh5+0pYQvfuh81fw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-list-mixin/-/vaadin-list-mixin-2.5.0.tgz", + "integrity": "sha512-NyQMJZ4sQ35gQxCOdoeBbGW2ou+MfqZRc9DSWotVgJheusRCV7wMHqUmKU/KyFa/IQ8ZoxWbVPdap8I9hyMKfA==", "requires": { - "@polymer/polymer": "^3.0.0" + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.4.1" } }, "@vaadin/vaadin-login": { @@ -2276,14 +2628,14 @@ } }, "@vaadin/vaadin-menu-bar": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-menu-bar/-/vaadin-menu-bar-1.0.3.tgz", - "integrity": "sha512-VsCt5yqNWzSc3bzrwK8CZHMdArsTQNvoR+4oYDLr1+DvBSnRYuDD6dQiuhxjCNcx9qtcmuH6eTXTFfczD/jFqw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-menu-bar/-/vaadin-menu-bar-1.0.5.tgz", + "integrity": "sha512-KCGskX1dfF+Wu8HuXpJtF08BGY9aDB4lVx9rDh32tUOBUZkuQfff+6y3qpLt0gfV+bSrdsW5OHGIOu6K1tKeWA==", "requires": { "@polymer/iron-resizable-behavior": "^3.0.0", "@polymer/polymer": "^3.0.0", "@vaadin/vaadin-button": "^2.1.4", - "@vaadin/vaadin-context-menu": "^4.3.8", + "@vaadin/vaadin-context-menu": "^4.3.12", "@vaadin/vaadin-element-mixin": "^2.0.0", "@vaadin/vaadin-lumo-styles": "^1.4.1", "@vaadin/vaadin-material-styles": "^1.2.2", @@ -2303,9 +2655,9 @@ } }, "@vaadin/vaadin-ordered-layout": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-ordered-layout/-/vaadin-ordered-layout-1.1.0.tgz", - "integrity": "sha512-ln3dXms/JmKCYu4sTc/xANxF13V8S6A1f/0xKvohYOEU5fRvq7suc8SR7GesyfXouF40kbFJ49sqTquK9TP95A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-ordered-layout/-/vaadin-ordered-layout-1.2.0.tgz", + "integrity": "sha512-srumEsOO599PmVX1L5oszNEz7sRHAhwn6LIDOFD+i9niGkFCq7Eijj2sGJ4KPWPA38XlzD2lo/zsM1wegf9o2Q==", "requires": { "@polymer/polymer": "^3.0.0", "@vaadin/vaadin-element-mixin": "^2.0.0", @@ -2315,15 +2667,15 @@ } }, "@vaadin/vaadin-overlay": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-overlay/-/vaadin-overlay-3.4.0.tgz", - "integrity": "sha512-796BtX3irl3HzEqXmvBzfUb5/WljD7x8hRnH+9OAW8jWAXg+mtPnxZEyGyhJF0s9D55Uliwj1ErkR4EHZ97How==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-overlay/-/vaadin-overlay-3.5.0.tgz", + "integrity": "sha512-w5Q4eTcbMictY1+FxeZk107Jf/dqSKwcC5QQ2osIGHixTC8ZyNsglKH0JeX4bBMKgNgby02GmxRCj4TPWz/D3Q==", "requires": { "@polymer/polymer": "^3.0.0", - "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-element-mixin": "^2.4.0", "@vaadin/vaadin-lumo-styles": "^1.3.0", "@vaadin/vaadin-material-styles": "^1.2.0", - "@vaadin/vaadin-themable-mixin": "^1.2.1" + "@vaadin/vaadin-themable-mixin": "^1.6.1" } }, "@vaadin/vaadin-progress-bar": { @@ -2388,9 +2740,9 @@ } }, "@vaadin/vaadin-shrinkwrap": { - "version": "14.1.25", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-shrinkwrap/-/vaadin-shrinkwrap-14.1.25.tgz", - "integrity": "sha512-74XRJnOyXGEfb6TOpyMxNjXquj/eoZjlAJh7kx7v7mk6FZISN4k6BdbbBV5MhPrqja3mP0KtE2qLjNG6wWiYBg==", + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-shrinkwrap/-/vaadin-shrinkwrap-14.2.0.tgz", + "integrity": "sha512-RMMa8HEOUOWokHWYiHEtNW8nRoOyLM/Efok40WDpIq6viatDwxWKoTZsj+O0ziSXd/2TcQwfQdFULP3uNLp3Fg==", "requires": { "@polymer/iron-a11y-announcer": "^3.0.2", "@polymer/iron-a11y-keys-behavior": "^3.0.1", @@ -2418,12 +2770,13 @@ "@vaadin/vaadin-crud": "^1.1.0", "@vaadin/vaadin-custom-field": "^1.0.11", "@vaadin/vaadin-date-picker": "^4.0.8", + "@vaadin/vaadin-date-time-picker": "^1.0.0", "@vaadin/vaadin-details": "^1.0.1", "@vaadin/vaadin-development-mode-detector": "^2.0.4", - "@vaadin/vaadin-dialog": "^2.2.1", + "@vaadin/vaadin-dialog": "^2.3.0", "@vaadin/vaadin-element-mixin": "^2.2.0", "@vaadin/vaadin-form-layout": "^2.1.7", - "@vaadin/vaadin-grid": "^5.5.2", + "@vaadin/vaadin-grid": "^5.5.3", "@vaadin/vaadin-grid-pro": "^2.0.7", "@vaadin/vaadin-icons": "^4.3.1", "@vaadin/vaadin-item": "^2.1.1", @@ -2432,10 +2785,10 @@ "@vaadin/vaadin-login": "^1.0.1", "@vaadin/vaadin-lumo-styles": "^1.5.0", "@vaadin/vaadin-material-styles": "^1.2.3", - "@vaadin/vaadin-menu-bar": "^1.0.3", + "@vaadin/vaadin-menu-bar": "^1.0.5", "@vaadin/vaadin-notification": "^1.4.0", - "@vaadin/vaadin-ordered-layout": "^1.1.0", - "@vaadin/vaadin-overlay": "^3.2.19", + "@vaadin/vaadin-ordered-layout": "^1.2.0", + "@vaadin/vaadin-overlay": "^3.3.1", "@vaadin/vaadin-progress-bar": "^1.1.2", "@vaadin/vaadin-radio-button": "^1.2.6", "@vaadin/vaadin-rich-text-editor": "^1.1.1", @@ -2672,6 +3025,21 @@ "@vaadin/vaadin-material-styles": "^1.1.0", "@vaadin/vaadin-overlay": "^3.2.0", "@vaadin/vaadin-themable-mixin": "^1.4.0" + }, + "dependencies": { + "@vaadin/vaadin-dialog": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-dialog/-/vaadin-dialog-2.2.1.tgz", + "integrity": "sha512-OPaXsCdVYWm8wR0c/kJ822SnjHwSi69kpp2zywB9SwvxauHnS/88ZHnJyHT5JunKw1otsHYmEa0Uqc1WYhIkQw==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.0.0", + "@vaadin/vaadin-lumo-styles": "^1.1.0", + "@vaadin/vaadin-material-styles": "^1.1.0", + "@vaadin/vaadin-overlay": "^3.2.0", + "@vaadin/vaadin-themable-mixin": "^1.3.2" + } + } } }, "@vaadin/vaadin-context-menu": { @@ -2730,6 +3098,21 @@ "@vaadin/vaadin-material-styles": "^1.2.3", "@vaadin/vaadin-text-field": "^2.3.0", "@vaadin/vaadin-themable-mixin": "^1.4.4" + }, + "dependencies": { + "@vaadin/vaadin-dialog": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-dialog/-/vaadin-dialog-2.2.1.tgz", + "integrity": "sha512-OPaXsCdVYWm8wR0c/kJ822SnjHwSi69kpp2zywB9SwvxauHnS/88ZHnJyHT5JunKw1otsHYmEa0Uqc1WYhIkQw==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.0.0", + "@vaadin/vaadin-lumo-styles": "^1.1.0", + "@vaadin/vaadin-material-styles": "^1.1.0", + "@vaadin/vaadin-overlay": "^3.2.0", + "@vaadin/vaadin-themable-mixin": "^1.3.2" + } + } } }, "@vaadin/vaadin-custom-field": { @@ -2764,6 +3147,157 @@ "@vaadin/vaadin-themable-mixin": "^1.3.2" } }, + "@vaadin/vaadin-date-time-picker": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-date-time-picker/-/vaadin-date-time-picker-1.1.0.tgz", + "integrity": "sha512-uCTIOouRlaNdXV9vUrFI4Dckv1w6i1YJdtI+n2qT4Irh32mFwdTNljJZQW3MnFoBDY4eGtMRNbrc/FK6LHj4rw==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-custom-field": "^1.1.0", + "@vaadin/vaadin-date-picker": "^4.1.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-themable-mixin": "^1.3.2", + "@vaadin/vaadin-time-picker": "^2.1.0" + }, + "dependencies": { + "@vaadin/vaadin-button": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-button/-/vaadin-button-2.3.0.tgz", + "integrity": "sha512-FnKvsxwBQhXWV/kW+PNY+vFF+V6cQE6IiSH32LZ6rlZ+aqsvpRLEF4yNr3sg39yBsdWfeU1J+44Ne4chPbcizA==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.0.0", + "@vaadin/vaadin-lumo-styles": "^1.3.3", + "@vaadin/vaadin-material-styles": "^1.2.0", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + }, + "@vaadin/vaadin-combo-box": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-combo-box/-/vaadin-combo-box-5.1.0.tgz", + "integrity": "sha512-7EBfTP+oAt7m1Hx1JffcNix95IJbM4weOg9LOQWrD2+Ei+NePcJIl1v3nHzErIPhdh/M+LkFcRo7dV5HT/A6Lw==", + "requires": { + "@polymer/iron-a11y-announcer": "^3.0.0", + "@polymer/iron-a11y-keys-behavior": "^3.0.0", + "@polymer/iron-list": "^3.0.0", + "@polymer/iron-resizable-behavior": "^3.0.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-item": "^2.2.0-alpha1", + "@vaadin/vaadin-lumo-styles": "^1.1.1", + "@vaadin/vaadin-material-styles": "^1.1.2", + "@vaadin/vaadin-overlay": "^3.4.0", + "@vaadin/vaadin-text-field": "^2.6.0", + "@vaadin/vaadin-themable-mixin": "^1.5.2" + } + }, + "@vaadin/vaadin-custom-field": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-custom-field/-/vaadin-custom-field-1.1.0.tgz", + "integrity": "sha512-fPaIJFjYO6UO4HMUA2Ps3GRPE1/gNPLvGSwy7x9L1vGk6iPW5PX0GObj+LE14PIzvJGW/9UcbaSSPhFrK6FL1g==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-themable-mixin": "^1.5.2" + } + }, + "@vaadin/vaadin-date-picker": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-date-picker/-/vaadin-date-picker-4.1.1.tgz", + "integrity": "sha512-L+Wq4BrTeVNwsJRf+QH8OUBsBS9fTekHznmFlqv6ux4vuAmGqTbtHnM0QGy7Ijx1TvfFLOLaxa8yAMW9xmlhsA==", + "requires": { + "@polymer/iron-a11y-announcer": "^3.0.0", + "@polymer/iron-a11y-keys-behavior": "^3.0.0", + "@polymer/iron-media-query": "^3.0.0", + "@polymer/iron-resizable-behavior": "^3.0.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-button": "^2.3.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.3.1", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-overlay": "^3.4.0", + "@vaadin/vaadin-text-field": "^2.6.0", + "@vaadin/vaadin-themable-mixin": "^1.5.2" + } + }, + "@vaadin/vaadin-element-mixin": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-element-mixin/-/vaadin-element-mixin-2.4.1.tgz", + "integrity": "sha512-Ie7fwcOmg1C71UFuRwcuo2GKS+HbKvLedfs3hGdICiuwJ56cQvQsbIlxa4utKWWCVlf6yuSvMrny8efPPenfTA==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-development-mode-detector": "^2.0.0", + "@vaadin/vaadin-usage-statistics": "^2.1.0" + } + }, + "@vaadin/vaadin-item": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-item/-/vaadin-item-2.2.0.tgz", + "integrity": "sha512-Yvpd2fiTwvfJA18lfjYsj33L+yr/YfHg3WZNp+v8OghfacfMdD5JofJpK6s0cJIuNTg+TC6hG1UwzcEC9jNMFw==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.1.0", + "@vaadin/vaadin-material-styles": "^1.1.0", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + }, + "@vaadin/vaadin-lumo-styles": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-lumo-styles/-/vaadin-lumo-styles-1.6.0.tgz", + "integrity": "sha512-MTJ2JssEVF3Go5b+zIe86Jw8nNtaN91wHmO2Ic1eI27PEJ5dRRGcLWX9CjTEx/8Zu9+3Fk4YeVP9ABWhiZZGUw==", + "requires": { + "@polymer/iron-icon": "^3.0.0", + "@polymer/iron-iconset-svg": "^3.0.0", + "@polymer/polymer": "^3.0.0" + } + }, + "@vaadin/vaadin-material-styles": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-material-styles/-/vaadin-material-styles-1.3.2.tgz", + "integrity": "sha512-EFrvGScoxhLNrPnWtT2Ia77whjF2TD4jrcyeh1jv9joCA2n5SUba+4XJciVSGmopqqQato6lwRnZSvMLJX7cyw==", + "requires": { + "@polymer/polymer": "^3.0.0" + } + }, + "@vaadin/vaadin-text-field": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-text-field/-/vaadin-text-field-2.6.0.tgz", + "integrity": "sha512-ErwPR67Fq1Zw9VWdj1ZHPk5JuNR0n+lMQk2wH7JmH1xibzXC20t2qkgaJUDnT5YpJ4Ap+7ZypUxBKWcbDu9D3A==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + }, + "@vaadin/vaadin-time-picker": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-time-picker/-/vaadin-time-picker-2.1.0.tgz", + "integrity": "sha512-t27xrcOr2fq7OKViMatLpw6ICVoDeZJkeH2wZtghNIbpVEiTM/tEwmmVjP2tWjON44Xt6siCIM3K/bHGYgzlIA==", + "requires": { + "@polymer/iron-a11y-keys-behavior": "^3.0.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-combo-box": "^5.1.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-text-field": "^2.6.0", + "@vaadin/vaadin-themable-mixin": "^1.3.2" + } + } + } + }, "@vaadin/vaadin-details": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@vaadin/vaadin-details/-/vaadin-details-1.0.1.tgz", @@ -2783,15 +3317,16 @@ "integrity": "sha512-S+PaFrZpK8uBIOnIHxjntTrgumd5ztuCnZww96ydGKXgo9whXfZsbMwDuD/102a/IuPUMyF+dh/n3PbWzJ6igA==" }, "@vaadin/vaadin-dialog": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-dialog/-/vaadin-dialog-2.2.1.tgz", - "integrity": "sha512-OPaXsCdVYWm8wR0c/kJ822SnjHwSi69kpp2zywB9SwvxauHnS/88ZHnJyHT5JunKw1otsHYmEa0Uqc1WYhIkQw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-dialog/-/vaadin-dialog-2.3.0.tgz", + "integrity": "sha512-Pbd65c4JOYps0Xa+ZpXnqQ8F3zlrCF0EJ2xG/IQEwQEJ5/K2TmNFkJyeDvquCiRM/GWl0c3YVK955WTvGU4QOQ==", "requires": { + "@polymer/iron-resizable-behavior": "^3.0.0", "@polymer/polymer": "^3.0.0", "@vaadin/vaadin-element-mixin": "^2.0.0", "@vaadin/vaadin-lumo-styles": "^1.1.0", "@vaadin/vaadin-material-styles": "^1.1.0", - "@vaadin/vaadin-overlay": "^3.2.0", + "@vaadin/vaadin-overlay": "^3.3.0", "@vaadin/vaadin-themable-mixin": "^1.3.2" } }, @@ -2819,21 +3354,77 @@ } }, "@vaadin/vaadin-grid": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-grid/-/vaadin-grid-5.5.2.tgz", - "integrity": "sha512-0wMc60baLoyLgjmrvrBLIDamLC3ANSeWFbdZV77dATyC12xo3WFgd97tPWerPKf/9b4EIwWVjRowq2rz+9beNg==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-grid/-/vaadin-grid-5.6.1.tgz", + "integrity": "sha512-tn7TbBMIsED1vKIJS8jn6Wb17zh2xS5R6pXrlENJc2RT0eMbWpqAjmZryNdOvXZf44JKcfH0omENTlCkQjbXxQ==", "requires": { "@polymer/iron-a11y-announcer": "^3.0.0", "@polymer/iron-a11y-keys-behavior": "^3.0.0", "@polymer/iron-resizable-behavior": "^3.0.0", "@polymer/iron-scroll-target-behavior": "^3.0.0", "@polymer/polymer": "^3.0.0", - "@vaadin/vaadin-checkbox": "^2.2.1", - "@vaadin/vaadin-element-mixin": "^2.1.1", - "@vaadin/vaadin-lumo-styles": "^1.1.1", - "@vaadin/vaadin-material-styles": "^1.1.1", - "@vaadin/vaadin-text-field": "^2.1.1", - "@vaadin/vaadin-themable-mixin": "^1.2.1" + "@vaadin/vaadin-checkbox": "^2.3.0", + "@vaadin/vaadin-element-mixin": "^2.3.2", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-text-field": "^2.6.0", + "@vaadin/vaadin-themable-mixin": "^1.5.2" + }, + "dependencies": { + "@vaadin/vaadin-checkbox": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-checkbox/-/vaadin-checkbox-2.3.0.tgz", + "integrity": "sha512-f3yyBBTj58gZDudYh8nGn2ZNOrubg2e05mp7d7roI7xEVcfwT/Y4a/D9bHeBcOgI8LvwN8fToxIIFBt5b8UA6g==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.4.1", + "@vaadin/vaadin-material-styles": "^1.2.0", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + }, + "@vaadin/vaadin-element-mixin": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-element-mixin/-/vaadin-element-mixin-2.4.1.tgz", + "integrity": "sha512-Ie7fwcOmg1C71UFuRwcuo2GKS+HbKvLedfs3hGdICiuwJ56cQvQsbIlxa4utKWWCVlf6yuSvMrny8efPPenfTA==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-development-mode-detector": "^2.0.0", + "@vaadin/vaadin-usage-statistics": "^2.1.0" + } + }, + "@vaadin/vaadin-lumo-styles": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-lumo-styles/-/vaadin-lumo-styles-1.6.0.tgz", + "integrity": "sha512-MTJ2JssEVF3Go5b+zIe86Jw8nNtaN91wHmO2Ic1eI27PEJ5dRRGcLWX9CjTEx/8Zu9+3Fk4YeVP9ABWhiZZGUw==", + "requires": { + "@polymer/iron-icon": "^3.0.0", + "@polymer/iron-iconset-svg": "^3.0.0", + "@polymer/polymer": "^3.0.0" + } + }, + "@vaadin/vaadin-material-styles": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-material-styles/-/vaadin-material-styles-1.3.2.tgz", + "integrity": "sha512-EFrvGScoxhLNrPnWtT2Ia77whjF2TD4jrcyeh1jv9joCA2n5SUba+4XJciVSGmopqqQato6lwRnZSvMLJX7cyw==", + "requires": { + "@polymer/polymer": "^3.0.0" + } + }, + "@vaadin/vaadin-text-field": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-text-field/-/vaadin-text-field-2.6.0.tgz", + "integrity": "sha512-ErwPR67Fq1Zw9VWdj1ZHPk5JuNR0n+lMQk2wH7JmH1xibzXC20t2qkgaJUDnT5YpJ4Ap+7ZypUxBKWcbDu9D3A==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + } } }, "@vaadin/vaadin-grid-pro": { @@ -2940,18 +3531,112 @@ } }, "@vaadin/vaadin-menu-bar": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-menu-bar/-/vaadin-menu-bar-1.0.3.tgz", - "integrity": "sha512-VsCt5yqNWzSc3bzrwK8CZHMdArsTQNvoR+4oYDLr1+DvBSnRYuDD6dQiuhxjCNcx9qtcmuH6eTXTFfczD/jFqw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-menu-bar/-/vaadin-menu-bar-1.1.0.tgz", + "integrity": "sha512-4CgN12YJdYDsqENa73JaxSw+5hKAeM54b80HYBe5QVa0skIt1pSJZnUhGZ9Gkw/cW2xjtnwXI2lYcOglyUt4WA==", "requires": { "@polymer/iron-resizable-behavior": "^3.0.0", "@polymer/polymer": "^3.0.0", - "@vaadin/vaadin-button": "^2.1.4", - "@vaadin/vaadin-context-menu": "^4.3.8", - "@vaadin/vaadin-element-mixin": "^2.0.0", - "@vaadin/vaadin-lumo-styles": "^1.4.1", - "@vaadin/vaadin-material-styles": "^1.2.2", - "@vaadin/vaadin-themable-mixin": "^1.2.0" + "@vaadin/vaadin-button": "^2.3.0", + "@vaadin/vaadin-context-menu": "^4.4.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-themable-mixin": "^1.5.0" + }, + "dependencies": { + "@vaadin/vaadin-button": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-button/-/vaadin-button-2.3.0.tgz", + "integrity": "sha512-FnKvsxwBQhXWV/kW+PNY+vFF+V6cQE6IiSH32LZ6rlZ+aqsvpRLEF4yNr3sg39yBsdWfeU1J+44Ne4chPbcizA==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-control-state-mixin": "^2.1.1", + "@vaadin/vaadin-element-mixin": "^2.0.0", + "@vaadin/vaadin-lumo-styles": "^1.3.3", + "@vaadin/vaadin-material-styles": "^1.2.0", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + }, + "@vaadin/vaadin-context-menu": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-context-menu/-/vaadin-context-menu-4.4.0.tgz", + "integrity": "sha512-q6S7UkNkuf5/dEDoV4UHq79j0+R9I79znDqO6gVk4cPv7Iy4cl79AnJHGqS4ippuVv4P7/3VUDz+SGNbXDk36A==", + "requires": { + "@polymer/iron-media-query": "^3.0.0", + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.3.1", + "@vaadin/vaadin-item": "^2.2.0", + "@vaadin/vaadin-list-box": "^1.3.0", + "@vaadin/vaadin-lumo-styles": "^1.6.0", + "@vaadin/vaadin-material-styles": "^1.3.2", + "@vaadin/vaadin-overlay": "^3.4.0", + "@vaadin/vaadin-themable-mixin": "^1.5.2" + } + }, + "@vaadin/vaadin-element-mixin": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-element-mixin/-/vaadin-element-mixin-2.4.1.tgz", + "integrity": "sha512-Ie7fwcOmg1C71UFuRwcuo2GKS+HbKvLedfs3hGdICiuwJ56cQvQsbIlxa4utKWWCVlf6yuSvMrny8efPPenfTA==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-development-mode-detector": "^2.0.0", + "@vaadin/vaadin-usage-statistics": "^2.1.0" + } + }, + "@vaadin/vaadin-item": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-item/-/vaadin-item-2.2.0.tgz", + "integrity": "sha512-Yvpd2fiTwvfJA18lfjYsj33L+yr/YfHg3WZNp+v8OghfacfMdD5JofJpK6s0cJIuNTg+TC6hG1UwzcEC9jNMFw==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-lumo-styles": "^1.1.0", + "@vaadin/vaadin-material-styles": "^1.1.0", + "@vaadin/vaadin-themable-mixin": "^1.2.1" + } + }, + "@vaadin/vaadin-list-box": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-list-box/-/vaadin-list-box-1.3.0.tgz", + "integrity": "sha512-SETW+VwFa31STfKog7Fb9uN42KvbCpFoEoD1UhJaQLzgOPq/DdYhNKzFeuMZcbsLGx8BBL9ycoqKIDZCTk1y1w==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", + "@vaadin/vaadin-item": "^2.2.0", + "@vaadin/vaadin-list-mixin": "^2.4.0", + "@vaadin/vaadin-lumo-styles": "^1.1.0", + "@vaadin/vaadin-material-styles": "^1.1.0", + "@vaadin/vaadin-themable-mixin": "^1.5.2" + } + }, + "@vaadin/vaadin-list-mixin": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-list-mixin/-/vaadin-list-mixin-2.5.0.tgz", + "integrity": "sha512-NyQMJZ4sQ35gQxCOdoeBbGW2ou+MfqZRc9DSWotVgJheusRCV7wMHqUmKU/KyFa/IQ8ZoxWbVPdap8I9hyMKfA==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.4.1" + } + }, + "@vaadin/vaadin-lumo-styles": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-lumo-styles/-/vaadin-lumo-styles-1.6.0.tgz", + "integrity": "sha512-MTJ2JssEVF3Go5b+zIe86Jw8nNtaN91wHmO2Ic1eI27PEJ5dRRGcLWX9CjTEx/8Zu9+3Fk4YeVP9ABWhiZZGUw==", + "requires": { + "@polymer/iron-icon": "^3.0.0", + "@polymer/iron-iconset-svg": "^3.0.0", + "@polymer/polymer": "^3.0.0" + } + }, + "@vaadin/vaadin-material-styles": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-material-styles/-/vaadin-material-styles-1.3.2.tgz", + "integrity": "sha512-EFrvGScoxhLNrPnWtT2Ia77whjF2TD4jrcyeh1jv9joCA2n5SUba+4XJciVSGmopqqQato6lwRnZSvMLJX7cyw==", + "requires": { + "@polymer/polymer": "^3.0.0" + } + } } }, "@vaadin/vaadin-notification": { @@ -2967,9 +3652,9 @@ } }, "@vaadin/vaadin-ordered-layout": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-ordered-layout/-/vaadin-ordered-layout-1.1.0.tgz", - "integrity": "sha512-ln3dXms/JmKCYu4sTc/xANxF13V8S6A1f/0xKvohYOEU5fRvq7suc8SR7GesyfXouF40kbFJ49sqTquK9TP95A==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-ordered-layout/-/vaadin-ordered-layout-1.2.0.tgz", + "integrity": "sha512-srumEsOO599PmVX1L5oszNEz7sRHAhwn6LIDOFD+i9niGkFCq7Eijj2sGJ4KPWPA38XlzD2lo/zsM1wegf9o2Q==", "requires": { "@polymer/polymer": "^3.0.0", "@vaadin/vaadin-element-mixin": "^2.0.0", @@ -2979,14 +3664,27 @@ } }, "@vaadin/vaadin-overlay": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@vaadin/vaadin-overlay/-/vaadin-overlay-3.3.1.tgz", - "integrity": "sha512-O/ROYmShZoNFtHPxp/kNLQZy5r0wExg+m2G4AuHVDbw76EZaOpLGdxD6e/PoBT3f7+XxLb3X+LfZqBdew5iZvA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-overlay/-/vaadin-overlay-3.4.0.tgz", + "integrity": "sha512-796BtX3irl3HzEqXmvBzfUb5/WljD7x8hRnH+9OAW8jWAXg+mtPnxZEyGyhJF0s9D55Uliwj1ErkR4EHZ97How==", "requires": { "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-element-mixin": "^2.3.0", "@vaadin/vaadin-lumo-styles": "^1.3.0", "@vaadin/vaadin-material-styles": "^1.2.0", "@vaadin/vaadin-themable-mixin": "^1.2.1" + }, + "dependencies": { + "@vaadin/vaadin-element-mixin": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vaadin/vaadin-element-mixin/-/vaadin-element-mixin-2.3.0.tgz", + "integrity": "sha512-9gQb6Y3c/KlkJkITr+JncBZQ3iAjLpU/B6Ykeis+AHjPn6p+f4x3xsJ09IJKtb5YqD5wy9Zu7ANdM++97abQ2g==", + "requires": { + "@polymer/polymer": "^3.0.0", + "@vaadin/vaadin-development-mode-detector": "^2.0.0", + "@vaadin/vaadin-usage-statistics": "^2.1.0" + } + } } }, "@vaadin/vaadin-progress-bar": { @@ -3532,24 +4230,14 @@ } }, "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", "dev": true, + "optional": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, "aproba": { @@ -3612,6 +4300,14 @@ "bn.js": "^4.0.0", "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } } }, "assert": { @@ -3848,20 +4544,11 @@ "dev": true }, "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", "dev": true, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } + "optional": true }, "bluebird": { "version": "3.7.2", @@ -3870,9 +4557,9 @@ "dev": true }, "bn.js": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==", "dev": true }, "body-parser": { @@ -4012,21 +4699,50 @@ "requires": { "bn.js": "^4.1.0", "randombytes": "^2.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } } }, "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "dev": true, - "requires": { - "bn.js": "^4.1.1", - "browserify-rsa": "^4.0.0", - "create-hash": "^1.1.0", - "create-hmac": "^1.1.2", - "elliptic": "^6.0.0", - "inherits": "^2.0.1", - "parse-asn1": "^5.0.0" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.0.tgz", + "integrity": "sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==", + "dev": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.2", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } } }, "browserify-zlib": { @@ -4152,9 +4868,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001046", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001046.tgz", - "integrity": "sha512-CsGjBRYWG6FvgbyGy+hBbaezpwiqIOLkxQPY4A4Ea49g1eNsnQuESB+n4QM0BKii1j80MyJ26Ir5ywTQkbRE4g==", + "version": "1.0.30001065", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001065.tgz", + "integrity": "sha512-DDxCLgJ266YnAHQv0jS1wdOaihRFF52Zgmlag39sQJVy2H46oROpJp4hITstqhdB8qnHSrKNoAEkQA9L/oYF9A==", "dev": true }, "chalk": { @@ -4169,23 +4885,69 @@ } }, "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz", + "integrity": "sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==", "dev": true, + "optional": true, "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.4.0" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "optional": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "optional": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "optional": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "optional": true, + "requires": { + "is-number": "^7.0.0" + } + } } }, "chownr": { @@ -4354,9 +5116,9 @@ } }, "compression-webpack-plugin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-3.0.1.tgz", - "integrity": "sha512-FOwoBVzDiwSdJDnZTKXDpAjJU90k8SbChgxnoiYwTo15xjIDJkSC8wFKuc13DymXjgasPEqzS5+2RUgSKXdKKA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-3.1.0.tgz", + "integrity": "sha512-iqTHj3rADN4yHwXMBrQa/xrncex/uEQy8QHlaTKxGchT/hC0SdlJlmL/5eRqffmWq2ep0/Romw6Ld39JjTR/ug==", "dev": true, "requires": { "cacache": "^13.0.1", @@ -4465,9 +5227,9 @@ "dev": true }, "copy-webpack-plugin": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.0.tgz", - "integrity": "sha512-0sNrj/Sx7/cWA0k7CVQa0sdA/dzCybqSb0+GbhKuQdOlAvnAwgC2osmbAFOAfha7ZXnreoQmCq5oDjG3gP4VHw==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz", + "integrity": "sha512-P15M5ZC8dyCjQHWwd4Ia/dm0SgVvZJMYeykVIVYXbGyqO4dWB5oyPHp9i7wjwo5LhtlhKbiBCdS2NvM07Wlybg==", "dev": true, "requires": { "cacache": "^12.0.3", @@ -4637,6 +5399,14 @@ "requires": { "bn.js": "^4.1.0", "elliptic": "^6.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } } }, "create-hash": { @@ -4914,6 +5684,14 @@ "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } } }, "dir-glob": { @@ -5033,9 +5811,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.3.415", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.415.tgz", - "integrity": "sha512-GbtYqKffx3sU8G0HxwXuJFfs58Q7+iwLa5rBwaULwET6jWW8IAQSrVnu7vEfiUIcMVfbYyFg7cw3zdm+EbBJmw==", + "version": "1.3.451", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.451.tgz", + "integrity": "sha512-2fvco0F2bBIgqzO8GRP0Jt/91pdrf9KfZ5FsmkYkjERmIJG585cFeFZV4+CO6oTmU3HmCTgfcZuEa7kW8VUh3A==", "dev": true }, "elliptic": { @@ -5051,6 +5829,14 @@ "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0", "minimalistic-crypto-utils": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } } }, "emoji-regex": { @@ -5104,9 +5890,9 @@ } }, "entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", - "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.2.tgz", + "integrity": "sha512-dmD3AvJQBUjKpcNkoqr+x+IF0SdRtPz9Vk0uTy4yWqga9ibB6s4v++QFWNohjiUGoMlF552ZvNyXDxz5iW0qmw==", "dev": true, "optional": true }, @@ -5199,9 +5985,9 @@ "dev": true }, "eventemitter3": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", - "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", "dev": true }, "events": { @@ -5447,13 +6233,6 @@ "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", "dev": true }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -5525,663 +6304,119 @@ "resolve-dir": "^1.0.1" } }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "follow-redirects": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz", - "integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==", - "dev": true, - "requires": { - "debug": "^3.0.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "fs-readdir-recursive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", - "dev": true - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.12.tgz", - "integrity": "sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q==", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1", - "node-pre-gyp": "*" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "3.2.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.6.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.9.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.3.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.9.0" - } - }, - "mkdirp": { - "version": "0.5.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.14.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4.4.2" - } - }, - "nopt": { - "version": "4.0.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "readable-stream": { - "version": "2.3.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.7.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.1", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.13", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "follow-redirects": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz", + "integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==", + "dev": true, + "requires": { + "debug": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, - "optional": true, "requires": { - "string-width": "^1.0.2 || 2" + "ms": "^2.1.1" } }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "optional": true + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true } } }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -6314,9 +6549,9 @@ } }, "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", "dev": true }, "handle-thing": { @@ -6379,13 +6614,33 @@ } }, "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "dev": true, "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } } }, "hash.js": { @@ -6589,15 +6844,15 @@ } }, "http-parser-js": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", - "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.2.tgz", + "integrity": "sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ==", "dev": true }, "http-proxy": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz", - "integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "requires": { "eventemitter3": "^4.0.0", @@ -6827,12 +7082,13 @@ "dev": true }, "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "optional": true, "requires": { - "binary-extensions": "^1.0.0" + "binary-extensions": "^2.0.0" } }, "is-buffer": { @@ -7303,6 +7559,14 @@ "requires": { "bn.js": "^4.0.0", "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } } }, "mime": { @@ -7312,18 +7576,18 @@ "dev": true }, "mime-db": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", - "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", "dev": true }, "mime-types": { - "version": "2.1.26", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", - "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", "dev": true, "requires": { - "mime-db": "1.43.0" + "mime-db": "1.44.0" } }, "mimic-fn": { @@ -7360,9 +7624,9 @@ "dev": true }, "minipass": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.1.tgz", - "integrity": "sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", "dev": true, "requires": { "yallist": "^4.0.0" @@ -7387,9 +7651,9 @@ } }, "minipass-pipeline": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.2.tgz", - "integrity": "sha512-3JS5A2DKhD2g0Gg8x3yamO0pj7YeKGwVlDS90pF++kxptwx/F+B//roxf9SqYil5tQo65bijy+dAuAFZmYOouA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.3.tgz", + "integrity": "sha512-cFOknTvng5vqnwOpDsZTWhNll6Jf8o2x+/diplafmxpuIymAjzoOolZG0VvQf3V2HgqzJNhnuKHYp2BqDgz8IQ==", "dev": true, "requires": { "minipass": "^3.0.0" @@ -7479,13 +7743,6 @@ "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", "dev": true }, - "nan": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", - "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", - "dev": true, - "optional": true - }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -7579,9 +7836,9 @@ } }, "node-releases": { - "version": "1.1.53", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.53.tgz", - "integrity": "sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ==", + "version": "1.1.56", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.56.tgz", + "integrity": "sha512-EVo605FhWLygH8a64TjgpjyHYOihkxECwX1bHHr8tETJKWEiWS2YJjPbvsX2jFjnjTNEgBCmk9mLjKG1Mf11cw==", "dev": true }, "normalize-path": { @@ -7977,6 +8234,13 @@ "sha.js": "^2.4.8" } }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "optional": true + }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -8068,9 +8332,9 @@ } }, "portfinder": { - "version": "1.0.25", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz", - "integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==", + "version": "1.0.26", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.26.tgz", + "integrity": "sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ==", "dev": true, "requires": { "async": "^2.6.2", @@ -8164,6 +8428,14 @@ "parse-asn1": "^5.0.0", "randombytes": "^2.0.1", "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + } } }, "pump": { @@ -8275,26 +8547,13 @@ } }, "raw-loader": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-3.0.0.tgz", - "integrity": "sha512-FsELYliOpX5HdPdxa7PzTmEc5OTchmLUs/r4f8oLDGCYE+xC2FjVbDXzdyLcBrdlDnvkx1x5wzphixcWpxJG5w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-3.1.0.tgz", + "integrity": "sha512-lzUVMuJ06HF4rYveaz9Tv0WRlUMxJ0Y1hgSkkgg+50iEdaI0TthyEDe08KIHb0XsF6rn8WYTqPCaGTZg3sX+qA==", "dev": true, "requires": { "loader-utils": "^1.1.0", - "schema-utils": "^1.0.0" - }, - "dependencies": { - "schema-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", - "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", - "dev": true, - "requires": { - "ajv": "^6.1.0", - "ajv-errors": "^1.0.0", - "ajv-keywords": "^3.1.0" - } - } + "schema-utils": "^2.0.1" } }, "readable-stream": { @@ -8313,14 +8572,13 @@ } }, "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", "dev": true, + "optional": true, "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "picomatch": "^2.2.1" } }, "regenerate": { @@ -8389,9 +8647,9 @@ } }, "regjsgen": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz", - "integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", "dev": true }, "regjsparser": { @@ -8968,9 +9226,9 @@ } }, "source-map-support": { - "version": "0.5.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.18.tgz", - "integrity": "sha512-9luZr/BZ2QeU6tO2uG8N2aZpVSli4TSAOAqFOyTO51AJcD9P99c0K1h6dD6r6qo5dyT44BR5exweOaLLeldTkQ==", + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -9485,9 +9743,9 @@ "optional": true }, "tslib": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", - "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", "dev": true }, "tty-browserify": { @@ -9770,14 +10028,107 @@ "dev": true }, "watchpack": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.1.tgz", - "integrity": "sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.2.tgz", + "integrity": "sha512-ymVbbQP40MFTp+cNMvpyBpBtygHnPzPkHqoIwRRj/0B8KhqQwV8LaKjtbaxF2lK4vl8zN9wCxS46IFCU5K4W0g==", "dev": true, "requires": { - "chokidar": "^2.1.8", + "chokidar": "^3.4.0", "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.0" + } + }, + "watchpack-chokidar2": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz", + "integrity": "sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==", + "dev": true, + "optional": true, + "requires": { + "chokidar": "^2.1.8" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "optional": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + } } }, "wbuf": { @@ -9854,9 +10205,9 @@ } }, "webpack-cli": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.10.tgz", - "integrity": "sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.11.tgz", + "integrity": "sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g==", "dev": true, "requires": { "chalk": "2.4.2", @@ -9925,17 +10276,17 @@ }, "dependencies": { "mime": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz", + "integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==", "dev": true } } }, "webpack-dev-server": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.9.0.tgz", - "integrity": "sha512-E6uQ4kRrTX9URN9s/lIbqTAztwEPdvzVrcmHE8EQ9YnuT9J8Es5Wrd8n9BKg1a0oZ5EgEke/EQFgUsp18dSTBw==", + "version": "3.10.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.10.3.tgz", + "integrity": "sha512-e4nWev8YzEVNdOMcNzNeCN947sWJNd43E5XvsJzbAL08kGc2frm1tQ32hTJslRS+H65LCb/AaUCYU7fjHCpDeQ==", "dev": true, "requires": { "ansi-html": "0.0.7", @@ -9953,7 +10304,7 @@ "ip": "^1.1.5", "is-absolute-url": "^3.0.3", "killable": "^1.0.1", - "loglevel": "^1.6.4", + "loglevel": "^1.6.6", "opn": "^5.5.0", "p-retry": "^3.0.1", "portfinder": "^1.0.25", @@ -9979,6 +10330,53 @@ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", @@ -10019,12 +10417,28 @@ "locate-path": "^3.0.0" } }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true + }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", @@ -10056,6 +10470,17 @@ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, "require-main-filename": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", @@ -10197,12 +10622,12 @@ } }, "websocket-driver": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", - "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, "requires": { - "http-parser-js": ">=0.4.0 <0.4.11", + "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } diff --git a/demo-v14/package.json b/demo-v14/package.json index be3da445..9f547401 100644 --- a/demo-v14/package.json +++ b/demo-v14/package.json @@ -4,18 +4,116 @@ "dependencies": { "@polymer/polymer": "3.2.0", "@webcomponents/webcomponentsjs": "^2.2.10", - "@vaadin/flow-deps": "./target/frontend" + "@vaadin/vaadin-crud": "1.1.0", + "@vaadin/vaadin-grid": "5.5.3", + "@vaadin/vaadin-icons": "4.3.1", + "@vaadin/vaadin-split-layout": "4.1.1", + "@vaadin/vaadin-combo-box": "5.0.11", + "@vaadin/vaadin-cookie-consent": "1.1.2", + "@vaadin/vaadin-core-shrinkwrap": "14.2.0", + "@vaadin/vaadin-upload": "4.2.2", + "@vaadin/vaadin-dialog": "2.3.0", + "@vaadin/vaadin-select": "2.1.7", + "@vaadin/vaadin-app-layout": "2.0.5", + "@vaadin/vaadin-item": "2.1.1", + "@vaadin/vaadin-board": "2.1.1", + "@vaadin/vaadin-charts": "6.2.4", + "@vaadin/vaadin-notification": "1.4.0", + "@vaadin/vaadin-grid-pro": "2.0.7", + "@vaadin/vaadin-progress-bar": "1.1.2", + "@vaadin/vaadin-shrinkwrap": "14.2.0", + "@vaadin/vaadin-date-time-picker": "1.0.0", + "@vaadin/vaadin-ordered-layout": "1.2.0", + "@vaadin/vaadin-login": "1.0.1", + "@vaadin/vaadin-button": "2.2.2", + "@vaadin/vaadin-date-picker": "4.0.8", + "@vaadin/vaadin-text-field": "2.5.5", + "@vaadin/vaadin-menu-bar": "1.0.5", + "@vaadin/vaadin-custom-field": "1.0.11", + "@vaadin/vaadin-form-layout": "2.1.7", + "@vaadin/vaadin-confirm-dialog": "1.1.6", + "@vaadin/vaadin-accordion": "1.0.1", + "@polymer/iron-list": "3.0.2", + "@vaadin/vaadin-list-box": "1.2.0", + "@vaadin/vaadin-details": "1.0.1", + "@vaadin/vaadin-checkbox": "2.2.13", + "@polymer/iron-icon": "3.0.1", + "@vaadin/vaadin-time-picker": "2.0.7", + "@vaadin/vaadin-context-menu": "4.3.15", + "@vaadin/vaadin-tabs": "3.0.5", + "@vaadin/vaadin-radio-button": "1.2.6", + "@vaadin/vaadin-lumo-styles": "1.5.0", + "@vaadin/vaadin-material-styles": "1.2.3", + "@vaadin/vaadin-rich-text-editor": "1.1.1" }, "devDependencies": { "webpack": "4.42.0", - "webpack-cli": "3.3.10", - "webpack-dev-server": "3.9.0", + "webpack-cli": "3.3.11", + "webpack-dev-server": "3.10.3", "webpack-babel-multi-target-plugin": "2.3.3", - "copy-webpack-plugin": "5.1.0", + "copy-webpack-plugin": "5.1.1", "webpack-merge": "4.2.2", - "raw-loader": "3.0.0", - "compression-webpack-plugin": "3.0.1", + "raw-loader": "3.1.0", + "compression-webpack-plugin": "3.1.0", "terser": "4.6.7" }, - "vaadinAppPackageHash": "a0a2b06c0da7d79ceb9d83fb4b4dccc967bf2ec12246aa0de4f053298fb7081e" + "vaadin": { + "dependencies": { + "@polymer/polymer": "3.2.0", + "@webcomponents/webcomponentsjs": "^2.2.10", + "@vaadin/vaadin-crud": "1.1.0", + "@vaadin/vaadin-grid": "5.5.3", + "@vaadin/vaadin-icons": "4.3.1", + "@vaadin/vaadin-split-layout": "4.1.1", + "@vaadin/vaadin-combo-box": "5.0.11", + "@vaadin/vaadin-cookie-consent": "1.1.2", + "@vaadin/vaadin-core-shrinkwrap": "14.2.0", + "@vaadin/vaadin-upload": "4.2.2", + "@vaadin/vaadin-dialog": "2.3.0", + "@vaadin/vaadin-select": "2.1.7", + "@vaadin/vaadin-app-layout": "2.0.5", + "@vaadin/vaadin-item": "2.1.1", + "@vaadin/vaadin-board": "2.1.1", + "@vaadin/vaadin-charts": "6.2.4", + "@vaadin/vaadin-notification": "1.4.0", + "@vaadin/vaadin-grid-pro": "2.0.7", + "@vaadin/vaadin-progress-bar": "1.1.2", + "@vaadin/vaadin-shrinkwrap": "14.2.0", + "@vaadin/vaadin-date-time-picker": "1.0.0", + "@vaadin/vaadin-ordered-layout": "1.2.0", + "@vaadin/vaadin-login": "1.0.1", + "@vaadin/vaadin-button": "2.2.2", + "@vaadin/vaadin-date-picker": "4.0.8", + "@vaadin/vaadin-text-field": "2.5.5", + "@vaadin/vaadin-menu-bar": "1.0.5", + "@vaadin/vaadin-custom-field": "1.0.11", + "@vaadin/vaadin-form-layout": "2.1.7", + "@vaadin/vaadin-confirm-dialog": "1.1.6", + "@vaadin/vaadin-accordion": "1.0.1", + "@polymer/iron-list": "3.0.2", + "@vaadin/vaadin-list-box": "1.2.0", + "@vaadin/vaadin-details": "1.0.1", + "@vaadin/vaadin-checkbox": "2.2.13", + "@polymer/iron-icon": "3.0.1", + "@vaadin/vaadin-time-picker": "2.0.7", + "@vaadin/vaadin-context-menu": "4.3.15", + "@vaadin/vaadin-tabs": "3.0.5", + "@vaadin/vaadin-radio-button": "1.2.6", + "@vaadin/vaadin-lumo-styles": "1.5.0", + "@vaadin/vaadin-material-styles": "1.2.3", + "@vaadin/vaadin-rich-text-editor": "1.1.1" + }, + "devDependencies": { + "webpack-babel-multi-target-plugin": "2.3.3", + "copy-webpack-plugin": "5.1.1", + "compression-webpack-plugin": "3.1.0", + "raw-loader": "3.1.0", + "webpack-cli": "3.3.11", + "webpack": "4.42.0", + "terser": "4.6.7", + "webpack-merge": "4.2.2", + "webpack-dev-server": "3.10.3" + }, + "hash": "ff6bf9595a64a06dbab813090ee759084167b12ba737d4b8d0a4e8305a6b4b05" + } } diff --git a/demo-v14/pom.xml b/demo-v14/pom.xml index 6a6a562e..1be97747 100644 --- a/demo-v14/pom.xml +++ b/demo-v14/pom.xml @@ -38,10 +38,6 @@ vaadin ${vaadin.version} - - com.vaadin - vaadin-date-time-picker-flow - com.vaadin.webjar diff --git a/demo-v14/webpack.generated.js b/demo-v14/webpack.generated.js index 7464df17..57ecd9ae 100644 --- a/demo-v14/webpack.generated.js +++ b/demo-v14/webpack.generated.js @@ -41,6 +41,8 @@ if (watchDogPort){ watchDogPort = watchDogPort.substr(watchDogPrefix.length); } +const transpile = !devMode || process.argv.find(v => v.indexOf('--transpile-es5') >= 0); + const net = require('net'); function setupWatchDog(){ @@ -94,13 +96,13 @@ module.exports = { contentBase: [mavenOutputFolderForFlowBundledFiles, 'src/main/webapp'], after: function(app, server) { app.get(`/stats.json`, function(req, res) { - res.json(stats.toJson()); + res.json(stats); }); app.get(`/stats.hash`, function(req, res) { - res.json(stats.toJson().hash.toString()); + res.json(stats.hash.toString()); }); app.get(`/assetsByChunkName`, function(req, res) { - res.json(stats.toJson().assetsByChunkName); + res.json(stats.assetsByChunkName); }); app.get(`/stop`, function(req, res) { // eslint-disable-next-line no-console @@ -112,10 +114,10 @@ module.exports = { module: { rules: [ - { // Files that Babel has to transpile + ...(transpile ? [{ // Files that Babel has to transpile test: /\.js$/, use: [BabelMultiTargetPlugin.loader()] - }, + }] : []), { test: /\.css$/i, use: ['raw-loader'] @@ -127,11 +129,11 @@ module.exports = { maxAssetSize: 2097152 // 2MB }, plugins: [ - // Generate compressed bundles - new CompressionPlugin(), + // Generate compressed bundles when not devMode + ...(devMode ? [] : [new CompressionPlugin()]), // Transpile with babel, and produce different bundles per browser - new BabelMultiTargetPlugin({ + ...(transpile ? [new BabelMultiTargetPlugin({ babel: { plugins: [ // workaround for Safari 10 scope issue (https://bugs.webkit.org/show_bug.cgi?id=159270) @@ -161,19 +163,38 @@ module.exports = { tagAssetsWithKey: true, // append a suffix to the file name } } - }), + })] : []), // Generates the stats file for flow `@Id` binding. function (compiler) { compiler.hooks.afterEmit.tapAsync("FlowIdPlugin", (compilation, done) => { + let statsJson = compilation.getStats().toJson(); + // Get bundles as accepted keys (except any es5 bundle) + let acceptedKeys = statsJson.assets.filter(asset => asset.chunks.length > 0 && !asset.chunkNames.toString().includes("es5")) + .map(asset => asset.chunks).reduce((acc, val) => acc.concat(val), []); + + // Collect all modules for the given keys + const modules = collectModules(statsJson, acceptedKeys); + + // Collect accepted chunks and their modules + const chunks = collectChunks(statsJson, acceptedKeys); + + let customStats = { + hash: statsJson.hash, + assetsByChunkName: statsJson.assetsByChunkName, + chunks: chunks, + modules: modules + }; + if (!devMode) { // eslint-disable-next-line no-console - console.log(" Emitted " + statsFile) - fs.writeFile(statsFile, JSON.stringify(compilation.getStats().toJson(), null, 1), done); + console.log(" Emitted " + statsFile); + fs.writeFile(statsFile, JSON.stringify(customStats, null, 1), done); } else { // eslint-disable-next-line no-console console.log(" Serving the 'stats.json' file dynamically."); - stats = compilation.getStats(); + + stats = customStats; done(); } }); @@ -187,3 +208,78 @@ module.exports = { }]), ] }; + +/** + * Collect chunk data for accepted chunk ids. + * @param statsJson full stats.json content + * @param acceptedKeys chunk ids that are accepted + * @returns slimmed down chunks + */ +function collectChunks(statsJson, acceptedChunks) { + const chunks = []; + // only handle chunks if they exist for stats + if (statsJson.chunks) { + statsJson.chunks.forEach(function (chunk) { + // Acc chunk if chunk id is in accepted chunks + if (acceptedChunks.includes(chunk.id)) { + const modules = []; + // Add all modules for chunk as slimmed down modules + chunk.modules.forEach(function (module) { + const slimModule = { + id: module.id, + name: module.name, + source: module.source, + }; + modules.push(slimModule); + }); + const slimChunk = { + id: chunk.id, + names: chunk.names, + files: chunk.files, + hash: chunk.hash, + modules: modules + } + chunks.push(slimChunk); + } + }); + } + return chunks; +} + +/** + * Collect all modules that are for a chunk in acceptedChunks. + * @param statsJson full stats.json + * @param acceptedChunks chunk names that are accepted for modules + * @returns slimmed down modules + */ +function collectModules(statsJson, acceptedChunks) { + let modules = []; + // skip if no modules defined + if (statsJson.modules) { + statsJson.modules.forEach(function (module) { + // Add module if module chunks contain an accepted chunk and the module is generated-flow-imports.js module + if (module.chunks.filter(key => acceptedChunks.includes(key)).length > 0 + && (module.name.includes("generated-flow-imports.js") || module.name.includes("generated-flow-imports-fallback.js"))) { + let subModules = []; + // Create sub modules only if they are available + if (module.modules) { + module.modules.filter(module => !module.name.includes("es5")).forEach(function (module) { + const subModule = { + name: module.name, + source: module.source + }; + subModules.push(subModule); + }); + } + const slimModule = { + id: module.id, + name: module.name, + source: module.source, + modules: subModules + }; + modules.push(slimModule); + } + }); + } + return modules; +} diff --git a/pom.xml b/pom.xml index 448112a9..d138a894 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ 10 10 UTF-8 - 14.1.25 + 14.2.0 \ No newline at end of file diff --git a/superfields/pom.xml b/superfields/pom.xml index 4f38ce08..0ebf86be 100644 --- a/superfields/pom.xml +++ b/superfields/pom.xml @@ -14,7 +14,7 @@ 10 10 UTF-8 - 14.1.25 + 14.2.0 3.1.2 @@ -88,10 +88,6 @@ ${vaadin.version} provided - - com.vaadin - vaadin-date-time-picker-flow - com.vaadin.webjar @@ -119,37 +115,6 @@ - - com.vaadin - vaadin-date-time-picker-flow - 1.0.0.alpha2 - - - com.vaadin.webjar - * - - - org.webjars.bowergithub.insites - * - - - org.webjars.bowergithub.polymer - * - - - org.webjars.bowergithub.polymerelements - * - - - org.webjars.bowergithub.vaadin - * - - - org.webjars.bowergithub.webcomponents - * - - - From b83344946c29c0086a7894ac8bb6ae5a192d02c8 Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 29 May 2020 02:03:11 +0300 Subject: [PATCH 12/66] #126, #127, #129 done (#128) #126 and #127 done default class name for the TextField inside number fields #129 done - using Java 11 in code quality check --- .github/workflows/codequality.yml | 4 ++-- .../styles/super-number-fields-styles.css | 15 ++++++++++++ .../main/java/org/vaadin/miki/MainView.java | 5 ++-- .../numbers/AbstractSuperNumberField.java | 23 ++++++++++++++++++- 4 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 demo-v14/frontend/styles/super-number-fields-styles.css diff --git a/.github/workflows/codequality.yml b/.github/workflows/codequality.yml index 6091ad33..98a6e2e1 100644 --- a/.github/workflows/codequality.yml +++ b/.github/workflows/codequality.yml @@ -15,10 +15,10 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 - - name: Set up JDK 10 + - name: Set up JDK 11 uses: actions/setup-java@v1 with: - java-version: 10 + java-version: 11 - name: Scan on SonarCloud.io run: mvn verify sonar:sonar -Psonar --file superfields/pom.xml env: diff --git a/demo-v14/frontend/styles/super-number-fields-styles.css b/demo-v14/frontend/styles/super-number-fields-styles.css new file mode 100644 index 00000000..4a4f6b2e --- /dev/null +++ b/demo-v14/frontend/styles/super-number-fields-styles.css @@ -0,0 +1,15 @@ +:host(#belongs-to-big-decimal) [part="value"] { + border-bottom: 2px solid orange; +} + +:host(.belongs-to-superintegerfield) [part="value"] { + border-bottom: 2px solid cyan; +} + +:host(.belongs-to-superdoublefield) [part="value"] { + border-bottom: 2px solid green; +} + +:host(#belongs-to-long) [part="value"] { + border-bottom: 2px solid purple; +} \ No newline at end of file diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainView.java b/demo-v14/src/main/java/org/vaadin/miki/MainView.java index 0652c490..da291534 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainView.java +++ b/demo-v14/src/main/java/org/vaadin/miki/MainView.java @@ -57,6 +57,7 @@ * @since 2020-04-07 */ @CssImport("./styles/demo-styles.css") +@CssImport(value = "./styles/super-number-fields-styles.css", themeFor = "vaadin-text-field") @Route @PageTitle("SuperFields Demo") public class MainView extends VerticalLayout { @@ -252,9 +253,9 @@ private Component getInfoPage() { public MainView() { this.components.put(SuperIntegerField.class, new SuperIntegerField("Integer (6 digits):").withMaximumIntegerDigits(6)); - this.components.put(SuperLongField.class, new SuperLongField("Long (11 digits):").withMaximumIntegerDigits(11)); + this.components.put(SuperLongField.class, new SuperLongField("Long (11 digits):").withMaximumIntegerDigits(11).withId("long")); this.components.put(SuperDoubleField.class, new SuperDoubleField("Double (8 + 4 digits):").withMaximumIntegerDigits(8).withMaximumFractionDigits(4)); - this.components.put(SuperBigDecimalField.class, new SuperBigDecimalField("Big decimal (12 + 3 digits):").withMaximumIntegerDigits(12).withMaximumFractionDigits(3).withMinimumFractionDigits(1)); + this.components.put(SuperBigDecimalField.class, new SuperBigDecimalField("Big decimal (12 + 3 digits):").withMaximumIntegerDigits(12).withMaximumFractionDigits(3).withMinimumFractionDigits(1).withId("big-decimal")); this.components.put(SuperDatePicker.class, new SuperDatePicker("Pick a date:").withDatePattern(DatePatterns.YYYY_MM_DD).withValue(LocalDate.now())); this.components.put(SuperDateTimePicker.class, new SuperDateTimePicker("Pick a date and time:").withDatePattern(DatePatterns.M_D_YYYY_SLASH).withValue(LocalDateTime.now())); this.components.put(SuperTabs.class, new SuperTabs((Supplier) HorizontalLayout::new) diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java index 80725cbb..ad1e2939 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java @@ -16,6 +16,7 @@ import org.vaadin.miki.markers.HasLocale; import org.vaadin.miki.markers.HasPlaceholder; import org.vaadin.miki.markers.HasTitle; +import org.vaadin.miki.markers.WithIdMixin; import org.vaadin.miki.markers.WithLabelMixin; import org.vaadin.miki.markers.WithLocaleMixin; import org.vaadin.miki.markers.WithPlaceholderMixin; @@ -39,10 +40,16 @@ public abstract class AbstractSuperNumberField implements HasPrefixAndSuffix, HasLabel, HasPlaceholder, HasTitle, HasLocale, WithLocaleMixin, WithLabelMixin, WithPlaceholderMixin, WithTitleMixin, - WithValueMixin, T>, T, SELF> { + WithValueMixin, T>, T, SELF>, + WithIdMixin { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractSuperNumberField.class); + /** + * Predefined class/id prefix for the inner text field. + */ + private static final String TEXT_FIELD_STYLE_PREFIX = "belongs-to-"; + /** * Some grouping separators are non-breaking spaces - impossible to type. */ @@ -112,6 +119,7 @@ protected AbstractSuperNumberField(T defaultValue, SerializablePredicate nega this.format.setMaximumFractionDigits(maxFractionDigits); this.updateRegularExpression(); + this.field.addClassName(TEXT_FIELD_STYLE_PREFIX +this.getClass().getSimpleName().toLowerCase()); this.add(this.field); this.field.setLabel(label); @@ -477,6 +485,19 @@ public String getTitle() { return this.field.getTitle(); } + @Override + public void setId(String id) { + super.setId(id); + this.field.setId(id == null ? null : TEXT_FIELD_STYLE_PREFIX +id); + } + + @SuppressWarnings("unchecked") + @Override + public SELF withId(String id) { + this.setId(id); + return (SELF)this; + } + /** * Returns the raw value, as currently displayed in the underlying text field. * This may depend on whether or not the component has focus, what locale is used, etc. From 88f970e42f9c2bdf023e5570682a26863222cc12 Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 29 May 2020 12:47:11 +0300 Subject: [PATCH 13/66] #132 done (#133) now using personal token when creating a release --- .github/workflows/makerelease.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/makerelease.yml b/.github/workflows/makerelease.yml index a6beb2a8..8366b507 100644 --- a/.github/workflows/makerelease.yml +++ b/.github/workflows/makerelease.yml @@ -23,7 +23,7 @@ jobs: - name: Create Release uses: fleskesvor/create-release@feature/support-target-commitish env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_TOKEN: ${{ secrets.ACTIONS_PAT }} with: tag_name: "v${{ steps.variables.outputs.version }}" commitish: "master" From 3e2429e203506141e1bc11463099ede9b7c4d2e7 Mon Sep 17 00:00:00 2001 From: Miki Date: Tue, 2 Jun 2020 00:15:37 +0300 Subject: [PATCH 14/66] 122 super text field (#134) #122 done added SuperTextField and SuperTextArea with API defined in interfaces updated demo app --- .../main/java/org/vaadin/miki/MainView.java | 24 ++++ .../superfields/dates/SuperDatePicker.java | 1 + .../dates/SuperDateTimePicker.java | 1 + .../CanReceiveSelectionEventsFromClient.java | 17 +++ .../miki/superfields/text/CanSelectText.java | 19 +++ .../miki/superfields/text/SuperTextArea.java | 103 ++++++++++++++ .../miki/superfields/text/SuperTextField.java | 121 +++++++++++++++++ .../text/TextSelectionDelegate.java | 128 ++++++++++++++++++ .../superfields/text/TextSelectionEvent.java | 53 ++++++++ .../text/TextSelectionListener.java | 13 ++ .../text/TextSelectionNotifier.java | 21 +++ ...ceivingSelectionEventsFromClientMixin.java | 25 ++++ .../resources/frontend/super-text-area.js | 15 ++ .../resources/frontend/super-text-field.js | 15 ++ .../frontend/text-selection-mixin.js | 69 ++++++++++ .../text/AbstractTestForTextSelection.java | 61 +++++++++ .../superfields/text/SuperTextAreaTest.java | 8 ++ .../superfields/text/SuperTextFieldTest.java | 9 ++ 18 files changed, 703 insertions(+) create mode 100644 superfields/src/main/java/org/vaadin/miki/superfields/text/CanReceiveSelectionEventsFromClient.java create mode 100644 superfields/src/main/java/org/vaadin/miki/superfields/text/CanSelectText.java create mode 100644 superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java create mode 100644 superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java create mode 100644 superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionDelegate.java create mode 100644 superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionEvent.java create mode 100644 superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionListener.java create mode 100644 superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionNotifier.java create mode 100644 superfields/src/main/java/org/vaadin/miki/superfields/text/WithReceivingSelectionEventsFromClientMixin.java create mode 100644 superfields/src/main/resources/META-INF/resources/frontend/super-text-area.js create mode 100644 superfields/src/main/resources/META-INF/resources/frontend/super-text-field.js create mode 100644 superfields/src/main/resources/META-INF/resources/frontend/text-selection-mixin.js create mode 100644 superfields/src/test/java/org/vaadin/miki/superfields/text/AbstractTestForTextSelection.java create mode 100644 superfields/src/test/java/org/vaadin/miki/superfields/text/SuperTextAreaTest.java create mode 100644 superfields/src/test/java/org/vaadin/miki/superfields/text/SuperTextFieldTest.java diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainView.java b/demo-v14/src/main/java/org/vaadin/miki/MainView.java index da291534..8dd9e306 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainView.java +++ b/demo-v14/src/main/java/org/vaadin/miki/MainView.java @@ -39,6 +39,10 @@ import org.vaadin.miki.superfields.tabs.SuperTabs; import org.vaadin.miki.superfields.tabs.TabHandler; import org.vaadin.miki.superfields.tabs.TabHandlers; +import org.vaadin.miki.superfields.text.CanSelectText; +import org.vaadin.miki.superfields.text.SuperTextArea; +import org.vaadin.miki.superfields.text.SuperTextField; +import org.vaadin.miki.superfields.text.TextSelectionNotifier; import org.vaadin.miki.superfields.unload.UnloadObserver; import java.time.LocalDate; @@ -132,6 +136,23 @@ private void buildHasValue(Component component, Consumer callback) ((HasValue) component).addValueChangeListener(this::onAnyValueChanged); } + private void buildCanSelectText(Component component, Consumer callback) { + final Button selectAll = new Button("Select all", event -> ((CanSelectText)component).selectAll()); + final Button selectNone = new Button("Select none", event -> ((CanSelectText)component).selectNone()); + final HorizontalLayout layout = new HorizontalLayout(new Span("Type something in the field, then click one of the buttons:"), selectAll, selectNone); + layout.setAlignItems(Alignment.CENTER); + callback.accept(new Component[]{ + layout + }); + if(component instanceof TextSelectionNotifier) { + final Span selection = new Span(); + ((TextSelectionNotifier) component).addTextSelectionListener(event -> selection.setText(event.getSelectedText())); + callback.accept(new Component[]{ + new HorizontalLayout(new Span("You can also select text yourself with keyboard our mouse. Here is the current selection: <"), selection, new Span(">")) + }); + } + } + @SuppressWarnings("unchecked") private void buildItemGrid(Component component, Consumer callback) { final RadioButtonGroup buttons = new RadioButtonGroup<>(); @@ -258,6 +279,8 @@ public MainView() { this.components.put(SuperBigDecimalField.class, new SuperBigDecimalField("Big decimal (12 + 3 digits):").withMaximumIntegerDigits(12).withMaximumFractionDigits(3).withMinimumFractionDigits(1).withId("big-decimal")); this.components.put(SuperDatePicker.class, new SuperDatePicker("Pick a date:").withDatePattern(DatePatterns.YYYY_MM_DD).withValue(LocalDate.now())); this.components.put(SuperDateTimePicker.class, new SuperDateTimePicker("Pick a date and time:").withDatePattern(DatePatterns.M_D_YYYY_SLASH).withValue(LocalDateTime.now())); + this.components.put(SuperTextField.class, new SuperTextField("Type something:").withPlaceholder("(nothing typed)").withId("super-text-field").withReceivingSelectionEventsFromClient(true)); + this.components.put(SuperTextArea.class, new SuperTextArea("Type a lot of something:").withPlaceholder("(nothing typed)").withId("super-text-area").withReceivingSelectionEventsFromClient(true)); this.components.put(SuperTabs.class, new SuperTabs((Supplier) HorizontalLayout::new) .withTabContentGenerator(s -> new Paragraph("Did you know? All SuperFields are "+s)) .withItems("Java friendly", "Super-configurable", "Open source") @@ -298,6 +321,7 @@ public MainView() { this.contentBuilders.put(AbstractSuperNumberField.class, this::buildAbstractSuperNumberField); this.contentBuilders.put(HasLocale.class, this::buildHasLocale); this.contentBuilders.put(HasValue.class, this::buildHasValue); + this.contentBuilders.put(CanSelectText.class, this::buildCanSelectText); this.contentBuilders.put(ItemGrid.class, this::buildItemGrid); this.contentBuilders.put(HasDatePattern.class, this::buildHasDatePattern); this.contentBuilders.put(SuperTabs.class, this::buildSuperTabs); diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java index f8a8f264..5438901a 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java @@ -23,6 +23,7 @@ */ @JsModule("./super-date-picker.js") @Tag("super-date-picker") +@SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes public class SuperDatePicker extends DatePicker implements HasLocale, HasLabel, HasPlaceholder, HasDatePattern, WithLocaleMixin, WithLabelMixin, diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java index dce504f9..b71f3764 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java @@ -25,6 +25,7 @@ */ @JsModule("./super-date-time-picker.js") @Tag("super-date-time-picker") +@SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes public class SuperDateTimePicker extends DateTimePicker implements HasLocale, HasLabel, HasDatePattern, WithLocaleMixin, WithLabelMixin, diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/CanReceiveSelectionEventsFromClient.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/CanReceiveSelectionEventsFromClient.java new file mode 100644 index 00000000..489ae517 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/CanReceiveSelectionEventsFromClient.java @@ -0,0 +1,17 @@ +package org.vaadin.miki.superfields.text; + +public interface CanReceiveSelectionEventsFromClient { + /** + * Check if client will inform server on selection change. + * Note: this feature is by default turned off. + * @return When {@code true}, each selection change in the client-side component will result in this component broadcasting a {@link TextSelectionEvent}. + */ + boolean isReceivingSelectionEventsFromClient(); + + /** + * Configures sending events by the client-side component. + * Note: this feature is by default turned off. + * @param receivingSelectionEventsFromClient When {@code false}, selecting text in client-side component will not send an event to server-side component. When {@code true}, it will. + */ + void setReceivingSelectionEventsFromClient(boolean receivingSelectionEventsFromClient); +} diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/CanSelectText.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/CanSelectText.java new file mode 100644 index 00000000..11604944 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/CanSelectText.java @@ -0,0 +1,19 @@ +package org.vaadin.miki.superfields.text; + +import com.vaadin.flow.component.HasElement; + +/** + * Marker interface for components that can select text. + * Handles selection using client-side JavaScript. + * @author miki + * @since 2020-05-29 + */ +public interface CanSelectText extends HasElement { + + void selectAll(); + + void selectNone(); + + void select(int from, int to); + +} diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java new file mode 100644 index 00000000..026d2980 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java @@ -0,0 +1,103 @@ +package org.vaadin.miki.superfields.text; + +import com.vaadin.flow.component.AbstractField; +import com.vaadin.flow.component.ClientCallable; +import com.vaadin.flow.component.Tag; +import com.vaadin.flow.component.dependency.JsModule; +import com.vaadin.flow.component.textfield.TextArea; +import com.vaadin.flow.shared.Registration; +import org.vaadin.miki.markers.HasLabel; +import org.vaadin.miki.markers.HasPlaceholder; +import org.vaadin.miki.markers.WithIdMixin; +import org.vaadin.miki.markers.WithLabelMixin; +import org.vaadin.miki.markers.WithPlaceholderMixin; +import org.vaadin.miki.markers.WithValueMixin; + +/** + * An extension of {@link TextArea} with some useful features. + * @author miki + * @since 2020-06-01 + */ +@Tag("super-text-area") +@JsModule("./super-text-area.js") +@SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes +public class SuperTextArea extends TextArea implements CanSelectText, TextSelectionNotifier, + HasLabel, HasPlaceholder, WithIdMixin, WithLabelMixin, WithPlaceholderMixin, + WithReceivingSelectionEventsFromClientMixin, + WithValueMixin, String, SuperTextArea> { + + private final TextSelectionDelegate delegate = new TextSelectionDelegate<>(this); + + private boolean receivingSelectionEventsFromClient = false; + + public SuperTextArea() { + } + + public SuperTextArea(String label) { + super(label); + } + + public SuperTextArea(String label, String placeholder) { + super(label, placeholder); + } + + public SuperTextArea(String label, String initialValue, String placeholder) { + super(label, initialValue, placeholder); + } + + public SuperTextArea(ValueChangeListener> listener) { + super(listener); + } + + public SuperTextArea(String label, ValueChangeListener> listener) { + super(label, listener); + } + + public SuperTextArea(String label, String initialValue, ValueChangeListener> listener) { + super(label, initialValue, listener); + } + + @Override + public boolean isReceivingSelectionEventsFromClient() { + return this.receivingSelectionEventsFromClient; + } + + @Override + public void setReceivingSelectionEventsFromClient(boolean receivingSelectionEventsFromClient) { + this.receivingSelectionEventsFromClient = receivingSelectionEventsFromClient; + this.delegate.informClientAboutSendingEvents(receivingSelectionEventsFromClient); + } + + @Override + public void selectAll() { + this.delegate.selectAll(this::getValue, this::getEventBus); + } + + @Override + public void selectNone() { + this.delegate.selectNone(this::getEventBus); + } + + @Override + public void select(int from, int to) { + this.delegate.select(this::getValue, this::getEventBus, from, to); + } + + @Override + @SuppressWarnings("unchecked") + public Registration addTextSelectionListener(TextSelectionListener listener) { + return this.getEventBus().addListener((Class>)(Class)TextSelectionEvent.class, listener); + } + + @ClientCallable + private void selectionChanged(int start, int end, String selection) { + TextSelectionEvent event = new TextSelectionEvent<>(this, true, start, end, selection); + this.delegate.fireTextSelectionEvent(this.getEventBus(), event); + } + + @Override + public void setValue(String value) { + this.delegate.updateAttributeOnValueChange(this::getEventBus); + super.setValue(value); + } +} diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java new file mode 100644 index 00000000..b9854ce1 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java @@ -0,0 +1,121 @@ +package org.vaadin.miki.superfields.text; + +import com.vaadin.flow.component.AbstractField; +import com.vaadin.flow.component.AttachEvent; +import com.vaadin.flow.component.ClientCallable; +import com.vaadin.flow.component.DetachEvent; +import com.vaadin.flow.component.Tag; +import com.vaadin.flow.component.dependency.JsModule; +import com.vaadin.flow.component.textfield.TextField; +import com.vaadin.flow.shared.Registration; +import org.vaadin.miki.markers.HasLabel; +import org.vaadin.miki.markers.HasPlaceholder; +import org.vaadin.miki.markers.WithIdMixin; +import org.vaadin.miki.markers.WithLabelMixin; +import org.vaadin.miki.markers.WithPlaceholderMixin; +import org.vaadin.miki.markers.WithValueMixin; + +/** + * An extension of {@link TextField} with some useful (hopefully) features. + * @author miki + * @since 2020-05-29 + */ +@Tag("super-text-field") +@JsModule("./super-text-field.js") +@SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes +public class SuperTextField extends TextField implements CanSelectText, TextSelectionNotifier, + HasLabel, HasPlaceholder, + WithIdMixin, WithLabelMixin, WithPlaceholderMixin, + WithValueMixin, String, SuperTextField>, + WithReceivingSelectionEventsFromClientMixin { + + private boolean receivingSelectionEventsFromClient = false; + + private final TextSelectionDelegate delegate = new TextSelectionDelegate<>(this); + + public SuperTextField() { + super(); + } + + public SuperTextField(String label) { + super(label); + } + + public SuperTextField(String label, String placeholder) { + super(label, placeholder); + } + + public SuperTextField(String label, String initialValue, String placeholder) { + super(label, initialValue, placeholder); + } + + public SuperTextField(ValueChangeListener> listener) { + super(listener); + } + + public SuperTextField(String label, ValueChangeListener> listener) { + super(label, listener); + } + + public SuperTextField(String label, String initialValue, ValueChangeListener> listener) { + super(label, initialValue, listener); + } + + @Override + protected void onAttach(AttachEvent attachEvent) { + this.delegate.informClientAboutSendingEvents(this.isReceivingSelectionEventsFromClient()); + super.onAttach(attachEvent); + } + + @Override + protected void onDetach(DetachEvent detachEvent) { + // detaching means server should not be informed + if(this.isReceivingSelectionEventsFromClient()) + this.delegate.informClientAboutSendingEvents(false); + super.onDetach(detachEvent); + } + + @Override + @SuppressWarnings("unchecked") + public Registration addTextSelectionListener(TextSelectionListener listener) { + return this.getEventBus().addListener((Class>)(Class)TextSelectionEvent.class, listener); + } + + @Override + public void selectAll() { + this.delegate.selectAll(this::getValue, this::getEventBus); + } + + @Override + public void selectNone() { + this.delegate.selectNone(this::getEventBus); + } + + @Override + public void select(int from, int to) { + this.delegate.select(this::getValue, this::getEventBus, from, to); + } + + @ClientCallable + private void selectionChanged(int start, int end, String selection) { + TextSelectionEvent event = new TextSelectionEvent<>(this, true, start, end, selection); + this.delegate.fireTextSelectionEvent(this.getEventBus(), event); + } + + @Override + public boolean isReceivingSelectionEventsFromClient() { + return this.receivingSelectionEventsFromClient; + } + + @Override + public void setReceivingSelectionEventsFromClient(boolean receivingSelectionEventsFromClient) { + this.receivingSelectionEventsFromClient = receivingSelectionEventsFromClient; + this.delegate.informClientAboutSendingEvents(receivingSelectionEventsFromClient); + } + + @Override + public void setValue(String value) { + this.delegate.updateAttributeOnValueChange(this::getEventBus); + super.setValue(value); + } +} diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionDelegate.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionDelegate.java new file mode 100644 index 00000000..01346f61 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionDelegate.java @@ -0,0 +1,128 @@ +package org.vaadin.miki.superfields.text; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.ComponentEventBus; + +import java.io.Serializable; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; + +/** + * Internal class that handles common behaviour related to text selection. + * Note: this is for internal use only. + * @author miki + * @since 2020-06-01 + */ +class TextSelectionDelegate implements Serializable { + + /** + * Defines the name of the HTML attribute that contains the selected text. + */ + public static final String SELECTED_TEXT_ATTRIBUTE_NAME = "data-selected-text"; + + private final C source; + + /** + * Creates the delegate for a given component. + * @param source Source of all events, data, etc. + */ + TextSelectionDelegate(C source) { + this.source = source; + } + + /** + * Sends information to the client side about whether or not it should forward text selection change events. + * @param value When {@code true}, client-side will notify server about changes in text selection. + */ + protected void informClientAboutSendingEvents(boolean value) { + this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> + this.source.getElement().callJsFunction( + "setCallingServer", + value + ) + )); + } + + /** + * Fires text selection event. + * @param eventBus Event bus. + * @param event Event with information about text selection. + */ + protected void fireTextSelectionEvent(ComponentEventBus eventBus, TextSelectionEvent event) { + eventBus.fireEvent(event); + } + + private void selectionChanged(ComponentEventBus eventBus, int start, int end, String selection) { + TextSelectionEvent event = new TextSelectionEvent<>(this.source, true, start, end, selection); + this.fireTextSelectionEvent(eventBus, event); + } + + /** + * Selects all text. + * @param valueSupplier Way of getting current value. Needed if no client notifications. + * @param eventBusSupplier Way of getting event bus. Needed if no client notifications. + */ + void selectAll(Supplier valueSupplier, Supplier eventBusSupplier) { + this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> + this.source.getElement().callJsFunction("selectAll", this.source.getElement()) + )); + // send event if the client is not doing it + if(!this.source.isReceivingSelectionEventsFromClient()) { + final String value = valueSupplier.get(); + this.source.getElement().setAttribute(SELECTED_TEXT_ATTRIBUTE_NAME, value); + this.selectionChanged(eventBusSupplier.get(), 0, value.length(), value); + } + } + + /** + * Selects no text. + * @param eventBusSupplier Way of getting event bus. Needed if no client notifications. + */ + void selectNone(Supplier eventBusSupplier) { + this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> + this.source.getElement().callJsFunction("selectNone", this.source.getElement()) + )); + // send event if the client is not doing it + if(!this.source.isReceivingSelectionEventsFromClient()) { + this.source.getElement().setAttribute(SELECTED_TEXT_ATTRIBUTE_NAME, ""); + this.selectionChanged(eventBusSupplier.get(), -1, -1, ""); + } + } + + /** + * Selects some text. + * @param valueSupplier Way of getting current value. Needed if no client notifications. + * @param eventBusSupplier Way of getting event bus. Needed if no client notifications. + * @param from Selection starting index, inclusive. + * @param to Selection end index, exclusive. + */ + void select(Supplier valueSupplier, Supplier eventBusSupplier, int from, int to) { + if(from <= to) + this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> + this.source.getElement().callJsFunction("select", this.source.getElement(), from, to) + )); + // send event if the client is not doing it + if(!this.source.isReceivingSelectionEventsFromClient()) { + final String value = valueSupplier.get().substring(from, to); + this.source.getElement().setAttribute(SELECTED_TEXT_ATTRIBUTE_NAME, value); + this.selectionChanged(eventBusSupplier.get(), from, to, value); + } + } + + /** + * Handles selection change on value change if there are no client notifications. + * Does nothing if the component is receiving client-side notifications. + * @param eventBusSupplier Way of getting event bus. + */ + void updateAttributeOnValueChange(Supplier eventBusSupplier) { + // special case here: if there was selection, no client-side events are caught and value is set, event must be fired + if(!this.source.isReceivingSelectionEventsFromClient()) { + final String lastSelected = Optional.ofNullable(this.source.getElement().getAttribute(SELECTED_TEXT_ATTRIBUTE_NAME)).orElse(""); + this.source.getElement().setAttribute(SELECTED_TEXT_ATTRIBUTE_NAME, ""); + if(!Objects.equals(lastSelected, "")) + this.fireTextSelectionEvent(eventBusSupplier.get(), new TextSelectionEvent<>(this.source, false, -1, -1, "")); + } + } + +} diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionEvent.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionEvent.java new file mode 100644 index 00000000..13155984 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionEvent.java @@ -0,0 +1,53 @@ +package org.vaadin.miki.superfields.text; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.ComponentEvent; + +import java.util.Optional; + +/** + * Component event with information about selected text. + * @param Type of component that broadcast the event. + * @author miki + * @since 2020-05-30 + */ +public final class TextSelectionEvent extends ComponentEvent { + + public static final int NO_SELECTION = -1; + + private final int selectionStart; + private final int selectionEnd; + private final String selectedText; + + /** + * Creates a new event using the given source and indicator whether the + * event originated from the client side or the server side. + * @param source the source component + * @param fromClient true if the event originated from the client + * @param selectionStart Where selection starts in the component. Can be {@link #NO_SELECTION}. + * @param selectionEnd Where selection ends in the component. Can be {@link #NO_SELECTION}. + * @param selectedText What is the selected text. Can be empty. + */ + public TextSelectionEvent(T source, boolean fromClient, int selectionStart, int selectionEnd, String selectedText) { + super(source, fromClient); + this.selectionStart = selectionStart; + this.selectionEnd = selectionEnd; + this.selectedText = Optional.ofNullable(selectedText).orElse(""); + } + + public int getSelectionStart() { + return selectionStart; + } + + public int getSelectionEnd() { + return selectionEnd; + } + + public String getSelectedText() { + return selectedText; + } + + public boolean isAnythingSelected() { + return this.selectionStart != NO_SELECTION && this.selectionEnd != this.selectionStart && !this.selectedText.isEmpty(); + } +} diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionListener.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionListener.java new file mode 100644 index 00000000..1f007f6d --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionListener.java @@ -0,0 +1,13 @@ +package org.vaadin.miki.superfields.text; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.ComponentEventListener; + +/** + * Marker interface for objects + * @param Component type. + * @author miki + * @since 2020-05-30 + */ +public interface TextSelectionListener extends ComponentEventListener> { +} diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionNotifier.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionNotifier.java new file mode 100644 index 00000000..97d3e3f7 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionNotifier.java @@ -0,0 +1,21 @@ +package org.vaadin.miki.superfields.text; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.shared.Registration; + +/** + * Marker interface for objects that broadcast {@link TextSelectionEvent}. + * @author miki + * @since 2020-05-30 + */ +@FunctionalInterface +public interface TextSelectionNotifier { + + /** + * Adds the listener. + * @param listener A listener to add. + * @return A {@link Registration} that can be used to stop listening to the event. + */ + Registration addTextSelectionListener(TextSelectionListener listener); + +} diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/WithReceivingSelectionEventsFromClientMixin.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/WithReceivingSelectionEventsFromClientMixin.java new file mode 100644 index 00000000..cb9fbde0 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/WithReceivingSelectionEventsFromClientMixin.java @@ -0,0 +1,25 @@ +package org.vaadin.miki.superfields.text; + +/** + * Marker interface for chaining {@link #setReceivingSelectionEventsFromClient(boolean)}. + * @param Self type. + * @author miki + * @since 2020-06-01 + */ +public interface WithReceivingSelectionEventsFromClientMixin extends CanReceiveSelectionEventsFromClient { + + /** + * Chains {@link #setReceivingSelectionEventsFromClient(boolean)} and returns itself. + * Note: this feature is by default turned off. + * @param receivingSelectionEventsFromClient Whether or not the client should send events about text selection changes. + * @return This. + * @see #setReceivingSelectionEventsFromClient(boolean) + */ + @SuppressWarnings("unchecked") + default SELF withReceivingSelectionEventsFromClient(boolean receivingSelectionEventsFromClient) { + this.setReceivingSelectionEventsFromClient(receivingSelectionEventsFromClient); + return (SELF)this; + } + + +} diff --git a/superfields/src/main/resources/META-INF/resources/frontend/super-text-area.js b/superfields/src/main/resources/META-INF/resources/frontend/super-text-area.js new file mode 100644 index 00000000..32e5764e --- /dev/null +++ b/superfields/src/main/resources/META-INF/resources/frontend/super-text-area.js @@ -0,0 +1,15 @@ +import {TextAreaElement} from '@vaadin/vaadin-text-field/src/vaadin-text-area'; +import {TextSelectionMixin} from "./text-selection-mixin"; + +class SuperTextArea extends TextSelectionMixin.to(TextAreaElement) { + + static get is() {return 'super-text-area'} + + setCallingServer(callingServer) { + console.log('STA: configuring event listeners; callingServer flag is '+callingServer); + this.listenToEvents(this.inputElement, this, callingServer); + } + +} + +customElements.define(SuperTextArea.is, SuperTextArea); \ No newline at end of file diff --git a/superfields/src/main/resources/META-INF/resources/frontend/super-text-field.js b/superfields/src/main/resources/META-INF/resources/frontend/super-text-field.js new file mode 100644 index 00000000..87c0b44d --- /dev/null +++ b/superfields/src/main/resources/META-INF/resources/frontend/super-text-field.js @@ -0,0 +1,15 @@ +import {TextFieldElement} from '@vaadin/vaadin-text-field/src/vaadin-text-field'; +import {TextSelectionMixin} from "./text-selection-mixin"; + +class SuperTextField extends TextSelectionMixin.to(TextFieldElement) { + + static get is() {return 'super-text-field'} + + setCallingServer(callingServer) { + console.log('STF: configuring event listeners; callingServer flag is '+callingServer); + this.listenToEvents(this.inputElement, this, callingServer); + } + +} + +customElements.define(SuperTextField.is, SuperTextField); \ No newline at end of file diff --git a/superfields/src/main/resources/META-INF/resources/frontend/text-selection-mixin.js b/superfields/src/main/resources/META-INF/resources/frontend/text-selection-mixin.js new file mode 100644 index 00000000..3d469f5f --- /dev/null +++ b/superfields/src/main/resources/META-INF/resources/frontend/text-selection-mixin.js @@ -0,0 +1,69 @@ +export class TextSelectionMixin { + static to(superclass) { + return class extends superclass { + + updateData(data, src) { + const currentStart = data.startsAt; + const currentEnd = data.endsAt; + // there is some selection + if (data.input.selectionStart !== undefined && data.input.selectionStart !== data.input.selectionEnd) { + data.startsAt = data.input.selectionStart; + data.endsAt = data.input.selectionEnd; + data.selection = data.input.value.substring(data.startsAt, data.endsAt); + } + else { + data.startsAt = -1; + data.endsAt = -1; + data.selection = ''; + } + src.dataset.selectedText = data.selection; + if(data.callServer && (currentStart !== data.startsAt || currentEnd !== data.endsAt)) { + console.log('TSM: calling server'); + src.$server.selectionChanged(data.startsAt, data.endsAt, data.selection); + } + } + + selectAll(src) { + console.log('TSM: selecting all text'); + src.selectionMixin.input.select(); + src.updateData(src.selectionMixin, src); + } + + selectNone(src) { + console.log('TSM: selecting no text'); + src.selectionMixin.input.selectionStart = src.selectionMixin.input.selectionEnd; + src.updateData(src.selectionMixin, src) + } + + select(src, from, to) { + console.log('TSM: selecting from '+from+' to '+to); + if (from <= to) { + src.selectionMixin.input.selectionStart = from; + src.selectionMixin.input.selectionEnd = to; + src.updateData(src.selectionMixin, src); + } + } + + listenToEvents(inputComponent, webComponent, notifyServer) { + console.log('TSM: setting up text selection for component <'+webComponent.tagName+'>'); + if (webComponent.selectionMixin === undefined) { + webComponent.selectionMixin = { + input: inputComponent, + callServer: notifyServer, + startsAt: -1, + endsAt: -1, + selection: '' + } + + const listener = () => webComponent.updateData(webComponent.selectionMixin, webComponent); + inputComponent.addEventListener('mouseup', listener); + inputComponent.addEventListener('keyup', listener); + inputComponent.addEventListener('mouseleave', listener); + } + else { + webComponent.selectionMixin.callServer = notifyServer; + } + } + } + } +} \ No newline at end of file diff --git a/superfields/src/test/java/org/vaadin/miki/superfields/text/AbstractTestForTextSelection.java b/superfields/src/test/java/org/vaadin/miki/superfields/text/AbstractTestForTextSelection.java new file mode 100644 index 00000000..75dc74ce --- /dev/null +++ b/superfields/src/test/java/org/vaadin/miki/superfields/text/AbstractTestForTextSelection.java @@ -0,0 +1,61 @@ +package org.vaadin.miki.superfields.text; + +import com.github.mvysny.kaributesting.v10.MockVaadin; +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.HasValue; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +abstract class AbstractTestForTextSelection & CanReceiveSelectionEventsFromClient & TextSelectionNotifier> { + + private C textComponent; + + private int eventCounter; + + private String lastSelectedText; + + protected abstract C constructComponent(); + + @Before + public void setUp() { + MockVaadin.setup(); + this.textComponent = this.constructComponent(); + this.textComponent.addTextSelectionListener(event -> { + eventCounter++; + lastSelectedText = event.getSelectedText(); + }); + this.eventCounter = 0; + } + + @After + public void tearDown() { + MockVaadin.tearDown(); + } + + // note: it is not possible to test client-side with karibu + @Test + public void testServerSideSelection() { + final String helloWorld = "hello, world!"; + Assert.assertFalse(this.textComponent.isReceivingSelectionEventsFromClient()); + this.textComponent.setValue(helloWorld); + this.textComponent.selectAll(); + Assert.assertEquals("text-selection should have been fired", 1, this.eventCounter); + Assert.assertEquals("all text should be selected in event", helloWorld, this.lastSelectedText); + Assert.assertEquals("all text should be selected in attribute", helloWorld, this.textComponent.getElement().getAttribute(TextSelectionDelegate.SELECTED_TEXT_ATTRIBUTE_NAME)); + this.textComponent.selectNone(); + Assert.assertEquals("text-selection should have been fired again", 2, this.eventCounter); + Assert.assertTrue("no text should be selected in event", this.lastSelectedText.isEmpty()); + Assert.assertTrue("no text should be selected in attribute", this.textComponent.getElement().getAttribute(TextSelectionDelegate.SELECTED_TEXT_ATTRIBUTE_NAME).isEmpty()); + this.textComponent.select(7, 12); + Assert.assertEquals("text-selection should have been fired again", 3, this.eventCounter); + Assert.assertEquals("some text should be selected in event", "world", this.lastSelectedText); + Assert.assertEquals("some text should be selected in attribute", "world", this.textComponent.getElement().getAttribute(TextSelectionDelegate.SELECTED_TEXT_ATTRIBUTE_NAME)); + this.textComponent.setValue("clear selection"); + Assert.assertEquals("text-selection should have been fired again", 4, this.eventCounter); + Assert.assertTrue("no text should be selected in event", this.lastSelectedText.isEmpty()); + Assert.assertTrue("no text should be selected in attribute", this.textComponent.getElement().getAttribute(TextSelectionDelegate.SELECTED_TEXT_ATTRIBUTE_NAME).isEmpty()); + } + +} diff --git a/superfields/src/test/java/org/vaadin/miki/superfields/text/SuperTextAreaTest.java b/superfields/src/test/java/org/vaadin/miki/superfields/text/SuperTextAreaTest.java new file mode 100644 index 00000000..ae3dde64 --- /dev/null +++ b/superfields/src/test/java/org/vaadin/miki/superfields/text/SuperTextAreaTest.java @@ -0,0 +1,8 @@ +package org.vaadin.miki.superfields.text; + +public class SuperTextAreaTest extends AbstractTestForTextSelection { + @Override + protected SuperTextArea constructComponent() { + return new SuperTextArea(); + } +} diff --git a/superfields/src/test/java/org/vaadin/miki/superfields/text/SuperTextFieldTest.java b/superfields/src/test/java/org/vaadin/miki/superfields/text/SuperTextFieldTest.java new file mode 100644 index 00000000..eef5802c --- /dev/null +++ b/superfields/src/test/java/org/vaadin/miki/superfields/text/SuperTextFieldTest.java @@ -0,0 +1,9 @@ +package org.vaadin.miki.superfields.text; + +public class SuperTextFieldTest extends AbstractTestForTextSelection { + + @Override + protected SuperTextField constructComponent() { + return new SuperTextField(); + } +} \ No newline at end of file From c50f6551c85779a2954a77f5af03ef6971f825e5 Mon Sep 17 00:00:00 2001 From: Miki Date: Tue, 2 Jun 2020 18:42:00 +0300 Subject: [PATCH 15/66] #136 done some more methods are now delegated properly to the text field --- .../main/java/org/vaadin/miki/MainView.java | 2 + .../numbers/AbstractSuperNumberField.java | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainView.java b/demo-v14/src/main/java/org/vaadin/miki/MainView.java index 8dd9e306..fe343aa6 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainView.java +++ b/demo-v14/src/main/java/org/vaadin/miki/MainView.java @@ -133,7 +133,9 @@ private void buildHasLocale(Component component, Consumer callback) } private void buildHasValue(Component component, Consumer callback) { + final Checkbox toggle = new Checkbox("Mark component as read only?", event -> ((HasValue)component).setReadOnly(event.getValue())); ((HasValue) component).addValueChangeListener(this::onAnyValueChanged); + callback.accept(new Component[]{toggle}); } private void buildCanSelectText(Component component, Consumer callback) { diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java index ad1e2939..9bd8617b 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java @@ -525,6 +525,46 @@ public void removeThemeVariants(TextFieldVariant... variants) { this.field.removeThemeVariants(variants); } + @Override + public void setReadOnly(boolean readOnly) { + this.field.setReadOnly(readOnly); + } + + @Override + public boolean isReadOnly() { + return this.field.isReadOnly(); + } + + @Override + public void setRequiredIndicatorVisible(boolean requiredIndicatorVisible) { + this.field.setRequiredIndicatorVisible(requiredIndicatorVisible); + } + + @Override + public boolean isRequiredIndicatorVisible() { + return this.field.isRequiredIndicatorVisible(); + } + + @Override + public void setErrorMessage(String errorMessage) { + this.field.setErrorMessage(errorMessage); + } + + @Override + public String getErrorMessage() { + return this.field.getErrorMessage(); + } + + @Override + public void setInvalid(boolean invalid) { + this.field.setInvalid(invalid); + } + + @Override + public boolean isInvalid() { + return this.field.isInvalid(); + } + /** * Explicitly invokes code that would otherwise be called when the component receives focus. * For testing purposes only. From 5601d60afa83f66787d60bf4e0283a081864e753 Mon Sep 17 00:00:00 2001 From: Miki Date: Wed, 3 Jun 2020 01:01:25 +0300 Subject: [PATCH 16/66] #137 done (#140) UnloadObserver is now a singleton in Java; also client-side code is now globally stored in `window.Vaadin.unloadObserver` --- .../main/java/org/vaadin/miki/MainView.java | 9 ++--- .../superfields/unload/UnloadObserver.java | 36 +++++++++++++++---- .../resources/frontend/unload-observer.js | 31 ++++++++-------- 3 files changed, 51 insertions(+), 25 deletions(-) diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainView.java b/demo-v14/src/main/java/org/vaadin/miki/MainView.java index fe343aa6..560a48e3 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainView.java +++ b/demo-v14/src/main/java/org/vaadin/miki/MainView.java @@ -19,6 +19,8 @@ import com.vaadin.flow.component.tabs.Tab; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.textfield.TextFieldVariant; +import com.vaadin.flow.function.SerializableBiConsumer; +import com.vaadin.flow.function.SerializableConsumer; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import org.vaadin.miki.markers.HasLocale; @@ -51,7 +53,6 @@ import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; -import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; @@ -68,9 +69,9 @@ public class MainView extends VerticalLayout { private final Map, Component> components = new LinkedHashMap<>(); - private final Map, Consumer> afterLocaleChange = new HashMap<>(); + private final Map, SerializableConsumer> afterLocaleChange = new HashMap<>(); - private final Map, BiConsumer>> contentBuilders = new LinkedHashMap<>(); + private final Map, SerializableBiConsumer>> contentBuilders = new LinkedHashMap<>(); private static Component generateParagraph(Class type, int row, int column) { Paragraph result = new Paragraph(type.getSimpleName()); @@ -289,7 +290,7 @@ public MainView() { ); this.components.put(ObservedField.class, new ObservedField()); this.components.put(ComponentObserver.class, new ComponentObserver()); - this.components.put(UnloadObserver.class, new UnloadObserver(false)); + this.components.put(UnloadObserver.class, UnloadObserver.get(false)); this.components.put(ItemGrid.class, new ItemGrid>( null, () -> { diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java b/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java index a37c73b0..349109f2 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java @@ -13,13 +13,38 @@ /** * Server-side component that listens to {@code beforeunload} events. * Based on the code by Kaspar Scherrer and Stuart Robinson. + * Warning: this class is a Singleton; the class is final, the constructors are private and there is at most one global instance. * * @author Kaspar Scherrer, Stuart Robinson; adapted to web-component by miki * @since 2020-04-29 */ @JsModule("./unload-observer.js") @Tag("unload-observer") -public class UnloadObserver extends PolymerTemplate implements WithIdMixin { +public final class UnloadObserver extends PolymerTemplate implements WithIdMixin { + + private static UnloadObserver instance = null; + + /** + * Returns the current instance. Will create one using default no-arg constructor if none is present yet. + * @return An instance of {@link UnloadObserver}. + */ + public static UnloadObserver get() { + if(instance == null) + instance = new UnloadObserver(); + return instance; + } + + /** + * Returns the current instance. Will create one if needed and set its {@link #setQueryingOnUnload(boolean)}. + * @param queryingOnUnload Whether or not query at page close. + * @return An instance of {@link UnloadObserver}. + */ + public static UnloadObserver get(boolean queryingOnUnload) { + if(instance == null) + instance = new UnloadObserver(queryingOnUnload); + else instance.setQueryingOnUnload(queryingOnUnload); + return instance; + } private boolean queryingOnUnload; @@ -28,7 +53,7 @@ public class UnloadObserver extends PolymerTemplate implements Wi /** * Creates the unload observer and by default queries the user on unloading the page. */ - public UnloadObserver() { + private UnloadObserver() { this(true); } @@ -36,7 +61,7 @@ public UnloadObserver() { * Creates the unload observer. * @param queryOnUnload Whether or not to query the user on unloading the page. */ - public UnloadObserver(boolean queryOnUnload) { + private UnloadObserver(boolean queryOnUnload) { super(); this.setQueryingOnUnload(queryOnUnload); } @@ -102,10 +127,7 @@ protected void onAttach(AttachEvent attachEvent) { @Override protected void onDetach(DetachEvent detachEvent) { - if(this.clientInitialised) { - this.getElement().callJsFunction("stopObserver"); - this.clientInitialised = false; - } + this.clientInitialised = false; super.onDetach(detachEvent); } diff --git a/superfields/src/main/resources/META-INF/resources/frontend/unload-observer.js b/superfields/src/main/resources/META-INF/resources/frontend/unload-observer.js index 99bebe20..fb9ee7e2 100644 --- a/superfields/src/main/resources/META-INF/resources/frontend/unload-observer.js +++ b/superfields/src/main/resources/META-INF/resources/frontend/unload-observer.js @@ -20,8 +20,17 @@ export class UnloadObserver extends PolymerElement { * Initialises the observer and registers a beforeunload listener. */ initObserver() { - console.log("registering unload listener") - window.addEventListener('beforeunload', event => this.unloadHappened(this, event)); + const src = this; + if (window.Vaadin.unloadObserver === undefined) { + window.Vaadin.unloadObserver = { + handler: undefined + } + } + if (window.Vaadin.unloadObserver.handler !== undefined) { + window.removeEventListener('beforeunload', window.Vaadin.unloadObserver.handler); + } + window.Vaadin.unloadObserver.handler = event => src.unloadHappened(src, event); + window.addEventListener('beforeunload', window.Vaadin.unloadObserver.handler); } /** @@ -30,10 +39,12 @@ export class UnloadObserver extends PolymerElement { * @param event Event that happened. */ unloadHappened(source, event) { - if (source.dataset.queryOnUnload) { + if (window.Vaadin.unloadObserver.query) { event.preventDefault(); event.returnValue = ''; - source.$server.unloadAttempted(); + if (source.$server) { + source.$server.unloadAttempted(); + } } } @@ -43,21 +54,13 @@ export class UnloadObserver extends PolymerElement { */ queryOnUnload(value) { if (value) { - this.dataset.queryOnUnload = 'true'; + window.Vaadin.unloadObserver.query = 'true'; } else { - delete this.dataset.queryOnUnload; + delete window.Vaadin.unloadObserver.query; } } - /** - * Unregisters itself from listening to unload events. - */ - stopObserver() { - console.log("removing unload listener") - window.removeEventListener('beforeunload', event => this.unloadHappened(this, event)); - } - static get properties() { return { }; From 9c89b3106ee78b599820e8d41f5e4d90de3a52fb Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 5 Jun 2020 01:09:49 +0300 Subject: [PATCH 17/66] 123 text selection api (#142) #123 done; #141 done; #122 fixed SuperTextArea also, updated demo app --- demo-v14/frontend/styles/demo-styles.css | 25 ++++- .../main/java/org/vaadin/miki/InfoPage.java | 25 +++++ .../main/java/org/vaadin/miki/MainView.java | 71 +++++++----- .../text/TextSelectionEvent.java | 3 +- .../text/TextSelectionListener.java | 3 +- .../text/TextSelectionNotifier.java | 3 +- .../CanReceiveSelectionEventsFromClient.java | 9 +- .../vaadin/miki/markers/CanSelectText.java | 30 ++++++ .../dates => markers}/HasDatePattern.java | 4 +- .../WithDatePatternMixin.java | 4 +- ...ceivingSelectionEventsFromClientMixin.java | 2 +- .../text/TextSelectionDelegate.java | 25 +++-- ...rnHelper.java => DatePatternDelegate.java} | 35 +++++- .../superfields/dates/SuperDatePicker.java | 101 +++++++++++++++++- .../dates/SuperDateTimePicker.java | 6 +- .../numbers/AbstractSuperNumberField.java | 59 +++++++++- .../miki/superfields/text/CanSelectText.java | 19 ---- .../miki/superfields/text/SuperTextArea.java | 23 ++++ .../miki/superfields/text/SuperTextField.java | 6 ++ .../resources/frontend/super-date-picker.js | 8 +- .../dates/DatePatternDelegateTest.java | 43 ++++++++ .../text/AbstractTestForTextSelection.java | 4 + 22 files changed, 431 insertions(+), 77 deletions(-) create mode 100644 demo-v14/src/main/java/org/vaadin/miki/InfoPage.java rename superfields/src/main/java/org/vaadin/miki/{superfields => events}/text/TextSelectionEvent.java (95%) rename superfields/src/main/java/org/vaadin/miki/{superfields => events}/text/TextSelectionListener.java (80%) rename superfields/src/main/java/org/vaadin/miki/{superfields => events}/text/TextSelectionNotifier.java (87%) rename superfields/src/main/java/org/vaadin/miki/{superfields/text => markers}/CanReceiveSelectionEventsFromClient.java (77%) create mode 100644 superfields/src/main/java/org/vaadin/miki/markers/CanSelectText.java rename superfields/src/main/java/org/vaadin/miki/{superfields/dates => markers}/HasDatePattern.java (87%) rename superfields/src/main/java/org/vaadin/miki/{superfields/dates => markers}/WithDatePatternMixin.java (87%) rename superfields/src/main/java/org/vaadin/miki/{superfields/text => markers}/WithReceivingSelectionEventsFromClientMixin.java (95%) rename superfields/src/main/java/org/vaadin/miki/{superfields => shared}/text/TextSelectionDelegate.java (81%) rename superfields/src/main/java/org/vaadin/miki/superfields/dates/{DatePatternHelper.java => DatePatternDelegate.java} (71%) delete mode 100644 superfields/src/main/java/org/vaadin/miki/superfields/text/CanSelectText.java create mode 100644 superfields/src/test/java/org/vaadin/miki/superfields/dates/DatePatternDelegateTest.java diff --git a/demo-v14/frontend/styles/demo-styles.css b/demo-v14/frontend/styles/demo-styles.css index 5d5642df..e1e9e0d9 100644 --- a/demo-v14/frontend/styles/demo-styles.css +++ b/demo-v14/frontend/styles/demo-styles.css @@ -42,4 +42,27 @@ span.highlighted { font-style: italic; letter-spacing: 1px; color: #004444; -} \ No newline at end of file +} + +.section-layout { + padding-top: 1em; + padding-bottom: 1em; + margin-top: 1em; +} + +.section-header { + font-size: larger; + text-align: center; + font-weight: bold; + letter-spacing: 1px; +} + +.component-header { + text-align: left; +} + +.component-section { + padding: 1em; + margin: 1em; +} + diff --git a/demo-v14/src/main/java/org/vaadin/miki/InfoPage.java b/demo-v14/src/main/java/org/vaadin/miki/InfoPage.java new file mode 100644 index 00000000..5279abd4 --- /dev/null +++ b/demo-v14/src/main/java/org/vaadin/miki/InfoPage.java @@ -0,0 +1,25 @@ +package org.vaadin.miki; + +import com.vaadin.flow.component.html.Anchor; +import com.vaadin.flow.component.html.Span; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; + +/** + * Information about the demo, its organisation and components. + * @author miki + * @since 2020-06-03 + */ +public class InfoPage extends VerticalLayout { + + public InfoPage() { + super( + new Span("Hello and welcome to SuperFields demo! Thank you for your interest in this little project, I hope you find it useful."), + new Span("The components shown in this demo are available in SuperFields, a small collection of handy stuff designed to work with Vaadin 14 and Java."), + new Span("To see a component in action simply select a corresponding tab from above. Each page features the chosen component at the top, followed by (some of) the configurable options."), + new Anchor("https://github.com/vaadin-miki/super-fields", "More information can be found on the project's main page on GitHub."), + new Anchor("https://github.com/vaadin-miki/super-fields/issues", "Please use GitHub to report issues and request features and components."), + new Span("Unless otherwise noted, all code has been written by me (Miki) and is released under Apache 2.0 License.") + ); + } + +} diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainView.java b/demo-v14/src/main/java/org/vaadin/miki/MainView.java index 560a48e3..9f4a3c03 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainView.java +++ b/demo-v14/src/main/java/org/vaadin/miki/MainView.java @@ -6,7 +6,6 @@ import com.vaadin.flow.component.checkbox.Checkbox; import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.dependency.CssImport; -import com.vaadin.flow.component.html.Anchor; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.Paragraph; import com.vaadin.flow.component.html.Span; @@ -26,7 +25,7 @@ import org.vaadin.miki.markers.HasLocale; import org.vaadin.miki.superfields.dates.DatePattern; import org.vaadin.miki.superfields.dates.DatePatterns; -import org.vaadin.miki.superfields.dates.HasDatePattern; +import org.vaadin.miki.markers.HasDatePattern; import org.vaadin.miki.superfields.dates.SuperDatePicker; import org.vaadin.miki.superfields.dates.SuperDateTimePicker; import org.vaadin.miki.superfields.itemgrid.ItemGrid; @@ -41,10 +40,11 @@ import org.vaadin.miki.superfields.tabs.SuperTabs; import org.vaadin.miki.superfields.tabs.TabHandler; import org.vaadin.miki.superfields.tabs.TabHandlers; -import org.vaadin.miki.superfields.text.CanSelectText; +import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; +import org.vaadin.miki.markers.CanSelectText; import org.vaadin.miki.superfields.text.SuperTextArea; import org.vaadin.miki.superfields.text.SuperTextField; -import org.vaadin.miki.superfields.text.TextSelectionNotifier; +import org.vaadin.miki.events.text.TextSelectionNotifier; import org.vaadin.miki.superfields.unload.UnloadObserver; import java.time.LocalDate; @@ -147,11 +147,19 @@ private void buildCanSelectText(Component component, Consumer callb callback.accept(new Component[]{ layout }); + if(component instanceof CanReceiveSelectionEventsFromClient) { + final Checkbox receiveFromClient = new Checkbox("Allow selection events initiated by keyboard or mouse?", + event -> ((CanReceiveSelectionEventsFromClient) component).setReceivingSelectionEventsFromClient(event.getValue())); + callback.accept(new Component[] {receiveFromClient}); + } if(component instanceof TextSelectionNotifier) { final Span selection = new Span(); ((TextSelectionNotifier) component).addTextSelectionListener(event -> selection.setText(event.getSelectedText())); + Icon icon = VaadinIcon.INFO_CIRCLE.create(); + icon.setColor("green"); + icon.getElement().setAttribute("title", "When the component does not receive events from the browser, selection events will only be called for server-side initiated actions."); callback.accept(new Component[]{ - new HorizontalLayout(new Span("You can also select text yourself with keyboard our mouse. Here is the current selection: <"), selection, new Span(">")) + new HorizontalLayout(new Span("Most recently selected text: <"), selection, new Span(">"), icon) }); } } @@ -250,14 +258,32 @@ private void buildSuperTabs(Component component, Consumer callback) } private Component buildContentsFor(Class type) { - VerticalLayout result = new VerticalLayout(); Component component = this.components.get(type); + component.getElement().getClassList().add("demo"); + Div result = new Div(); + result.setSizeUndefined(); + result.addClassName("component-page"); + VerticalLayout componentSection = new VerticalLayout(); + componentSection.setSizeUndefined(); + componentSection.addClassName("component-section"); + Span title = new Span("Demo page of "+component.getClass().getSimpleName()); + title.addClassName("section-header"); + title.addClassName("component-header"); + componentSection.add(title, component); + result.add(componentSection); this.contentBuilders.entrySet().stream(). filter(entry -> entry.getKey().isAssignableFrom(type)). - forEach(entry -> entry.getValue().accept(component, result::add)); - - result.add(component); + forEach(entry -> { + VerticalLayout section = new VerticalLayout(); + section.setSizeUndefined(); + section.addClassName("section-layout"); + Span header = new Span("Configuration options for "+entry.getKey().getSimpleName()); + header.addClassName("section-header"); + section.add(header); + entry.getValue().accept(component, section::add); + result.add(section); + }); return result; } @@ -265,16 +291,6 @@ private void onAnyValueChanged(HasValue.ValueChangeEvent valueChangeEvent) { Notification.show(String.format("%s changed value to %s", valueChangeEvent.getHasValue().getClass().getSimpleName(), valueChangeEvent.getValue())); } - private Component getInfoPage() { - return new VerticalLayout( - new Span("Hello and welcome to SuperFields demo! Thank you for your interest in this little project, I hope you find it useful."), - new Span("The components shown in this demo are available in SuperFields, a small collection of handy stuff designed to work with Vaadin 14 and Java. One day I got tired of repeating the same code over and over again to fix issues that repeat across pretty much every project I coded... and instead of complaining, I decided to fix the problems by releasing this library."), - new Anchor("https://github.com/vaadin-miki/super-fields/issues", "Please use this link to report issues and request features and components."), - new Anchor("https://github.com/vaadin-miki/super-fields", "You can also visit the project's main page on GitHub."), - new Span("Unless otherwise noted, all code has been written by me (Miki) and is released under Apache 2.0 License.") - ); - } - public MainView() { this.components.put(SuperIntegerField.class, new SuperIntegerField("Integer (6 digits):").withMaximumIntegerDigits(6)); this.components.put(SuperLongField.class, new SuperLongField("Long (11 digits):").withMaximumIntegerDigits(11).withId("long")); @@ -282,8 +298,8 @@ public MainView() { this.components.put(SuperBigDecimalField.class, new SuperBigDecimalField("Big decimal (12 + 3 digits):").withMaximumIntegerDigits(12).withMaximumFractionDigits(3).withMinimumFractionDigits(1).withId("big-decimal")); this.components.put(SuperDatePicker.class, new SuperDatePicker("Pick a date:").withDatePattern(DatePatterns.YYYY_MM_DD).withValue(LocalDate.now())); this.components.put(SuperDateTimePicker.class, new SuperDateTimePicker("Pick a date and time:").withDatePattern(DatePatterns.M_D_YYYY_SLASH).withValue(LocalDateTime.now())); - this.components.put(SuperTextField.class, new SuperTextField("Type something:").withPlaceholder("(nothing typed)").withId("super-text-field").withReceivingSelectionEventsFromClient(true)); - this.components.put(SuperTextArea.class, new SuperTextArea("Type a lot of something:").withPlaceholder("(nothing typed)").withId("super-text-area").withReceivingSelectionEventsFromClient(true)); + this.components.put(SuperTextField.class, new SuperTextField("Type something:").withPlaceholder("(nothing typed)").withId("super-text-field")); + this.components.put(SuperTextArea.class, new SuperTextArea("Type a lot of something:").withPlaceholder("(nothing typed)").withId("super-text-area")); this.components.put(SuperTabs.class, new SuperTabs((Supplier) HorizontalLayout::new) .withTabContentGenerator(s -> new Paragraph("Did you know? All SuperFields are "+s)) .withItems("Java friendly", "Super-configurable", "Open source") @@ -321,10 +337,10 @@ public MainView() { }) ); + this.contentBuilders.put(CanSelectText.class, this::buildCanSelectText); + this.contentBuilders.put(HasValue.class, this::buildHasValue); this.contentBuilders.put(AbstractSuperNumberField.class, this::buildAbstractSuperNumberField); this.contentBuilders.put(HasLocale.class, this::buildHasLocale); - this.contentBuilders.put(HasValue.class, this::buildHasValue); - this.contentBuilders.put(CanSelectText.class, this::buildCanSelectText); this.contentBuilders.put(ItemGrid.class, this::buildItemGrid); this.contentBuilders.put(HasDatePattern.class, this::buildHasDatePattern); this.contentBuilders.put(SuperTabs.class, this::buildSuperTabs); @@ -337,13 +353,14 @@ public MainView() { this.afterLocaleChange.put(SuperDoubleField.class, o -> ((SuperDoubleField)o).withMaximumIntegerDigits(8).setMaximumFractionDigits(4)); this.afterLocaleChange.put(SuperBigDecimalField.class, o -> ((SuperBigDecimalField)o).withMaximumIntegerDigits(12).withMaximumFractionDigits(3).setMinimumFractionDigits(1)); - final SuperTabs> tabs = new SuperTabs<>( + final SuperTabs> tabs = new SuperTabs>( type -> new Tab(type.getSimpleName()), - this::buildContentsFor, - this.components.keySet().toArray(new Class[0]) + this::buildContentsFor ); - tabs.addTab(MainView.class, new Tab(new Icon(VaadinIcon.INFO_CIRCLE), new Span("About this demo")), this.getInfoPage()); + tabs.addTab(MainView.class, new Tab(new Icon(VaadinIcon.INFO_CIRCLE), new Span("SuperFields demo")), new InfoPage()); + + tabs.addTab(this.components.keySet().toArray(new Class[0])); this.add(tabs); } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionEvent.java b/superfields/src/main/java/org/vaadin/miki/events/text/TextSelectionEvent.java similarity index 95% rename from superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionEvent.java rename to superfields/src/main/java/org/vaadin/miki/events/text/TextSelectionEvent.java index 13155984..e379a95f 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionEvent.java +++ b/superfields/src/main/java/org/vaadin/miki/events/text/TextSelectionEvent.java @@ -1,7 +1,8 @@ -package org.vaadin.miki.superfields.text; +package org.vaadin.miki.events.text; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.ComponentEvent; +import org.vaadin.miki.markers.CanSelectText; import java.util.Optional; diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionListener.java b/superfields/src/main/java/org/vaadin/miki/events/text/TextSelectionListener.java similarity index 80% rename from superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionListener.java rename to superfields/src/main/java/org/vaadin/miki/events/text/TextSelectionListener.java index 1f007f6d..2275b2c6 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionListener.java +++ b/superfields/src/main/java/org/vaadin/miki/events/text/TextSelectionListener.java @@ -1,7 +1,8 @@ -package org.vaadin.miki.superfields.text; +package org.vaadin.miki.events.text; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.ComponentEventListener; +import org.vaadin.miki.markers.CanSelectText; /** * Marker interface for objects diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionNotifier.java b/superfields/src/main/java/org/vaadin/miki/events/text/TextSelectionNotifier.java similarity index 87% rename from superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionNotifier.java rename to superfields/src/main/java/org/vaadin/miki/events/text/TextSelectionNotifier.java index 97d3e3f7..d92887e8 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionNotifier.java +++ b/superfields/src/main/java/org/vaadin/miki/events/text/TextSelectionNotifier.java @@ -1,7 +1,8 @@ -package org.vaadin.miki.superfields.text; +package org.vaadin.miki.events.text; import com.vaadin.flow.component.Component; import com.vaadin.flow.shared.Registration; +import org.vaadin.miki.markers.CanSelectText; /** * Marker interface for objects that broadcast {@link TextSelectionEvent}. diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/CanReceiveSelectionEventsFromClient.java b/superfields/src/main/java/org/vaadin/miki/markers/CanReceiveSelectionEventsFromClient.java similarity index 77% rename from superfields/src/main/java/org/vaadin/miki/superfields/text/CanReceiveSelectionEventsFromClient.java rename to superfields/src/main/java/org/vaadin/miki/markers/CanReceiveSelectionEventsFromClient.java index 489ae517..2a1b468d 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/text/CanReceiveSelectionEventsFromClient.java +++ b/superfields/src/main/java/org/vaadin/miki/markers/CanReceiveSelectionEventsFromClient.java @@ -1,5 +1,12 @@ -package org.vaadin.miki.superfields.text; +package org.vaadin.miki.markers; +import org.vaadin.miki.events.text.TextSelectionEvent; + +/** + * Marker interface for objects capable of receiving text selection events from client-side code. + * @author miki + * @since 2020-06-04 + */ public interface CanReceiveSelectionEventsFromClient { /** * Check if client will inform server on selection change. diff --git a/superfields/src/main/java/org/vaadin/miki/markers/CanSelectText.java b/superfields/src/main/java/org/vaadin/miki/markers/CanSelectText.java new file mode 100644 index 00000000..22aa17a2 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/markers/CanSelectText.java @@ -0,0 +1,30 @@ +package org.vaadin.miki.markers; + +import com.vaadin.flow.component.HasElement; + +/** + * Marker interface for components that can select text. + * What selecting text means and how it is done is left to the implementations. + * @author miki + * @since 2020-05-29 + */ +public interface CanSelectText extends HasElement { + + /** + * Selects entire text in the component. + */ + void selectAll(); + + /** + * Removes the current selection and selects no text. + */ + void selectNone(); + + /** + * Selects text starting from index {@code from} (inclusive) and ending at index {@code to} (exclusive). + * @param from Starting index (inclusive). + * @param to Ending index (exclusive). + */ + void select(int from, int to); + +} diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/HasDatePattern.java b/superfields/src/main/java/org/vaadin/miki/markers/HasDatePattern.java similarity index 87% rename from superfields/src/main/java/org/vaadin/miki/superfields/dates/HasDatePattern.java rename to superfields/src/main/java/org/vaadin/miki/markers/HasDatePattern.java index 9f30ad1f..489d28a1 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/HasDatePattern.java +++ b/superfields/src/main/java/org/vaadin/miki/markers/HasDatePattern.java @@ -1,4 +1,6 @@ -package org.vaadin.miki.superfields.dates; +package org.vaadin.miki.markers; + +import org.vaadin.miki.superfields.dates.DatePattern; /** * Marker interface for objects that have a {@link DatePattern}. diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/WithDatePatternMixin.java b/superfields/src/main/java/org/vaadin/miki/markers/WithDatePatternMixin.java similarity index 87% rename from superfields/src/main/java/org/vaadin/miki/superfields/dates/WithDatePatternMixin.java rename to superfields/src/main/java/org/vaadin/miki/markers/WithDatePatternMixin.java index 43154506..86ed73dd 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/WithDatePatternMixin.java +++ b/superfields/src/main/java/org/vaadin/miki/markers/WithDatePatternMixin.java @@ -1,4 +1,6 @@ -package org.vaadin.miki.superfields.dates; +package org.vaadin.miki.markers; + +import org.vaadin.miki.superfields.dates.DatePattern; /** * Mixin interface to allow chaining {@link #setDatePattern(DatePattern)}. diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/WithReceivingSelectionEventsFromClientMixin.java b/superfields/src/main/java/org/vaadin/miki/markers/WithReceivingSelectionEventsFromClientMixin.java similarity index 95% rename from superfields/src/main/java/org/vaadin/miki/superfields/text/WithReceivingSelectionEventsFromClientMixin.java rename to superfields/src/main/java/org/vaadin/miki/markers/WithReceivingSelectionEventsFromClientMixin.java index cb9fbde0..7e7e2dcb 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/text/WithReceivingSelectionEventsFromClientMixin.java +++ b/superfields/src/main/java/org/vaadin/miki/markers/WithReceivingSelectionEventsFromClientMixin.java @@ -1,4 +1,4 @@ -package org.vaadin.miki.superfields.text; +package org.vaadin.miki.markers; /** * Marker interface for chaining {@link #setReceivingSelectionEventsFromClient(boolean)}. diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionDelegate.java b/superfields/src/main/java/org/vaadin/miki/shared/text/TextSelectionDelegate.java similarity index 81% rename from superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionDelegate.java rename to superfields/src/main/java/org/vaadin/miki/shared/text/TextSelectionDelegate.java index 01346f61..6b96f197 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/text/TextSelectionDelegate.java +++ b/superfields/src/main/java/org/vaadin/miki/shared/text/TextSelectionDelegate.java @@ -1,7 +1,10 @@ -package org.vaadin.miki.superfields.text; +package org.vaadin.miki.shared.text; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.ComponentEventBus; +import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; +import org.vaadin.miki.markers.CanSelectText; +import org.vaadin.miki.events.text.TextSelectionEvent; import java.io.Serializable; import java.util.Objects; @@ -9,12 +12,12 @@ import java.util.function.Supplier; /** - * Internal class that handles common behaviour related to text selection. - * Note: this is for internal use only. + * A class that handles common behaviour related to text selection. + * This assumes that the client-side component mixes in {@code text-selection-mikin.js}. * @author miki * @since 2020-06-01 */ -class TextSelectionDelegate implements Serializable { +public class TextSelectionDelegate implements Serializable { /** * Defines the name of the HTML attribute that contains the selected text. @@ -27,7 +30,7 @@ class TextSelectionDelegate ui.beforeClientResponse(this.source, context -> this.source.getElement().callJsFunction( "setCallingServer", @@ -49,7 +52,7 @@ protected void informClientAboutSendingEvents(boolean value) { * @param eventBus Event bus. * @param event Event with information about text selection. */ - protected void fireTextSelectionEvent(ComponentEventBus eventBus, TextSelectionEvent event) { + public void fireTextSelectionEvent(ComponentEventBus eventBus, TextSelectionEvent event) { eventBus.fireEvent(event); } @@ -63,7 +66,7 @@ private void selectionChanged(ComponentEventBus eventBus, int start, int end, St * @param valueSupplier Way of getting current value. Needed if no client notifications. * @param eventBusSupplier Way of getting event bus. Needed if no client notifications. */ - void selectAll(Supplier valueSupplier, Supplier eventBusSupplier) { + public void selectAll(Supplier valueSupplier, Supplier eventBusSupplier) { this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> this.source.getElement().callJsFunction("selectAll", this.source.getElement()) )); @@ -79,7 +82,7 @@ void selectAll(Supplier valueSupplier, Supplier event * Selects no text. * @param eventBusSupplier Way of getting event bus. Needed if no client notifications. */ - void selectNone(Supplier eventBusSupplier) { + public void selectNone(Supplier eventBusSupplier) { this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> this.source.getElement().callJsFunction("selectNone", this.source.getElement()) )); @@ -97,7 +100,7 @@ void selectNone(Supplier eventBusSupplier) { * @param from Selection starting index, inclusive. * @param to Selection end index, exclusive. */ - void select(Supplier valueSupplier, Supplier eventBusSupplier, int from, int to) { + public void select(Supplier valueSupplier, Supplier eventBusSupplier, int from, int to) { if(from <= to) this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> this.source.getElement().callJsFunction("select", this.source.getElement(), from, to) @@ -115,7 +118,7 @@ void select(Supplier valueSupplier, Supplier eventBus * Does nothing if the component is receiving client-side notifications. * @param eventBusSupplier Way of getting event bus. */ - void updateAttributeOnValueChange(Supplier eventBusSupplier) { + public void updateAttributeOnValueChange(Supplier eventBusSupplier) { // special case here: if there was selection, no client-side events are caught and value is set, event must be fired if(!this.source.isReceivingSelectionEventsFromClient()) { final String lastSelected = Optional.ofNullable(this.source.getElement().getAttribute(SELECTED_TEXT_ATTRIBUTE_NAME)).orElse(""); diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternHelper.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternDelegate.java similarity index 71% rename from superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternHelper.java rename to superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternDelegate.java index 556cd364..6a0ba097 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternHelper.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternDelegate.java @@ -2,15 +2,21 @@ import com.vaadin.flow.component.AttachEvent; import com.vaadin.flow.component.Component; +import org.vaadin.miki.markers.HasDatePattern; + +import java.io.Serializable; +import java.time.LocalDate; /** - * Helper class that calls a method on a client side. + * Helper class that contains code related handling date patterns. * Internal use only. * * @author miki * @since 2020-05-02 */ -final class DatePatternHelper { +final class DatePatternDelegate implements Serializable { + + private static final long serialVersionUID = 20200506L; /** * Returns the pattern descriptor string expected by the client-side code. @@ -60,7 +66,7 @@ private static String convertDatePatternToClientPattern(DatePattern pattern) { * The client-side representation should have mixed in methods from {@code date-pattern-mixin.js}. * @param source Source to use. */ - DatePatternHelper(C source) { + DatePatternDelegate(C source) { this.source = source; this.source.addAttachListener(this::onAttached); } @@ -97,4 +103,27 @@ protected void updateClientSidePattern() { )); } + private int[] getDayMonthYearPositions(DatePattern.Order order) { + if(order == DatePattern.Order.DAY_MONTH_YEAR) + return new int[]{0, 1, 2}; + else if(order == DatePattern.Order.MONTH_DAY_YEAR) + return new int[]{1, 0, 2}; + else return new int[]{2, 1, 0}; + } + + /** + * Formats the date according to the pattern present in the source. + * @param date Date to format. Must not be {@code null}. + * @return Formatted date. + */ + String formatDate(LocalDate date) { + final DatePattern pattern = this.source.getDatePattern(); + final String[] parts = new String[3]; + final int[] indices = this.getDayMonthYearPositions(pattern.getDisplayOrder()); + parts[indices[0]] = pattern.isZeroPrefixedDay() ? String.format("%02d", date.getDayOfMonth()) : String.valueOf(date.getDayOfMonth()); + parts[indices[1]] = pattern.isZeroPrefixedMonth() ? String.format("%02d", date.getMonthValue()) : String.valueOf(date.getMonthValue()); + parts[indices[2]] = pattern.isShortYear() ? String.format("%02d", date.getYear() % 100) : String.valueOf(date.getYear()); + return String.join(String.valueOf(pattern.getSeparator()), parts); + } + } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java index 5438901a..e286e8b5 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java @@ -1,19 +1,34 @@ package org.vaadin.miki.superfields.dates; import com.vaadin.flow.component.AbstractField; +import com.vaadin.flow.component.AttachEvent; +import com.vaadin.flow.component.ClientCallable; +import com.vaadin.flow.component.DetachEvent; import com.vaadin.flow.component.Tag; import com.vaadin.flow.component.datepicker.DatePicker; import com.vaadin.flow.component.dependency.JsModule; +import com.vaadin.flow.shared.Registration; +import org.vaadin.miki.markers.HasDatePattern; import org.vaadin.miki.markers.HasLabel; import org.vaadin.miki.markers.HasLocale; import org.vaadin.miki.markers.HasPlaceholder; +import org.vaadin.miki.markers.WithDatePatternMixin; import org.vaadin.miki.markers.WithIdMixin; import org.vaadin.miki.markers.WithLabelMixin; import org.vaadin.miki.markers.WithLocaleMixin; import org.vaadin.miki.markers.WithPlaceholderMixin; import org.vaadin.miki.markers.WithValueMixin; +import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; +import org.vaadin.miki.markers.CanSelectText; +import org.vaadin.miki.shared.text.TextSelectionDelegate; +import org.vaadin.miki.events.text.TextSelectionEvent; +import org.vaadin.miki.events.text.TextSelectionListener; +import org.vaadin.miki.events.text.TextSelectionNotifier; +import org.vaadin.miki.markers.WithReceivingSelectionEventsFromClientMixin; import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; import java.util.Locale; /** @@ -26,12 +41,18 @@ @SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes public class SuperDatePicker extends DatePicker implements HasLocale, HasLabel, HasPlaceholder, HasDatePattern, + CanSelectText, CanReceiveSelectionEventsFromClient, WithReceivingSelectionEventsFromClientMixin, + TextSelectionNotifier, WithLocaleMixin, WithLabelMixin, WithPlaceholderMixin, WithDatePatternMixin, WithValueMixin, LocalDate, SuperDatePicker>, WithIdMixin { - private final DatePatternHelper delegate = new DatePatternHelper<>(this); + private final DatePatternDelegate datePatternDelegate = new DatePatternDelegate<>(this); + + private final TextSelectionDelegate textSelectionDelegate = new TextSelectionDelegate<>(this); + + private boolean receivingClientSideSelectionEvent = false; private DatePattern datePattern; @@ -88,8 +109,8 @@ public SuperDatePicker(LocalDate initialDate, Locale locale) { public final void setLocale(Locale locale) { // there is a call for setting locale from the superclass' constructor // and when that happens, the field is not yet initialised - if(this.delegate != null) { - this.delegate.initPatternSetting(); + if(this.datePatternDelegate != null) { + this.datePatternDelegate.initPatternSetting(); SuperDatePickerI18nHelper.updateI18N(locale, this::getI18n, this::setI18n); } super.setLocale(locale); @@ -98,11 +119,83 @@ public final void setLocale(Locale locale) { @Override public void setDatePattern(DatePattern datePattern) { this.datePattern = datePattern; - this.delegate.updateClientSidePattern(); + this.datePatternDelegate.updateClientSidePattern(); } @Override public DatePattern getDatePattern() { return this.datePattern; } + + @Override + public void setValue(LocalDate value) { + this.textSelectionDelegate.updateAttributeOnValueChange(this::getEventBus); + super.setValue(value); + } + + @Override + protected void onAttach(AttachEvent attachEvent) { + this.textSelectionDelegate.informClientAboutSendingEvents(this.isReceivingSelectionEventsFromClient()); + super.onAttach(attachEvent); + } + + @Override + protected void onDetach(DetachEvent detachEvent) { + // detaching means server should not be informed + if(this.isReceivingSelectionEventsFromClient()) + this.textSelectionDelegate.informClientAboutSendingEvents(false); + super.onDetach(detachEvent); + } + + @ClientCallable + private void selectionChanged(int start, int end, String selection) { + TextSelectionEvent event = new TextSelectionEvent<>(this, true, start, end, selection); + this.textSelectionDelegate.fireTextSelectionEvent(this.getEventBus(), event); + } + + @Override + public boolean isReceivingSelectionEventsFromClient() { + return this.receivingClientSideSelectionEvent; + } + + @Override + public void setReceivingSelectionEventsFromClient(boolean receivingSelectionEventsFromClient) { + this.receivingClientSideSelectionEvent = receivingSelectionEventsFromClient; + this.textSelectionDelegate.informClientAboutSendingEvents(receivingSelectionEventsFromClient); + } + + /** + * Returns the current value formatted with current locale or pattern. + * @return Current date, formatted. Will return {@code null} if the current date is {@code null}. + */ + public String getFormattedValue() { + final LocalDate value = this.getValue(); + if(value == null) + return null; + else if(this.getDatePattern() == null) + return value.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(this.getLocale())); + else + return this.datePatternDelegate.formatDate(value); + } + + @Override + public void selectAll() { + this.textSelectionDelegate.selectAll(this::getFormattedValue, this::getEventBus); + } + + @Override + public void selectNone() { + this.textSelectionDelegate.selectNone(this::getEventBus); + } + + @Override + public void select(int from, int to) { + this.textSelectionDelegate.select(this::getFormattedValue, this::getEventBus, from, to); + } + + @Override + @SuppressWarnings("unchecked") + public Registration addTextSelectionListener(TextSelectionListener listener) { + return this.getEventBus().addListener((Class>)(Class)TextSelectionEvent.class, listener); + } } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java index b71f3764..9c00cbd5 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java @@ -6,8 +6,10 @@ import com.vaadin.flow.component.datetimepicker.DateTimePicker; import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.timepicker.TimePicker; +import org.vaadin.miki.markers.HasDatePattern; import org.vaadin.miki.markers.HasLabel; import org.vaadin.miki.markers.HasLocale; +import org.vaadin.miki.markers.WithDatePatternMixin; import org.vaadin.miki.markers.WithIdMixin; import org.vaadin.miki.markers.WithLabelMixin; import org.vaadin.miki.markers.WithLocaleMixin; @@ -29,7 +31,7 @@ public class SuperDateTimePicker extends DateTimePicker implements HasLocale, HasLabel, HasDatePattern, WithLocaleMixin, WithLabelMixin, - WithDatePatternMixin, WithIdMixin, + WithDatePatternMixin, WithIdMixin, WithValueMixin, LocalDateTime, SuperDateTimePicker> { // so, this component is a composition of DatePicker and TimePicker @@ -37,7 +39,7 @@ public class SuperDateTimePicker extends DateTimePicker private static final String INTERNAL_DATE_PICKER_FIELD_NAME = "datePicker"; private static final String INTERNAL_TIME_PICKER_FIELD_NAME = "timePicker"; - private final DatePatternHelper delegate = new DatePatternHelper<>(this); + private final DatePatternDelegate delegate = new DatePatternDelegate<>(this); private DatePattern datePattern; diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java index 9bd8617b..2ebdd3f5 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java @@ -10,6 +10,7 @@ import com.vaadin.flow.component.textfield.TextFieldVariant; import com.vaadin.flow.function.SerializableFunction; import com.vaadin.flow.function.SerializablePredicate; +import com.vaadin.flow.shared.Registration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.vaadin.miki.markers.HasLabel; @@ -22,6 +23,13 @@ import org.vaadin.miki.markers.WithPlaceholderMixin; import org.vaadin.miki.markers.WithTitleMixin; import org.vaadin.miki.markers.WithValueMixin; +import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; +import org.vaadin.miki.markers.CanSelectText; +import org.vaadin.miki.superfields.text.SuperTextField; +import org.vaadin.miki.events.text.TextSelectionEvent; +import org.vaadin.miki.events.text.TextSelectionListener; +import org.vaadin.miki.events.text.TextSelectionNotifier; +import org.vaadin.miki.markers.WithReceivingSelectionEventsFromClientMixin; import java.text.DecimalFormat; import java.text.NumberFormat; @@ -38,7 +46,9 @@ */ public abstract class AbstractSuperNumberField> extends CustomField - implements HasPrefixAndSuffix, HasLabel, HasPlaceholder, HasTitle, HasLocale, + implements CanSelectText, CanReceiveSelectionEventsFromClient, WithReceivingSelectionEventsFromClientMixin, + TextSelectionNotifier, + HasPrefixAndSuffix, HasLabel, HasPlaceholder, HasTitle, HasLocale, WithLocaleMixin, WithLabelMixin, WithPlaceholderMixin, WithTitleMixin, WithValueMixin, T>, T, SELF>, WithIdMixin { @@ -68,7 +78,7 @@ public abstract class AbstractSuperNumberField nega this.field.addFocusListener(this::onFieldSelected); this.field.addBlurListener(this::onFieldBlurred); + this.field.addTextSelectionListener(this::onTextSelected); } private static String escapeDot(char character) { @@ -565,6 +576,50 @@ public boolean isInvalid() { return this.field.isInvalid(); } + @Override + public void select(int from, int to) { + this.field.select(from, to); + } + + @Override + public void selectAll() { + this.field.selectAll(); + } + + @Override + public void selectNone() { + this.field.selectNone(); + } + + @SuppressWarnings("unchecked") + private void onTextSelected(TextSelectionEvent event) { + final TextSelectionEvent selfEvent = new TextSelectionEvent<>((SELF)this, event.isFromClient(), event.getSelectionStart(), event.getSelectionEnd(), event.getSelectedText()); + this.getEventBus().fireEvent(selfEvent); + } + + @Override + public void setReceivingSelectionEventsFromClient(boolean receivingSelectionEventsFromClient) { + this.field.setReceivingSelectionEventsFromClient(receivingSelectionEventsFromClient); + } + + @Override + public boolean isReceivingSelectionEventsFromClient() { + return this.field.isReceivingSelectionEventsFromClient(); + } + + @Override + @SuppressWarnings("unchecked") + public Registration addTextSelectionListener(TextSelectionListener listener) { + return this.getEventBus().addListener((Class>)(Class)TextSelectionEvent.class, listener); + } + + @Override + @SuppressWarnings("unchecked") + public SELF withReceivingSelectionEventsFromClient(boolean receivingSelectionEventsFromClient) { + this.setReceivingSelectionEventsFromClient(receivingSelectionEventsFromClient); + return (SELF)this; + } + /** * Explicitly invokes code that would otherwise be called when the component receives focus. * For testing purposes only. diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/CanSelectText.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/CanSelectText.java deleted file mode 100644 index 11604944..00000000 --- a/superfields/src/main/java/org/vaadin/miki/superfields/text/CanSelectText.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.vaadin.miki.superfields.text; - -import com.vaadin.flow.component.HasElement; - -/** - * Marker interface for components that can select text. - * Handles selection using client-side JavaScript. - * @author miki - * @since 2020-05-29 - */ -public interface CanSelectText extends HasElement { - - void selectAll(); - - void selectNone(); - - void select(int from, int to); - -} diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java index 026d2980..4127224b 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java @@ -1,17 +1,25 @@ package org.vaadin.miki.superfields.text; import com.vaadin.flow.component.AbstractField; +import com.vaadin.flow.component.AttachEvent; import com.vaadin.flow.component.ClientCallable; +import com.vaadin.flow.component.DetachEvent; import com.vaadin.flow.component.Tag; import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.textfield.TextArea; import com.vaadin.flow.shared.Registration; +import org.vaadin.miki.events.text.TextSelectionEvent; +import org.vaadin.miki.events.text.TextSelectionListener; +import org.vaadin.miki.events.text.TextSelectionNotifier; +import org.vaadin.miki.markers.CanSelectText; import org.vaadin.miki.markers.HasLabel; import org.vaadin.miki.markers.HasPlaceholder; import org.vaadin.miki.markers.WithIdMixin; import org.vaadin.miki.markers.WithLabelMixin; import org.vaadin.miki.markers.WithPlaceholderMixin; +import org.vaadin.miki.markers.WithReceivingSelectionEventsFromClientMixin; import org.vaadin.miki.markers.WithValueMixin; +import org.vaadin.miki.shared.text.TextSelectionDelegate; /** * An extension of {@link TextArea} with some useful features. @@ -57,6 +65,21 @@ public SuperTextArea(String label, String initialValue, ValueChangeListener & CanReceiveSelectionEventsFromClient & TextSelectionNotifier> { From df8cdf5c427e3091b909cb20398f87236421dd1f Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 5 Jun 2020 13:38:52 +0300 Subject: [PATCH 18/66] #139 done (#144) --- superfields/README.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/superfields/README.md b/superfields/README.md index b7c681be..b61629ea 100644 --- a/superfields/README.md +++ b/superfields/README.md @@ -6,7 +6,9 @@ Source code for the app and for the components can be found at https://github.co # SuperFields -All SuperFields are Java-friendly. There is as little client-side code as possible ;) +All SuperFields are Java-friendly. There is as little client-side code as possible ;) In addition to that, any client-side code is considered **implementation detail** and may change at any time. + +#### Fluid API All SuperFields feature fluid API (or method chaining), at least to some extent. For example, instead of doing: @@ -18,10 +20,18 @@ All SuperFields feature fluid API (or method chaining), at least to some extent. you can do a magic one-liner: `new SuperDatePicker().withId("super-date-picker").withValue(LocalDate.today())`. +#### Text selection + +Some components contain server-side methods to control text selection in their web component part. In addition, they can optionally listen to text-selection events happening in the browser and broadcast them to the server. + +The web components listen to each key press and mouse click. If text selection changes as a result of that action, they send an event to the server-side component. This may happen quite often and increase server load, so the feature is turned off by default. To turn it on simply call `setReceivingSelectionEventsFromClient(true)` (or `withReceivingSelectionEventsFromClient(true)`). + ## Number fields None of the number fields support range checking, so if you allow too many digits, overflows will occur. +All number fields support text selection API. + ### `SuperDoubleField` and `SuperBigDecimalField` An input field for entering localised `Double` and `BigDecimal` numbers. Supports thousands (grouping) separators for the integer part and optional decimal separator. @@ -30,6 +40,12 @@ An input field for entering localised `Double` and `BigDecimal` numbers. Support An input field for entering localised `Integer` and `Long` numbers. Supports thousands (grouping) separators. +## Text fields + +### `SuperTextField` and `SuperTextArea` + +These are the same components as their Vaadin counterparts, except they fully support text selection API. This means that the text contained in the components can be selected from server-side code and that changes to selection in the browser are sent to the server as events. + ## Date fields ### `SuperDatePicker` and `SuperDateTimePicker` @@ -38,7 +54,9 @@ Fully localised `DatePicker` and `DateTimePicker` that fetch month names and wee In addition to the above, both components allow setting custom date display pattern. This pattern should survive setting locale or i18n object, so keep that in mind. -Both components behave funky when changing locale at runtime if their calendars were already shown. That is mostly due to some weird caching on the client side and is also a Vaadin bug. +Both components behave funky when changing locale at runtime if their calendars were already shown. That is mostly due to some weird caching on the client side and is also a Vaadin bug. + +**Please note:** only `SuperDatePicker` has support for text selection API. ## Select fields @@ -76,4 +94,6 @@ A boolean field that changes its value (`true` or `false`) depending on whether A component that listens and reacts to browser's `beforeunload` events that happen for example when browser window/tab is closed. The support [varies between browsers](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event), but in general is quite good. This should work with at least the major browsers. +**Please note**: This component is a singleton - there can be only one instance of it. As such, please refrain from adding the same instance into multiple layouts. + The code is based on solution [posted by Kaspar Scherrer and Stuart Robinson](https://vaadin.com/forum/thread/17523194/unsaved-changes-detect-page-exit-or-reload). It does not work with `` or `Anchor` as download links, so please use [FileDownloadWrapper](https://vaadin.com/directory/component/file-download-wrapper/discussions) for that. From 292cf82fc1d498acf98ce97cca3d7badf102b1f1 Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 5 Jun 2020 15:13:02 +0300 Subject: [PATCH 19/66] #143 done (#145) TextSelectionDelegate is now really a delegate --- .../vaadin/miki/markers/CanSelectText.java | 4 +- .../shared/text/TextSelectionDelegate.java | 172 ++++++++++++------ .../superfields/dates/SuperDatePicker.java | 46 ++--- .../numbers/AbstractSuperNumberField.java | 2 +- .../miki/superfields/text/SuperTextArea.java | 36 +--- .../miki/superfields/text/SuperTextField.java | 35 +--- 6 files changed, 150 insertions(+), 145 deletions(-) diff --git a/superfields/src/main/java/org/vaadin/miki/markers/CanSelectText.java b/superfields/src/main/java/org/vaadin/miki/markers/CanSelectText.java index 22aa17a2..26dcd267 100644 --- a/superfields/src/main/java/org/vaadin/miki/markers/CanSelectText.java +++ b/superfields/src/main/java/org/vaadin/miki/markers/CanSelectText.java @@ -1,14 +1,12 @@ package org.vaadin.miki.markers; -import com.vaadin.flow.component.HasElement; - /** * Marker interface for components that can select text. * What selecting text means and how it is done is left to the implementations. * @author miki * @since 2020-05-29 */ -public interface CanSelectText extends HasElement { +public interface CanSelectText { /** * Selects entire text in the component. diff --git a/superfields/src/main/java/org/vaadin/miki/shared/text/TextSelectionDelegate.java b/superfields/src/main/java/org/vaadin/miki/shared/text/TextSelectionDelegate.java index 6b96f197..b004f55e 100644 --- a/superfields/src/main/java/org/vaadin/miki/shared/text/TextSelectionDelegate.java +++ b/superfields/src/main/java/org/vaadin/miki/shared/text/TextSelectionDelegate.java @@ -1,23 +1,39 @@ package org.vaadin.miki.shared.text; +import com.vaadin.flow.component.AttachEvent; import com.vaadin.flow.component.Component; import com.vaadin.flow.component.ComponentEventBus; +import com.vaadin.flow.component.DetachEvent; +import com.vaadin.flow.component.HasValue; +import com.vaadin.flow.dom.Element; +import com.vaadin.flow.function.SerializableSupplier; +import com.vaadin.flow.shared.Registration; +import org.vaadin.miki.events.text.TextSelectionEvent; +import org.vaadin.miki.events.text.TextSelectionListener; +import org.vaadin.miki.events.text.TextSelectionNotifier; import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; import org.vaadin.miki.markers.CanSelectText; -import org.vaadin.miki.events.text.TextSelectionEvent; import java.io.Serializable; import java.util.Objects; import java.util.Optional; -import java.util.function.Supplier; +import java.util.function.Consumer; /** - * A class that handles common behaviour related to text selection. - * This assumes that the client-side component mixes in {@code text-selection-mikin.js}. + * A class that handles common behaviour related to text selection. This is mostly for internal use. + * + * There are a lot of steps that need to be taken care of to integrate this with any component. Please check project's wiki. + * The methods {@code onAttach onDetach} must be overwritten in the delegating class and delegated here. + * The source component must implement {@link CanSelectText} and {@link CanReceiveSelectionEventsFromClient} and delegate them + * to this object. + * The client-side component must mix in {@code text-selection-mixin.js} or otherwise react to needed JS method calls. + * Finally, the delegating class must implement a method {@code @ClientCallable void selectionChanged(int, int, String)}. + * * @author miki * @since 2020-06-01 */ -public class TextSelectionDelegate implements Serializable { +public class TextSelectionDelegate + implements Serializable, CanSelectText, CanReceiveSelectionEventsFromClient, TextSelectionNotifier { /** * Defines the name of the HTML attribute that contains the selected text. @@ -25,13 +41,28 @@ public class TextSelectionDelegate stringValueSupplier; + + private boolean receivingSelectionEventsFromClient = false; /** * Creates the delegate for a given component. * @param source Source of all events, data, etc. + * @param eventBus Event bus to use for firing events. Typically, {@code source.getEventBus()}. + * @param stringValueSupplier Method to obtain current value of the component as a {@link String}. */ - public TextSelectionDelegate(C source) { + public TextSelectionDelegate(C source, ComponentEventBus eventBus, SerializableSupplier stringValueSupplier) { this.source = source; + this.sourceElement = source.getElement(); + this.eventBus = eventBus; + this.stringValueSupplier = stringValueSupplier; + if(source instanceof HasValue) + ((HasValue) source).addValueChangeListener(event -> this.clearSelectionOnValueChange()); } /** @@ -39,8 +70,8 @@ public TextSelectionDelegate(C source) { * @param value When {@code true}, client-side will notify server about changes in text selection. */ public void informClientAboutSendingEvents(boolean value) { - this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> - this.source.getElement().callJsFunction( + this.sourceElement.getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> + this.sourceElement.callJsFunction( "setCallingServer", value ) @@ -49,83 +80,106 @@ public void informClientAboutSendingEvents(boolean value) { /** * Fires text selection event. - * @param eventBus Event bus. - * @param event Event with information about text selection. + * @param fromClient Whether or not the event originates from the client. + * @param start Selection start. + * @param end Selection end. + * @param text Selection text. */ - public void fireTextSelectionEvent(ComponentEventBus eventBus, TextSelectionEvent event) { - eventBus.fireEvent(event); + public void fireTextSelectionEvent(boolean fromClient, int start, int end, String text) { + TextSelectionEvent event = new TextSelectionEvent<>(this.source, fromClient, start, end, text); + this.eventBus.fireEvent(event); } - private void selectionChanged(ComponentEventBus eventBus, int start, int end, String selection) { - TextSelectionEvent event = new TextSelectionEvent<>(this.source, true, start, end, selection); - this.fireTextSelectionEvent(eventBus, event); - } - - /** - * Selects all text. - * @param valueSupplier Way of getting current value. Needed if no client notifications. - * @param eventBusSupplier Way of getting event bus. Needed if no client notifications. - */ - public void selectAll(Supplier valueSupplier, Supplier eventBusSupplier) { - this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> - this.source.getElement().callJsFunction("selectAll", this.source.getElement()) + @Override + public void selectAll() { + this.sourceElement.getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> + this.sourceElement.callJsFunction("selectAll", this.source.getElement()) )); // send event if the client is not doing it - if(!this.source.isReceivingSelectionEventsFromClient()) { - final String value = valueSupplier.get(); - this.source.getElement().setAttribute(SELECTED_TEXT_ATTRIBUTE_NAME, value); - this.selectionChanged(eventBusSupplier.get(), 0, value.length(), value); + if(!this.isReceivingSelectionEventsFromClient()) { + final String value = this.stringValueSupplier.get(); + this.sourceElement.setAttribute(SELECTED_TEXT_ATTRIBUTE_NAME, value); + this.fireTextSelectionEvent(false, 0, value.length(), value); } } - /** - * Selects no text. - * @param eventBusSupplier Way of getting event bus. Needed if no client notifications. - */ - public void selectNone(Supplier eventBusSupplier) { - this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> - this.source.getElement().callJsFunction("selectNone", this.source.getElement()) + @Override + public void selectNone() { + this.sourceElement.getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> + this.sourceElement.callJsFunction("selectNone", this.source.getElement()) )); // send event if the client is not doing it - if(!this.source.isReceivingSelectionEventsFromClient()) { - this.source.getElement().setAttribute(SELECTED_TEXT_ATTRIBUTE_NAME, ""); - this.selectionChanged(eventBusSupplier.get(), -1, -1, ""); + if(!this.isReceivingSelectionEventsFromClient()) { + this.sourceElement.setAttribute(SELECTED_TEXT_ATTRIBUTE_NAME, ""); + this.fireTextSelectionEvent(false, -1, -1, ""); } } - /** - * Selects some text. - * @param valueSupplier Way of getting current value. Needed if no client notifications. - * @param eventBusSupplier Way of getting event bus. Needed if no client notifications. - * @param from Selection starting index, inclusive. - * @param to Selection end index, exclusive. - */ - public void select(Supplier valueSupplier, Supplier eventBusSupplier, int from, int to) { + + @Override + public void select(int from, int to) { if(from <= to) - this.source.getElement().getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> - this.source.getElement().callJsFunction("select", this.source.getElement(), from, to) + this.sourceElement.getNode().runWhenAttached(ui -> ui.beforeClientResponse(this.source, context -> + this.sourceElement.callJsFunction("select", this.source.getElement(), from, to) )); // send event if the client is not doing it - if(!this.source.isReceivingSelectionEventsFromClient()) { - final String value = valueSupplier.get().substring(from, to); - this.source.getElement().setAttribute(SELECTED_TEXT_ATTRIBUTE_NAME, value); - this.selectionChanged(eventBusSupplier.get(), from, to, value); + if(!this.isReceivingSelectionEventsFromClient()) { + final String value = this.stringValueSupplier.get().substring(from, to); + this.sourceElement.setAttribute(SELECTED_TEXT_ATTRIBUTE_NAME, value); + this.fireTextSelectionEvent(false, from, to, value); } } /** * Handles selection change on value change if there are no client notifications. * Does nothing if the component is receiving client-side notifications. - * @param eventBusSupplier Way of getting event bus. */ - public void updateAttributeOnValueChange(Supplier eventBusSupplier) { + public void clearSelectionOnValueChange() { // special case here: if there was selection, no client-side events are caught and value is set, event must be fired - if(!this.source.isReceivingSelectionEventsFromClient()) { - final String lastSelected = Optional.ofNullable(this.source.getElement().getAttribute(SELECTED_TEXT_ATTRIBUTE_NAME)).orElse(""); - this.source.getElement().setAttribute(SELECTED_TEXT_ATTRIBUTE_NAME, ""); + if(!this.isReceivingSelectionEventsFromClient()) { + final String lastSelected = Optional.ofNullable(this.sourceElement.getAttribute(SELECTED_TEXT_ATTRIBUTE_NAME)).orElse(""); + this.sourceElement.setAttribute(SELECTED_TEXT_ATTRIBUTE_NAME, ""); if(!Objects.equals(lastSelected, "")) - this.fireTextSelectionEvent(eventBusSupplier.get(), new TextSelectionEvent<>(this.source, false, -1, -1, "")); + this.fireTextSelectionEvent(false, -1, -1, ""); } } + /** + * Informs client about sending events and calls the original method. + * @param event Event. + * @param originalMethod Method to call. Must not be {@code null}. + */ + public void onAttach(AttachEvent event, Consumer originalMethod) { + this.informClientAboutSendingEvents(this.isReceivingSelectionEventsFromClient()); + originalMethod.accept(event); + } + + /** + * Informs client to not send events (if needed) and calls the original method. + * @param event Event. + * @param originalMethod Method to call. Must not be {@code null}. + */ + public void onDetach(DetachEvent event, Consumer originalMethod) { + // detaching means server should not be informed + if(this.isReceivingSelectionEventsFromClient()) + this.informClientAboutSendingEvents(false); + originalMethod.accept(event); + } + + @Override + @SuppressWarnings("unchecked") + public Registration addTextSelectionListener(TextSelectionListener listener) { + return this.eventBus.addListener((Class>)(Class)TextSelectionEvent.class, listener); + } + + @Override + public boolean isReceivingSelectionEventsFromClient() { + return this.receivingSelectionEventsFromClient; + } + + @Override + public void setReceivingSelectionEventsFromClient(boolean receivingSelectionEventsFromClient) { + this.receivingSelectionEventsFromClient = receivingSelectionEventsFromClient; + this.informClientAboutSendingEvents(receivingSelectionEventsFromClient); + } } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java index e286e8b5..80eb297b 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java @@ -8,6 +8,10 @@ import com.vaadin.flow.component.datepicker.DatePicker; import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.shared.Registration; +import org.vaadin.miki.events.text.TextSelectionListener; +import org.vaadin.miki.events.text.TextSelectionNotifier; +import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; +import org.vaadin.miki.markers.CanSelectText; import org.vaadin.miki.markers.HasDatePattern; import org.vaadin.miki.markers.HasLabel; import org.vaadin.miki.markers.HasLocale; @@ -17,14 +21,9 @@ import org.vaadin.miki.markers.WithLabelMixin; import org.vaadin.miki.markers.WithLocaleMixin; import org.vaadin.miki.markers.WithPlaceholderMixin; +import org.vaadin.miki.markers.WithReceivingSelectionEventsFromClientMixin; import org.vaadin.miki.markers.WithValueMixin; -import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; -import org.vaadin.miki.markers.CanSelectText; import org.vaadin.miki.shared.text.TextSelectionDelegate; -import org.vaadin.miki.events.text.TextSelectionEvent; -import org.vaadin.miki.events.text.TextSelectionListener; -import org.vaadin.miki.events.text.TextSelectionNotifier; -import org.vaadin.miki.markers.WithReceivingSelectionEventsFromClientMixin; import java.time.LocalDate; import java.time.format.DateTimeFormatter; @@ -50,9 +49,7 @@ public class SuperDatePicker extends DatePicker private final DatePatternDelegate datePatternDelegate = new DatePatternDelegate<>(this); - private final TextSelectionDelegate textSelectionDelegate = new TextSelectionDelegate<>(this); - - private boolean receivingClientSideSelectionEvent = false; + private final TextSelectionDelegate textSelectionDelegate = new TextSelectionDelegate<>(this, this.getEventBus(), this::getFormattedValue); private DatePattern datePattern; @@ -127,41 +124,29 @@ public DatePattern getDatePattern() { return this.datePattern; } - @Override - public void setValue(LocalDate value) { - this.textSelectionDelegate.updateAttributeOnValueChange(this::getEventBus); - super.setValue(value); - } - @Override protected void onAttach(AttachEvent attachEvent) { - this.textSelectionDelegate.informClientAboutSendingEvents(this.isReceivingSelectionEventsFromClient()); - super.onAttach(attachEvent); + this.textSelectionDelegate.onAttach(attachEvent, super::onAttach); } @Override protected void onDetach(DetachEvent detachEvent) { - // detaching means server should not be informed - if(this.isReceivingSelectionEventsFromClient()) - this.textSelectionDelegate.informClientAboutSendingEvents(false); - super.onDetach(detachEvent); + this.textSelectionDelegate.onDetach(detachEvent, super::onDetach); } @ClientCallable private void selectionChanged(int start, int end, String selection) { - TextSelectionEvent event = new TextSelectionEvent<>(this, true, start, end, selection); - this.textSelectionDelegate.fireTextSelectionEvent(this.getEventBus(), event); + this.textSelectionDelegate.fireTextSelectionEvent(true, start, end, selection); } @Override public boolean isReceivingSelectionEventsFromClient() { - return this.receivingClientSideSelectionEvent; + return this.textSelectionDelegate.isReceivingSelectionEventsFromClient(); } @Override public void setReceivingSelectionEventsFromClient(boolean receivingSelectionEventsFromClient) { - this.receivingClientSideSelectionEvent = receivingSelectionEventsFromClient; - this.textSelectionDelegate.informClientAboutSendingEvents(receivingSelectionEventsFromClient); + this.textSelectionDelegate.setReceivingSelectionEventsFromClient(receivingSelectionEventsFromClient); } /** @@ -180,22 +165,21 @@ else if(this.getDatePattern() == null) @Override public void selectAll() { - this.textSelectionDelegate.selectAll(this::getFormattedValue, this::getEventBus); + this.textSelectionDelegate.selectAll(); } @Override public void selectNone() { - this.textSelectionDelegate.selectNone(this::getEventBus); + this.textSelectionDelegate.selectNone(); } @Override public void select(int from, int to) { - this.textSelectionDelegate.select(this::getFormattedValue, this::getEventBus, from, to); + this.textSelectionDelegate.select(from, to); } @Override - @SuppressWarnings("unchecked") public Registration addTextSelectionListener(TextSelectionListener listener) { - return this.getEventBus().addListener((Class>)(Class)TextSelectionEvent.class, listener); + return this.textSelectionDelegate.addTextSelectionListener(listener); } } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java index 2ebdd3f5..aa1e3b71 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java @@ -310,7 +310,7 @@ private void onFieldSelected(FocusNotifier.FocusEvent event) { } // workaround for https://github.com/vaadin/vaadin-text-field-flow/issues/65 if(this.isAutoselect()) - this.field.getElement().executeJs("this.inputElement.select()"); + this.field.selectAll(); } /** diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java index 4127224b..3f68cd1e 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java @@ -8,7 +8,6 @@ import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.textfield.TextArea; import com.vaadin.flow.shared.Registration; -import org.vaadin.miki.events.text.TextSelectionEvent; import org.vaadin.miki.events.text.TextSelectionListener; import org.vaadin.miki.events.text.TextSelectionNotifier; import org.vaadin.miki.markers.CanSelectText; @@ -34,9 +33,7 @@ public class SuperTextArea extends TextArea implements CanSelectText, TextSelect WithReceivingSelectionEventsFromClientMixin, WithValueMixin, String, SuperTextArea> { - private final TextSelectionDelegate delegate = new TextSelectionDelegate<>(this); - - private boolean receivingSelectionEventsFromClient = false; + private final TextSelectionDelegate delegate = new TextSelectionDelegate<>(this, this.getEventBus(), this::getValue); public SuperTextArea() { } @@ -67,60 +64,47 @@ public SuperTextArea(String label, String initialValue, ValueChangeListener listener) { - return this.getEventBus().addListener((Class>)(Class)TextSelectionEvent.class, listener); + return this.delegate.addTextSelectionListener(listener); } @ClientCallable private void selectionChanged(int start, int end, String selection) { - TextSelectionEvent event = new TextSelectionEvent<>(this, true, start, end, selection); - this.delegate.fireTextSelectionEvent(this.getEventBus(), event); + this.delegate.fireTextSelectionEvent(true, start, end, selection); } - @Override - public void setValue(String value) { - this.delegate.updateAttributeOnValueChange(this::getEventBus); - super.setValue(value); - } } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java index 05d50ec7..d8d96b59 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java @@ -8,7 +8,6 @@ import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.shared.Registration; -import org.vaadin.miki.events.text.TextSelectionEvent; import org.vaadin.miki.events.text.TextSelectionListener; import org.vaadin.miki.events.text.TextSelectionNotifier; import org.vaadin.miki.markers.CanSelectText; @@ -35,9 +34,7 @@ public class SuperTextField extends TextField implements CanSelectText, TextSele WithValueMixin, String, SuperTextField>, WithReceivingSelectionEventsFromClientMixin { - private boolean receivingSelectionEventsFromClient = false; - - private final TextSelectionDelegate delegate = new TextSelectionDelegate<>(this); + private final TextSelectionDelegate delegate = new TextSelectionDelegate<>(this, this.getEventBus(), this::getValue); public SuperTextField() { super(); @@ -69,59 +66,47 @@ public SuperTextField(String label, String initialValue, ValueChangeListener listener) { - return this.getEventBus().addListener((Class>)(Class)TextSelectionEvent.class, listener); + return this.delegate.addTextSelectionListener(listener); } @Override public void selectAll() { - this.delegate.selectAll(this::getValue, this::getEventBus); + this.delegate.selectAll(); } @Override public void selectNone() { - this.delegate.selectNone(this::getEventBus); + this.delegate.selectNone(); } @Override public void select(int from, int to) { - this.delegate.select(this::getValue, this::getEventBus, from, to); + this.delegate.select(from, to); } @ClientCallable private void selectionChanged(int start, int end, String selection) { - TextSelectionEvent event = new TextSelectionEvent<>(this, true, start, end, selection); - this.delegate.fireTextSelectionEvent(this.getEventBus(), event); + this.delegate.fireTextSelectionEvent(true, start, end, selection); } @Override public boolean isReceivingSelectionEventsFromClient() { - return this.receivingSelectionEventsFromClient; + return this.delegate.isReceivingSelectionEventsFromClient(); } @Override public void setReceivingSelectionEventsFromClient(boolean receivingSelectionEventsFromClient) { - this.receivingSelectionEventsFromClient = receivingSelectionEventsFromClient; - this.delegate.informClientAboutSendingEvents(receivingSelectionEventsFromClient); + this.delegate.setReceivingSelectionEventsFromClient(receivingSelectionEventsFromClient); } - @Override - public void setValue(String value) { - this.delegate.updateAttributeOnValueChange(this::getEventBus); - super.setValue(value); - } } From bfc1641594f8e7ee22c1aacc84dd30e275b1a115 Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 5 Jun 2020 21:08:23 +0300 Subject: [PATCH 20/66] #135 and #146 done (#148) added `SuperTabs.isMultiline` also cleaned up some sonar warnings --- demo-v14/frontend/styles/demo-styles.css | 3 +- .../frontend/styles/super-tabs-styles.css | 3 ++ .../main/java/org/vaadin/miki/MainView.java | 10 +++- .../miki/superfields/tabs/SuperTabs.java | 54 ++++++++++++++++++- .../superfields/tabs/TabContentGenerator.java | 4 +- .../miki/superfields/tabs/TabHandler.java | 4 +- .../superfields/tabs/TabHeaderGenerator.java | 4 +- .../frontend/styles/super-tabs-multiline.css | 9 ++++ 8 files changed, 83 insertions(+), 8 deletions(-) create mode 100644 demo-v14/frontend/styles/super-tabs-styles.css create mode 100644 superfields/src/main/resources/META-INF/resources/frontend/styles/super-tabs-multiline.css diff --git a/demo-v14/frontend/styles/demo-styles.css b/demo-v14/frontend/styles/demo-styles.css index e1e9e0d9..a67ec115 100644 --- a/demo-v14/frontend/styles/demo-styles.css +++ b/demo-v14/frontend/styles/demo-styles.css @@ -17,7 +17,7 @@ p.selected-tab { background: #2b908f; font-weight: bold; border: 3px solid darkblue; - padding: 0px; + padding: 0; } div.item-grid-cell { @@ -65,4 +65,3 @@ span.highlighted { padding: 1em; margin: 1em; } - diff --git a/demo-v14/frontend/styles/super-tabs-styles.css b/demo-v14/frontend/styles/super-tabs-styles.css new file mode 100644 index 00000000..44fc526a --- /dev/null +++ b/demo-v14/frontend/styles/super-tabs-styles.css @@ -0,0 +1,3 @@ +:host(#belongs-to-super-tabs) [part="tabs"] { + width: 400px; +} \ No newline at end of file diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainView.java b/demo-v14/src/main/java/org/vaadin/miki/MainView.java index 9f4a3c03..4713c8cf 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainView.java +++ b/demo-v14/src/main/java/org/vaadin/miki/MainView.java @@ -63,6 +63,7 @@ */ @CssImport("./styles/demo-styles.css") @CssImport(value = "./styles/super-number-fields-styles.css", themeFor = "vaadin-text-field") +@CssImport(value = "./styles/super-tabs-styles.css", themeFor = "vaadin-tabs") @Route @PageTitle("SuperFields Demo") public class MainView extends VerticalLayout { @@ -247,6 +248,8 @@ private void buildUnloadObserver(Component component, Consumer call } private void buildSuperTabs(Component component, Consumer callback) { + final Checkbox multilineTabs = new Checkbox("Multiline tabs?", event -> ((SuperTabs)component).setMultiline(event.getValue())); + final ComboBox tabHandlers = new ComboBox<>("Select a tab handler: ", TabHandlers.VISIBILITY_HANDLER, TabHandlers.REMOVING_HANDLER, TabHandlers.selectedContentHasClassName("selected-tab")); tabHandlers.addValueChangeListener(event -> { @@ -254,7 +257,7 @@ private void buildSuperTabs(Component component, Consumer callback) ((SuperTabs)component).setTabHandler(event.getValue()); }); - callback.accept(new Component[]{tabHandlers}); + callback.accept(new Component[]{multilineTabs, tabHandlers}); } private Component buildContentsFor(Class type) { @@ -302,7 +305,10 @@ public MainView() { this.components.put(SuperTextArea.class, new SuperTextArea("Type a lot of something:").withPlaceholder("(nothing typed)").withId("super-text-area")); this.components.put(SuperTabs.class, new SuperTabs((Supplier) HorizontalLayout::new) .withTabContentGenerator(s -> new Paragraph("Did you know? All SuperFields are "+s)) - .withItems("Java friendly", "Super-configurable", "Open source") + .withItems( + "Java friendly", "Super-configurable", "Open source", + "Fun to use", "Reasonably well documented" + ).withId("super-tabs") ); this.components.put(ObservedField.class, new ObservedField()); this.components.put(ComponentObserver.class, new ComponentObserver()); diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/tabs/SuperTabs.java b/superfields/src/main/java/org/vaadin/miki/superfields/tabs/SuperTabs.java index a028215b..7b6c0f6f 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/tabs/SuperTabs.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/tabs/SuperTabs.java @@ -7,6 +7,7 @@ import com.vaadin.flow.component.HasStyle; import com.vaadin.flow.component.Tag; import com.vaadin.flow.component.customfield.CustomField; +import com.vaadin.flow.component.dependency.CssImport; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.Span; import com.vaadin.flow.component.tabs.Tab; @@ -36,6 +37,7 @@ * @since 2020-04-10 */ @Tag("super-tabs") +@CssImport(value = "./styles/super-tabs-multiline.css", themeFor = "vaadin-tabs") public class SuperTabs extends CustomField implements HasLabel, HasStyle, WithItemsMixin>, WithIdMixin>, @@ -46,13 +48,18 @@ public class SuperTabs */ public static final Supplier
DEFAULT_TAB_CONTENTS_CONTAINER = Div::new; + /** + * Name of the theme for multiline tabs. + */ + public static final String MULTILINE_THEME_NAME = "multi-line-tabs"; + private final Tabs tabs = new Tabs(); private final HasComponents contents; private final Map tabsToContents = new HashMap<>(); - private final List> values = new ArrayList<>(); + private final transient List> values = new ArrayList<>(); private TabHandler tabHandler; @@ -62,6 +69,8 @@ public class SuperTabs private boolean customValueAllowed = false; + private boolean multiline = false; + /** * Creates the component with no tabs and default {@link TabHandler}, {@link TabHeaderGenerator} and {@link TabContentGenerator}. */ @@ -145,6 +154,7 @@ public SuperTabs(T defaultValue, Supplier< this.setTabContentGenerator(tabContentGenerator); this.tabs.setAutoselect(false); this.tabs.setWidthFull(); + this.tabs.getElement().getClassList().add("part-of-supertabs"); final C mainContents = mainContentSupplier.get(); if(mainContents instanceof HasSize) ((HasSize) mainContents).setWidthFull(); @@ -460,8 +470,50 @@ public SuperTabs withTabHandler(TabHandler tabHandler) { return this; } + /** + * Checks whether tabs wrap to a new line. + * @return When {@code true} and tabs would overflow current viewport, the extra ones will drop to the next line; {@code false} otherwise and by default. + */ + public boolean isMultiline() { + return this.multiline; + } + + /** + * Sets whether or not tabs should overflow to next line. + * @param multiline When {@code true} and tabs overflow current viewport, the extra ones will drop to the next line; {@code false} when all should be displayed in one line (with navigation buttons if needed). + */ + public void setMultiline(boolean multiline) { + this.multiline = multiline; + if(this.multiline) + this.tabs.setThemeName(MULTILINE_THEME_NAME); + else this.tabs.removeThemeName(MULTILINE_THEME_NAME); + } + + /** + * Chains {@link #setMultiline(boolean)} and returns itself. + * @param multiline Whether or not wrap tabs into new line on overflow. + * @return This. + * @see #setMultiline(boolean) + */ + public SuperTabs withMultiline(boolean multiline) { + this.setMultiline(multiline); + return this; + } + @Override public void setItems(Collection collection) { this.addTabs(collection); } + + @Override + public void setId(String id) { + this.tabs.setId(id == null ? null : "belongs-to-"+id); + super.setId(id); + } + + @Override + public SuperTabs withId(String id) { + this.setId(id); + return this; + } } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/tabs/TabContentGenerator.java b/superfields/src/main/java/org/vaadin/miki/superfields/tabs/TabContentGenerator.java index 878e5109..9eb59845 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/tabs/TabContentGenerator.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/tabs/TabContentGenerator.java @@ -2,6 +2,8 @@ import com.vaadin.flow.component.Component; +import java.io.Serializable; + /** * Marker interface for objects that produce components for tabs. * @param Type of object to generate content for. @@ -9,7 +11,7 @@ * @since 2020-04-10 */ @FunctionalInterface -public interface TabContentGenerator { +public interface TabContentGenerator extends Serializable { /** * Creates a new instance of a component that corresponds to the given object. diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/tabs/TabHandler.java b/superfields/src/main/java/org/vaadin/miki/superfields/tabs/TabHandler.java index b9ba9fa3..358a5025 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/tabs/TabHandler.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/tabs/TabHandler.java @@ -4,13 +4,15 @@ import com.vaadin.flow.component.HasComponents; import com.vaadin.flow.component.tabs.Tab; +import java.io.Serializable; + /** * Interface for objects handling the tab adding, displaying and hiding. * * @author miki * @since 2020-04-30 */ -public interface TabHandler { +public interface TabHandler extends Serializable { /** * Called when a tab has been added, but its contents have not. diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/tabs/TabHeaderGenerator.java b/superfields/src/main/java/org/vaadin/miki/superfields/tabs/TabHeaderGenerator.java index 7d3e45c4..ef10cd73 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/tabs/TabHeaderGenerator.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/tabs/TabHeaderGenerator.java @@ -2,6 +2,8 @@ import com.vaadin.flow.component.tabs.Tab; +import java.io.Serializable; + /** * Marker interface for objects that produce tabs. * @param Type of object to generate tabs for. @@ -9,7 +11,7 @@ * @since 2020-04-10 */ @FunctionalInterface -public interface TabHeaderGenerator { +public interface TabHeaderGenerator extends Serializable { /** * Creates a new instance of a tab that corresponds to the given object. diff --git a/superfields/src/main/resources/META-INF/resources/frontend/styles/super-tabs-multiline.css b/superfields/src/main/resources/META-INF/resources/frontend/styles/super-tabs-multiline.css new file mode 100644 index 00000000..78a8843c --- /dev/null +++ b/superfields/src/main/resources/META-INF/resources/frontend/styles/super-tabs-multiline.css @@ -0,0 +1,9 @@ +:host([theme="multi-line-tabs"]) [part="tabs"] { + flex-wrap: wrap; +--_lumo-tabs-overflow-mask-image: none !important; +} + +:host([theme="multi-line-tabs"]) [part="forward-button"], +:host([theme="multi-line-tabs"]) [part="back-button"] { + display: none; +} From 39a37556a2f5468f955022a0045c572304dcdca6 Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 5 Jun 2020 21:42:20 +0300 Subject: [PATCH 21/66] #147 done (#149) WithIdMixin now using dedicated HasId interface --- .../java/org/vaadin/miki/markers/HasId.java | 25 ++++++++++++++++++ .../org/vaadin/miki/markers/WithIdMixin.java | 6 ++--- .../superfields/dates/SuperDatePicker.java | 7 +---- .../dates/SuperDateTimePicker.java | 8 ++---- .../superfields/lazyload/ObservedField.java | 2 +- .../numbers/AbstractSuperNumberField.java | 26 +++++-------------- .../miki/superfields/tabs/SuperTabs.java | 5 ---- .../miki/superfields/text/SuperTextArea.java | 4 +-- .../miki/superfields/text/SuperTextField.java | 3 --- 9 files changed, 39 insertions(+), 47 deletions(-) create mode 100644 superfields/src/main/java/org/vaadin/miki/markers/HasId.java diff --git a/superfields/src/main/java/org/vaadin/miki/markers/HasId.java b/superfields/src/main/java/org/vaadin/miki/markers/HasId.java new file mode 100644 index 00000000..552a4898 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/markers/HasId.java @@ -0,0 +1,25 @@ +package org.vaadin.miki.markers; + +import java.util.Optional; + +/** + * Marker interface for objects that provide access to their {@code id} property. + * Note: this is Vaadin-compatible, so the getter returns an {@link Optional}. + * @author miki + * @since 2020-06-05 + */ +public interface HasId { + + /** + * Sets this object's id. + * @param id A new id. Can be {@code null} to remove existing id. + */ + void setId(String id); + + /** + * Returns the id, if exists. + * @return The id, if any. + */ + Optional getId(); + +} diff --git a/superfields/src/main/java/org/vaadin/miki/markers/WithIdMixin.java b/superfields/src/main/java/org/vaadin/miki/markers/WithIdMixin.java index 1ebf6656..eeb5bcf2 100644 --- a/superfields/src/main/java/org/vaadin/miki/markers/WithIdMixin.java +++ b/superfields/src/main/java/org/vaadin/miki/markers/WithIdMixin.java @@ -1,14 +1,12 @@ package org.vaadin.miki.markers; -import com.vaadin.flow.component.HasElement; - /** * Mixin interface to allow chaining setting id. * @param Self type. * @author miki * @since 2020-04-22 */ -public interface WithIdMixin extends HasElement { +public interface WithIdMixin extends HasId { /** * Chains setting id. @@ -17,7 +15,7 @@ public interface WithIdMixin extends HasElement { */ @SuppressWarnings("unchecked") default SELF withId(String id) { - this.getElement().setAttribute("id", id); + this.setId(id); return (SELF)this; } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java index 80eb297b..47a1a6a4 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java @@ -12,10 +12,6 @@ import org.vaadin.miki.events.text.TextSelectionNotifier; import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; import org.vaadin.miki.markers.CanSelectText; -import org.vaadin.miki.markers.HasDatePattern; -import org.vaadin.miki.markers.HasLabel; -import org.vaadin.miki.markers.HasLocale; -import org.vaadin.miki.markers.HasPlaceholder; import org.vaadin.miki.markers.WithDatePatternMixin; import org.vaadin.miki.markers.WithIdMixin; import org.vaadin.miki.markers.WithLabelMixin; @@ -39,8 +35,7 @@ @Tag("super-date-picker") @SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes public class SuperDatePicker extends DatePicker - implements HasLocale, HasLabel, HasPlaceholder, HasDatePattern, - CanSelectText, CanReceiveSelectionEventsFromClient, WithReceivingSelectionEventsFromClientMixin, + implements CanSelectText, CanReceiveSelectionEventsFromClient, WithReceivingSelectionEventsFromClientMixin, TextSelectionNotifier, WithLocaleMixin, WithLabelMixin, WithPlaceholderMixin, WithDatePatternMixin, diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java index 9c00cbd5..299bbb59 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java @@ -6,9 +6,6 @@ import com.vaadin.flow.component.datetimepicker.DateTimePicker; import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.timepicker.TimePicker; -import org.vaadin.miki.markers.HasDatePattern; -import org.vaadin.miki.markers.HasLabel; -import org.vaadin.miki.markers.HasLocale; import org.vaadin.miki.markers.WithDatePatternMixin; import org.vaadin.miki.markers.WithIdMixin; import org.vaadin.miki.markers.WithLabelMixin; @@ -29,9 +26,8 @@ @Tag("super-date-time-picker") @SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes public class SuperDateTimePicker extends DateTimePicker - implements HasLocale, HasLabel, HasDatePattern, - WithLocaleMixin, WithLabelMixin, - WithDatePatternMixin, WithIdMixin, + implements WithLocaleMixin, WithLabelMixin, + WithDatePatternMixin, WithIdMixin, WithValueMixin, LocalDateTime, SuperDateTimePicker> { // so, this component is a composition of DatePicker and TimePicker diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/lazyload/ObservedField.java b/superfields/src/main/java/org/vaadin/miki/superfields/lazyload/ObservedField.java index 18434bcd..16e5d9dd 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/lazyload/ObservedField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/lazyload/ObservedField.java @@ -20,7 +20,7 @@ * @since 2020-04-24 */ public class ObservedField extends Composite - implements HasValue, Boolean>, HasStyle, + implements HasStyle, WithValueMixin, Boolean, ObservedField>, WithIdMixin { diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java index aa1e3b71..68f09672 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java @@ -13,23 +13,19 @@ import com.vaadin.flow.shared.Registration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.vaadin.miki.markers.HasLabel; -import org.vaadin.miki.markers.HasLocale; -import org.vaadin.miki.markers.HasPlaceholder; -import org.vaadin.miki.markers.HasTitle; +import org.vaadin.miki.events.text.TextSelectionEvent; +import org.vaadin.miki.events.text.TextSelectionListener; +import org.vaadin.miki.events.text.TextSelectionNotifier; +import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; +import org.vaadin.miki.markers.CanSelectText; import org.vaadin.miki.markers.WithIdMixin; import org.vaadin.miki.markers.WithLabelMixin; import org.vaadin.miki.markers.WithLocaleMixin; import org.vaadin.miki.markers.WithPlaceholderMixin; +import org.vaadin.miki.markers.WithReceivingSelectionEventsFromClientMixin; import org.vaadin.miki.markers.WithTitleMixin; import org.vaadin.miki.markers.WithValueMixin; -import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; -import org.vaadin.miki.markers.CanSelectText; import org.vaadin.miki.superfields.text.SuperTextField; -import org.vaadin.miki.events.text.TextSelectionEvent; -import org.vaadin.miki.events.text.TextSelectionListener; -import org.vaadin.miki.events.text.TextSelectionNotifier; -import org.vaadin.miki.markers.WithReceivingSelectionEventsFromClientMixin; import java.text.DecimalFormat; import java.text.NumberFormat; @@ -47,8 +43,7 @@ public abstract class AbstractSuperNumberField> extends CustomField implements CanSelectText, CanReceiveSelectionEventsFromClient, WithReceivingSelectionEventsFromClientMixin, - TextSelectionNotifier, - HasPrefixAndSuffix, HasLabel, HasPlaceholder, HasTitle, HasLocale, + TextSelectionNotifier, HasPrefixAndSuffix, WithLocaleMixin, WithLabelMixin, WithPlaceholderMixin, WithTitleMixin, WithValueMixin, T>, T, SELF>, WithIdMixin { @@ -502,13 +497,6 @@ public void setId(String id) { this.field.setId(id == null ? null : TEXT_FIELD_STYLE_PREFIX +id); } - @SuppressWarnings("unchecked") - @Override - public SELF withId(String id) { - this.setId(id); - return (SELF)this; - } - /** * Returns the raw value, as currently displayed in the underlying text field. * This may depend on whether or not the component has focus, what locale is used, etc. diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/tabs/SuperTabs.java b/superfields/src/main/java/org/vaadin/miki/superfields/tabs/SuperTabs.java index 7b6c0f6f..5225be17 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/tabs/SuperTabs.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/tabs/SuperTabs.java @@ -511,9 +511,4 @@ public void setId(String id) { super.setId(id); } - @Override - public SuperTabs withId(String id) { - this.setId(id); - return this; - } } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java index 3f68cd1e..1a79a4c5 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextArea.java @@ -11,8 +11,6 @@ import org.vaadin.miki.events.text.TextSelectionListener; import org.vaadin.miki.events.text.TextSelectionNotifier; import org.vaadin.miki.markers.CanSelectText; -import org.vaadin.miki.markers.HasLabel; -import org.vaadin.miki.markers.HasPlaceholder; import org.vaadin.miki.markers.WithIdMixin; import org.vaadin.miki.markers.WithLabelMixin; import org.vaadin.miki.markers.WithPlaceholderMixin; @@ -29,7 +27,7 @@ @JsModule("./super-text-area.js") @SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes public class SuperTextArea extends TextArea implements CanSelectText, TextSelectionNotifier, - HasLabel, HasPlaceholder, WithIdMixin, WithLabelMixin, WithPlaceholderMixin, + WithIdMixin, WithLabelMixin, WithPlaceholderMixin, WithReceivingSelectionEventsFromClientMixin, WithValueMixin, String, SuperTextArea> { diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java index d8d96b59..7eede87f 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/text/SuperTextField.java @@ -11,8 +11,6 @@ import org.vaadin.miki.events.text.TextSelectionListener; import org.vaadin.miki.events.text.TextSelectionNotifier; import org.vaadin.miki.markers.CanSelectText; -import org.vaadin.miki.markers.HasLabel; -import org.vaadin.miki.markers.HasPlaceholder; import org.vaadin.miki.markers.WithIdMixin; import org.vaadin.miki.markers.WithLabelMixin; import org.vaadin.miki.markers.WithPlaceholderMixin; @@ -29,7 +27,6 @@ @JsModule("./super-text-field.js") @SuppressWarnings("squid:S110") // there is no way to reduce the number of parent classes public class SuperTextField extends TextField implements CanSelectText, TextSelectionNotifier, - HasLabel, HasPlaceholder, WithIdMixin, WithLabelMixin, WithPlaceholderMixin, WithValueMixin, String, SuperTextField>, WithReceivingSelectionEventsFromClientMixin { From 4cbaffef6840990e0f4726a20dd2d78819a52a13 Mon Sep 17 00:00:00 2001 From: Miki Date: Tue, 9 Jun 2020 01:15:20 +0300 Subject: [PATCH 22/66] #152 done (#153) new marker interface to support optional null value is now added tests and demo app updated --- .../main/java/org/vaadin/miki/MainView.java | 7 ++++ .../WithNullValueOptionallyAllowed.java | 41 +++++++++++++++++++ .../numbers/AbstractSuperNumberField.java | 27 ++++++++++-- .../numbers/BaseTestsForIntegerNumbers.java | 15 +++++++ 4 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 superfields/src/main/java/org/vaadin/miki/markers/WithNullValueOptionallyAllowed.java diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainView.java b/demo-v14/src/main/java/org/vaadin/miki/MainView.java index 4713c8cf..faff633c 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainView.java +++ b/demo-v14/src/main/java/org/vaadin/miki/MainView.java @@ -23,6 +23,7 @@ import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import org.vaadin.miki.markers.HasLocale; +import org.vaadin.miki.markers.WithNullValueOptionallyAllowed; import org.vaadin.miki.superfields.dates.DatePattern; import org.vaadin.miki.superfields.dates.DatePatterns; import org.vaadin.miki.markers.HasDatePattern; @@ -134,6 +135,11 @@ private void buildHasLocale(Component component, Consumer callback) callback.accept(new Component[]{locales}); } + private void buildNullValueOptionallyAllowed(Component component, Consumer callback) { + final Checkbox allow = new Checkbox("Allow empty string as null value?", event -> ((WithNullValueOptionallyAllowed)component).setNullValueAllowed(event.getValue())); + callback.accept(new Component[]{allow}); + } + private void buildHasValue(Component component, Consumer callback) { final Checkbox toggle = new Checkbox("Mark component as read only?", event -> ((HasValue)component).setReadOnly(event.getValue())); ((HasValue) component).addValueChangeListener(this::onAnyValueChanged); @@ -346,6 +352,7 @@ public MainView() { this.contentBuilders.put(CanSelectText.class, this::buildCanSelectText); this.contentBuilders.put(HasValue.class, this::buildHasValue); this.contentBuilders.put(AbstractSuperNumberField.class, this::buildAbstractSuperNumberField); + this.contentBuilders.put(WithNullValueOptionallyAllowed.class, this::buildNullValueOptionallyAllowed); this.contentBuilders.put(HasLocale.class, this::buildHasLocale); this.contentBuilders.put(ItemGrid.class, this::buildItemGrid); this.contentBuilders.put(HasDatePattern.class, this::buildHasDatePattern); diff --git a/superfields/src/main/java/org/vaadin/miki/markers/WithNullValueOptionallyAllowed.java b/superfields/src/main/java/org/vaadin/miki/markers/WithNullValueOptionallyAllowed.java new file mode 100644 index 00000000..826a3ace --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/markers/WithNullValueOptionallyAllowed.java @@ -0,0 +1,41 @@ +package org.vaadin.miki.markers; + +import com.vaadin.flow.component.HasValue; + +/** + * Marker interface for descendants of {@link HasValue} that may optionally allow {@code null} as value. + * By default objects should not allow {@code null}s. + * In general, when this feature is turned on and {@link #setValue(Object)} is called with {@code null}, the + * object should never throw a {@link NullPointerException}. + * + * @param Event type. + * @param Value type. + * @author miki + * @since 2020-06-09 + */ +public interface WithNullValueOptionallyAllowed, E extends HasValue.ValueChangeEvent, V> extends HasValue { + + /** + * Checks whether or not {@code null} is allowed as a value of the component. + * @return Whether or not {@code null} is allowed as a value. Should default to {@code false}. + */ + boolean isNullValueAllowed(); + + /** + * Sets allowance of {@code null} as this component's value. + * @param allowingNullValue Whether or not to allow {@code null} as a value. + */ + void setNullValueAllowed(boolean allowingNullValue); + + /** + * Chains {@link #setNullValueAllowed(boolean)} and returns itself. + * @param allowingNullValue Whether or not to allow {@code null} as a value. + * @return This. + */ + @SuppressWarnings("unchecked") + default SELF withNullValueAllowed(boolean allowingNullValue) { + this.setNullValueAllowed(allowingNullValue); + return (SELF)this; + } + +} diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java index 68f09672..567fed47 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java @@ -21,6 +21,7 @@ import org.vaadin.miki.markers.WithIdMixin; import org.vaadin.miki.markers.WithLabelMixin; import org.vaadin.miki.markers.WithLocaleMixin; +import org.vaadin.miki.markers.WithNullValueOptionallyAllowed; import org.vaadin.miki.markers.WithPlaceholderMixin; import org.vaadin.miki.markers.WithReceivingSelectionEventsFromClientMixin; import org.vaadin.miki.markers.WithTitleMixin; @@ -46,7 +47,7 @@ public abstract class AbstractSuperNumberField, HasPrefixAndSuffix, WithLocaleMixin, WithLabelMixin, WithPlaceholderMixin, WithTitleMixin, WithValueMixin, T>, T, SELF>, - WithIdMixin { + WithIdMixin, WithNullValueOptionallyAllowed, T>, T> { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractSuperNumberField.class); @@ -101,6 +102,8 @@ public abstract class AbstractSuperNumberField Date: Tue, 9 Jun 2020 01:21:42 +0300 Subject: [PATCH 23/66] Bump websocket-extensions from 0.1.3 to 0.1.4 in /demo-v14 (#151) Bumps [websocket-extensions](https://github.com/faye/websocket-extensions-node) from 0.1.3 to 0.1.4. - [Release notes](https://github.com/faye/websocket-extensions-node/releases) - [Changelog](https://github.com/faye/websocket-extensions-node/blob/master/CHANGELOG.md) - [Commits](https://github.com/faye/websocket-extensions-node/compare/0.1.3...0.1.4) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Miki --- demo-v14/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demo-v14/package-lock.json b/demo-v14/package-lock.json index 97778083..bb40c1cc 100644 --- a/demo-v14/package-lock.json +++ b/demo-v14/package-lock.json @@ -10633,9 +10633,9 @@ } }, "websocket-extensions": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true }, "which": { From 7d9efbfa6fb32c18d4270f3262bf4ce040a9af82 Mon Sep 17 00:00:00 2001 From: Miki Date: Tue, 9 Jun 2020 21:55:53 +0300 Subject: [PATCH 24/66] #154 fixed (#155) added unit tests and notifications in the demo app --- .../main/java/org/vaadin/miki/InfoPage.java | 4 ++- .../main/java/org/vaadin/miki/MainView.java | 28 ++++++++++++++++--- .../numbers/AbstractSuperNumberField.java | 4 +++ .../numbers/BaseTestsForIntegerNumbers.java | 28 +++++++++++++++++++ 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/demo-v14/src/main/java/org/vaadin/miki/InfoPage.java b/demo-v14/src/main/java/org/vaadin/miki/InfoPage.java index 5279abd4..f1fa5589 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/InfoPage.java +++ b/demo-v14/src/main/java/org/vaadin/miki/InfoPage.java @@ -16,9 +16,11 @@ public InfoPage() { new Span("Hello and welcome to SuperFields demo! Thank you for your interest in this little project, I hope you find it useful."), new Span("The components shown in this demo are available in SuperFields, a small collection of handy stuff designed to work with Vaadin 14 and Java."), new Span("To see a component in action simply select a corresponding tab from above. Each page features the chosen component at the top, followed by (some of) the configurable options."), + new Span("Bottom left corner of the browser window will show major notifications from each component - like value change notifications. Bottom right corner is reserved for secondary notifications, e.g. focus and blur events."), new Anchor("https://github.com/vaadin-miki/super-fields", "More information can be found on the project's main page on GitHub."), new Anchor("https://github.com/vaadin-miki/super-fields/issues", "Please use GitHub to report issues and request features and components."), - new Span("Unless otherwise noted, all code has been written by me (Miki) and is released under Apache 2.0 License.") + new Anchor("https://vaadin.com/directory/component/superfields", "If you find this library useful, please consider sparing a moment and writing a comment or leaving a rating in the Vaadin Directory. Thank you!"), + new Span("Disclaimer: unless otherwise noted, all code has been written by me (Miki) and is released under Apache 2.0 License. This library is not officially supported or endorsed by Vaadin and is not part of the Vaadin Platform.") ); } diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainView.java b/demo-v14/src/main/java/org/vaadin/miki/MainView.java index faff633c..1f93bb3b 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainView.java +++ b/demo-v14/src/main/java/org/vaadin/miki/MainView.java @@ -1,6 +1,8 @@ package org.vaadin.miki; +import com.vaadin.flow.component.BlurNotifier; import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.FocusNotifier; import com.vaadin.flow.component.HasValue; import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.checkbox.Checkbox; @@ -22,11 +24,14 @@ import com.vaadin.flow.function.SerializableConsumer; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; +import org.vaadin.miki.events.text.TextSelectionNotifier; +import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; +import org.vaadin.miki.markers.CanSelectText; +import org.vaadin.miki.markers.HasDatePattern; import org.vaadin.miki.markers.HasLocale; import org.vaadin.miki.markers.WithNullValueOptionallyAllowed; import org.vaadin.miki.superfields.dates.DatePattern; import org.vaadin.miki.superfields.dates.DatePatterns; -import org.vaadin.miki.markers.HasDatePattern; import org.vaadin.miki.superfields.dates.SuperDatePicker; import org.vaadin.miki.superfields.dates.SuperDateTimePicker; import org.vaadin.miki.superfields.itemgrid.ItemGrid; @@ -41,11 +46,8 @@ import org.vaadin.miki.superfields.tabs.SuperTabs; import org.vaadin.miki.superfields.tabs.TabHandler; import org.vaadin.miki.superfields.tabs.TabHandlers; -import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; -import org.vaadin.miki.markers.CanSelectText; import org.vaadin.miki.superfields.text.SuperTextArea; import org.vaadin.miki.superfields.text.SuperTextField; -import org.vaadin.miki.events.text.TextSelectionNotifier; import org.vaadin.miki.superfields.unload.UnloadObserver; import java.time.LocalDate; @@ -69,6 +71,8 @@ @PageTitle("SuperFields Demo") public class MainView extends VerticalLayout { + private static final int NOTIFICATION_TIME = 1500; + private final Map, Component> components = new LinkedHashMap<>(); private final Map, SerializableConsumer> afterLocaleChange = new HashMap<>(); @@ -123,6 +127,20 @@ private void buildAbstractSuperNumberField(Component component, Consumer callback) { + ((FocusNotifier)component).addFocusListener(event -> + Notification.show("Component "+component.getClass().getSimpleName()+" received focus.", NOTIFICATION_TIME, Notification.Position.BOTTOM_END) + ); + callback.accept(new Component[]{new Span("Focus the demo component to see a notification.")}); + } + + private void buildBlurNotifier(Component component, Consumer callback) { + ((BlurNotifier)component).addBlurListener(event -> + Notification.show("Component "+component.getClass().getSimpleName()+" lost focus.", NOTIFICATION_TIME, Notification.Position.BOTTOM_END) + ); + callback.accept(new Component[]{new Span("Leave the demo component to see a notification.")}); + } + private void buildHasLocale(Component component, Consumer callback) { final ComboBox locales = new ComboBox<>("Select locale:", new Locale("pl", "PL"), Locale.UK, Locale.FRANCE, Locale.GERMANY, Locale.CHINA); locales.setItemLabelGenerator(locale -> locale.getDisplayCountry() + " / "+locale.getDisplayLanguage()); @@ -360,6 +378,8 @@ public MainView() { this.contentBuilders.put(ObservedField.class, this::buildObservedField); this.contentBuilders.put(ComponentObserver.class, this::buildIntersectionObserver); this.contentBuilders.put(UnloadObserver.class, this::buildUnloadObserver); + this.contentBuilders.put(FocusNotifier.class, this::buildFocusNotifier); + this.contentBuilders.put(BlurNotifier.class, this::buildBlurNotifier); this.afterLocaleChange.put(SuperIntegerField.class, o -> ((SuperIntegerField)o).setMaximumIntegerDigits(6)); this.afterLocaleChange.put(SuperLongField.class, o -> ((SuperLongField)o).setMaximumIntegerDigits(11)); diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java index 567fed47..d1990945 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java @@ -298,6 +298,8 @@ private void updateRegularExpression() { private void onFieldBlurred(BlurNotifier.BlurEvent event) { this.setPresentationValue(this.getValue()); + // fire event + this.getEventBus().fireEvent(new BlurEvent<>(this, event.isFromClient())); } private void onFieldSelected(FocusNotifier.FocusEvent event) { @@ -309,6 +311,8 @@ private void onFieldSelected(FocusNotifier.FocusEvent event) { // workaround for https://github.com/vaadin/vaadin-text-field-flow/issues/65 if(this.isAutoselect()) this.field.selectAll(); + // fire event + this.getEventBus().fireEvent(new FocusEvent<>(this, event.isFromClient())); } /** diff --git a/superfields/src/test/java/org/vaadin/miki/superfields/numbers/BaseTestsForIntegerNumbers.java b/superfields/src/test/java/org/vaadin/miki/superfields/numbers/BaseTestsForIntegerNumbers.java index 243da9e5..efd1f472 100644 --- a/superfields/src/test/java/org/vaadin/miki/superfields/numbers/BaseTestsForIntegerNumbers.java +++ b/superfields/src/test/java/org/vaadin/miki/superfields/numbers/BaseTestsForIntegerNumbers.java @@ -1,6 +1,9 @@ package org.vaadin.miki.superfields.numbers; import com.github.mvysny.kaributesting.v10.MockVaadin; +import com.vaadin.flow.component.ComponentEvent; +import com.vaadin.flow.component.ComponentEventListener; +import com.vaadin.flow.shared.Registration; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -11,6 +14,8 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; /** @@ -34,6 +39,8 @@ class BaseTestsForIntegerNumbers { private AbstractSuperNumberField field; + private boolean eventFlag = false; + public BaseTestsForIntegerNumbers(Supplier> fieldSupplier, T baseTestNumber, T negativeTestNumber, String numberWithGroups, String numberWithoutGroups, T zero) { this.fieldSupplier = fieldSupplier; this.baseTestNumber = baseTestNumber; @@ -199,4 +206,25 @@ public void testNullWithNoNullAllowedThrowsException() { this.getField().setValue(null); } + private > void checkEventTriggered(Function, Registration> addEvent, Consumer> fireEvent) { + this.eventFlag = false; + Registration registration = addEvent.apply(event -> this.eventFlag = true); + fireEvent.accept(this.getField()); + Assert.assertTrue(this.eventFlag); + this.eventFlag = false; + registration.remove(); + this.getField().simulateFocus(); + Assert.assertFalse(this.eventFlag); + } + + @Test + public void testFocus() { + this.checkEventTriggered(this.getField()::addFocusListener, AbstractSuperNumberField::simulateFocus); + } + + @Test + public void testBlur() { + this.checkEventTriggered(this.getField()::addBlurListener, AbstractSuperNumberField::simulateBlur); + } + } From c1be9fee3e0f09fda6ddc2f895c9de4a9b3cb3b2 Mon Sep 17 00:00:00 2001 From: Miki Date: Wed, 10 Jun 2020 22:36:51 +0300 Subject: [PATCH 25/66] #131 could it be this simple? --- .github/workflows/setversion.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/setversion.yml b/.github/workflows/setversion.yml index 74525957..40fffa9c 100644 --- a/.github/workflows/setversion.yml +++ b/.github/workflows/setversion.yml @@ -51,6 +51,13 @@ jobs: with: commit_message: "(bot) version and release notes updated to ${{ steps.what-version.outputs.version }}" branch: ${{ github.event.ref }} + - name: Resolve conflicts (keep ours) + run: git merge master --strategy=ours + - name: Push resolved conflicts + uses: stefanzweifel/git-auto-commit-action@v4.1.6 + with: + commit_message: "(bot) resolved conflicts from master (kept development-$${ steps.what-version.outputs.version }})" + branch: ${{ github.event.ref }} - name: Create PR uses: UnforgivenPL/pull-request@v1 with: From f9d14315012df94f3cf1cde192b1136d8079a219 Mon Sep 17 00:00:00 2001 From: Miki Date: Tue, 16 Jun 2020 14:09:48 +0300 Subject: [PATCH 26/66] 131 conflict resolving (#164) #131 done, hopefully --- .github/workflows/releasebranch.yml | 49 +++++++++++++++++++++++++++-- .github/workflows/setversion.yml | 37 +++++++--------------- superfields/release-notes.md | 15 +++++++++ 3 files changed, 74 insertions(+), 27 deletions(-) diff --git a/.github/workflows/releasebranch.yml b/.github/workflows/releasebranch.yml index fc67f869..0fd31822 100644 --- a/.github/workflows/releasebranch.yml +++ b/.github/workflows/releasebranch.yml @@ -1,4 +1,4 @@ -name: Release branch on milestone close +name: Prepare release branch on milestone close on: milestone: @@ -13,7 +13,52 @@ jobs: run: | set -x echo "::set-output name=version::`echo '${{ github.event.milestone.title }}' | cut -d' ' -f1`" - - name: Push release branch + - name: Push milestone notes branch + uses: UnforgivenPL/push-branch@v2 + with: + repository: ${{ github.repository }} + token: ${{ secrets.GITHUB_TOKEN }} + source: development + target: notes-${{ steps.version.outputs.version }} + - uses: actions/checkout@v2 + with: + ref: notes-${{ steps.version.outputs.version }} + - name: Create milestone notes + uses: UnforgivenPL/milestone-notes@v1 + with: + match-milestone: "^${{ steps.version.outputs.version }} " + repository: ${{ github.repository }} + labels: "enhancement, api, bug" + - name: Format milestone notes + run: | + sed -i -e "s/## enhancement/## New features and enhancements/g" milestone-notes.md + sed -i -e "s/## api/## Changes to API/g" milestone-notes.md + sed -i -e "s/## bug/## Bug fixes/g" milestone-notes.md + sed -i -e "s/^$/(nothing reported)/g" milestone-notes.md + - name: Update release notes + run: | + echo -e "\n" | cat milestone-notes.md - superfields/release-notes.md > superfields/release-notes.md.new + awk 'NF' superfields/release-notes.md.new + mv superfields/release-notes.md.new superfields/release-notes.md + - name: Remove milestone notes + run: rm milestone-notes.md + - name: Push changes to notes branch + uses: stefanzweifel/git-auto-commit-action@v4.1.6 + with: + commit_message: "(bot) release notes updated for ${{ steps.version.outputs.version }}" + branch: notes-${{ steps.version.outputs.version }} + - name: Prepare merge and push it to development + run: | + set -x + git fetch + git checkout notes-${{ steps.version.outputs.version }} + git checkout development + git config user.email "${{ secrets.EMAIL }}" + git config user.name "Miki (bot)" + git merge notes-${{ steps.version.outputs.version }} + git push origin + git push -d origin notes-${{ steps.version.outputs.version }} + - name: Create release branch uses: UnforgivenPL/push-branch@v2 with: repository: ${{ github.repository }} diff --git a/.github/workflows/setversion.yml b/.github/workflows/setversion.yml index 40fffa9c..8391fc15 100644 --- a/.github/workflows/setversion.yml +++ b/.github/workflows/setversion.yml @@ -9,6 +9,8 @@ jobs: timeout-minutes: 15 steps: - uses: actions/checkout@v2 + with: + fetch-depth: 0 - name: Set up JDK 10 uses: actions/setup-java@v1 with: @@ -28,36 +30,21 @@ jobs: mvn versions:set -DnewVersion=$VERSION --file pom.xml mvn versions:set -DnewVersion=$VERSION --file superfields/pom.xml sed -i -e s/{VERSION}/$VERSION/g ./README.md - - name: Create milestone notes - uses: UnforgivenPL/milestone-notes@v1 - with: - match-milestone: "^${{ steps.what-version.outputs.version }} " - repository: ${{ github.repository }} - labels: "enhancement, api, bug" - - name: Format milestone notes - run: | - sed -i -e "s/## enhancement/## New features and enhancements/g" milestone-notes.md - sed -i -e "s/## api/## Changes to API/g" milestone-notes.md - sed -i -e "s/## bug/## Bug fixes/g" milestone-notes.md - sed -i -e "s/^$/(nothing reported)/g" milestone-notes.md - - name: Update release notes - run: | - echo -e "\n" | cat milestone-notes.md - superfields/release-notes.md > superfields/release-notes.md.new - mv superfields/release-notes.md.new superfields/release-notes.md - - name: Remove milestone notes - run: rm milestone-notes.md - name: Push changes uses: stefanzweifel/git-auto-commit-action@v4.1.6 with: - commit_message: "(bot) version and release notes updated to ${{ steps.what-version.outputs.version }}" + commit_message: "(bot) version updated to ${{ steps.what-version.outputs.version }}" branch: ${{ github.event.ref }} - name: Resolve conflicts (keep ours) - run: git merge master --strategy=ours - - name: Push resolved conflicts - uses: stefanzweifel/git-auto-commit-action@v4.1.6 - with: - commit_message: "(bot) resolved conflicts from master (kept development-$${ steps.what-version.outputs.version }})" - branch: ${{ github.event.ref }} + run: | + set -x + git fetch + git checkout master + git checkout ${{ github.event.ref }} + git config user.email "${{ secrets.EMAIL }}" + git config user.name "Miki (bot)" + git merge master --strategy=ours + git push origin - name: Create PR uses: UnforgivenPL/pull-request@v1 with: diff --git a/superfields/release-notes.md b/superfields/release-notes.md index dd64dd71..32a03984 100644 --- a/superfields/release-notes.md +++ b/superfields/release-notes.md @@ -1,3 +1,18 @@ +# 0.6.2 - Vaadin 14.2 compatibility +## New features and enhancements +* \#124 - [Update Vaadin dependencies to 14.2](https://api.github.com/repos/vaadin-miki/super-fields/issues/124) +## Changes to API +* \#127 - [WithIdMixin is missing from number fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/127) +## Bug fixes +* \#126 - [Number fields cannot be easily styled](https://api.github.com/repos/vaadin-miki/super-fields/issues/126) +* \#127 - [WithIdMixin is missing from number fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/127) +# 0.6.1 - Release process improvement +## New features and enhancements +* \#107 - [Generate release notes from a milestone](https://api.github.com/repos/vaadin-miki/super-fields/issues/107) +## Changes to API +(nothing reported) +## Bug fixes +* \#105 - [Removing date (time) picker and adding it back in the dom resets the display pattern](https://api.github.com/repos/vaadin-miki/super-fields/issues/105) # 0.6 - ComponentObserver and UnloadObserver ## New features and enhancements * \#66 - [A field that changes value on becoming shown and hidden](https://api.github.com/repos/vaadin-miki/super-fields/issues/66) From 89c6bd3f88106abb239eabab1509879c770a8119 Mon Sep 17 00:00:00 2001 From: Miki Date: Wed, 17 Jun 2020 22:34:56 +0300 Subject: [PATCH 27/66] #131 using separate step with PR for notes (with automatic merge) (#165) hopefully this means the end of #131 and semi-automated releases are good to go --- .github/workflows/releasebranch.yml | 60 +++++------------------------ .github/workflows/releasenotes.yml | 60 +++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/releasenotes.yml diff --git a/.github/workflows/releasebranch.yml b/.github/workflows/releasebranch.yml index 0fd31822..f01e8577 100644 --- a/.github/workflows/releasebranch.yml +++ b/.github/workflows/releasebranch.yml @@ -1,63 +1,21 @@ -name: Prepare release branch on milestone close +name: Merge release notes, create release branch on: - milestone: - types: [closed] + check_suite: + types: [completed] jobs: - make-branch: + make-release-branch: runs-on: ubuntu-latest - if: ${{ startsWith(github.event.milestone.title, '0.') || startsWith(github.event.milestone.title, '1.') || startsWith(github.event.milestone.title, '2.') || startsWith(github.event.milestone.title, '3.') || startsWith(github.event.milestone.title, '4.') || startsWith(github.event.milestone.title, '5.') || startsWith(github.event.milestone.title, '6.') || startsWith(github.event.milestone.title, '7.') || startsWith(github.event.milestone.title, '8.') || startsWith(github.event.milestone.title, '9.') }} + if: ${{ github.event.check_suite[conclusion] == 'success' && startsWith(github.event.check_suite[head_branch], 'notes-') }} steps: - - id: version - run: | - set -x - echo "::set-output name=version::`echo '${{ github.event.milestone.title }}' | cut -d' ' -f1`" - - name: Push milestone notes branch - uses: UnforgivenPL/push-branch@v2 + - name: Merge PR + uses: UnforgivenPL/merge-pr@v1 with: repository: ${{ github.repository }} token: ${{ secrets.GITHUB_TOKEN }} - source: development - target: notes-${{ steps.version.outputs.version }} - - uses: actions/checkout@v2 - with: - ref: notes-${{ steps.version.outputs.version }} - - name: Create milestone notes - uses: UnforgivenPL/milestone-notes@v1 - with: - match-milestone: "^${{ steps.version.outputs.version }} " - repository: ${{ github.repository }} - labels: "enhancement, api, bug" - - name: Format milestone notes - run: | - sed -i -e "s/## enhancement/## New features and enhancements/g" milestone-notes.md - sed -i -e "s/## api/## Changes to API/g" milestone-notes.md - sed -i -e "s/## bug/## Bug fixes/g" milestone-notes.md - sed -i -e "s/^$/(nothing reported)/g" milestone-notes.md - - name: Update release notes - run: | - echo -e "\n" | cat milestone-notes.md - superfields/release-notes.md > superfields/release-notes.md.new - awk 'NF' superfields/release-notes.md.new - mv superfields/release-notes.md.new superfields/release-notes.md - - name: Remove milestone notes - run: rm milestone-notes.md - - name: Push changes to notes branch - uses: stefanzweifel/git-auto-commit-action@v4.1.6 - with: - commit_message: "(bot) release notes updated for ${{ steps.version.outputs.version }}" - branch: notes-${{ steps.version.outputs.version }} - - name: Prepare merge and push it to development - run: | - set -x - git fetch - git checkout notes-${{ steps.version.outputs.version }} - git checkout development - git config user.email "${{ secrets.EMAIL }}" - git config user.name "Miki (bot)" - git merge notes-${{ steps.version.outputs.version }} - git push origin - git push -d origin notes-${{ steps.version.outputs.version }} + pr: ${{ github.event.check_suite[pull_requests][0].number }} + must-have-labels: release - name: Create release branch uses: UnforgivenPL/push-branch@v2 with: diff --git a/.github/workflows/releasenotes.yml b/.github/workflows/releasenotes.yml new file mode 100644 index 00000000..f0c946ce --- /dev/null +++ b/.github/workflows/releasenotes.yml @@ -0,0 +1,60 @@ +name: Prepare release notes when milestone closes + +on: + milestone: + types: [closed] + +jobs: + update-release-notes: + runs-on: ubuntu-latest + if: ${{ startsWith(github.event.milestone.title, '0.') || startsWith(github.event.milestone.title, '1.') || startsWith(github.event.milestone.title, '2.') || startsWith(github.event.milestone.title, '3.') || startsWith(github.event.milestone.title, '4.') || startsWith(github.event.milestone.title, '5.') || startsWith(github.event.milestone.title, '6.') || startsWith(github.event.milestone.title, '7.') || startsWith(github.event.milestone.title, '8.') || startsWith(github.event.milestone.title, '9.') }} + steps: + - id: version + run: | + set -x + echo "::set-output name=version::`echo '${{ github.event.milestone.title }}' | cut -d' ' -f1`" + - name: Push milestone notes branch + uses: UnforgivenPL/push-branch@v2 + with: + repository: ${{ github.repository }} + token: ${{ secrets.GITHUB_TOKEN }} + source: development + target: notes-${{ steps.version.outputs.version }} + - uses: actions/checkout@v2 + with: + ref: notes-${{ steps.version.outputs.version }} + - name: Create milestone notes + uses: UnforgivenPL/milestone-notes@v1 + with: + match-milestone: "^${{ steps.version.outputs.version }} " + repository: ${{ github.repository }} + labels: "enhancement, api, bug" + - name: Format milestone notes + run: | + sed -i -e "s/## enhancement/## New features and enhancements/g" milestone-notes.md + sed -i -e "s/## api/## Changes to API/g" milestone-notes.md + sed -i -e "s/## bug/## Bug fixes/g" milestone-notes.md + sed -i -e "s/^$/(nothing reported)/g" milestone-notes.md + - name: Update release notes + run: | + echo -e "\n" | cat milestone-notes.md - superfields/release-notes.md > superfields/release-notes.md.new + awk 'NF' superfields/release-notes.md.new + mv superfields/release-notes.md.new superfields/release-notes.md + - name: Remove milestone notes + run: rm milestone-notes.md + - name: Push changes to notes branch + uses: stefanzweifel/git-auto-commit-action@v4.1.6 + with: + commit_message: "(bot) release notes updated for ${{ steps.version.outputs.version }}" + branch: notes-${{ steps.version.outputs.version }} + - name: Create PR + uses: UnforgivenPL/pull-request@v1 + with: + source: notes-${{ steps.version.outputs.version }} + target: development + repository: ${{ github.repository }} + token: ${{ secrets.ACTIONS_PAT }} + pr-title: Release notes for version ${{ steps.what-version.outputs.version }} + pr-body: Automatically updated notes ${{ steps.what-version.outputs.version }}. + pr-assignees: ${{ github.actor }} + pr-labels: release From 47f03a6d4437bd7307d4e33b37530cebb70eb627 Mon Sep 17 00:00:00 2001 From: Miki Date: Sun, 21 Jun 2020 23:54:06 +0300 Subject: [PATCH 28/66] #131 using delayed merge action (#167) this should now merge the PR after a delay of 300 seconds, which should be more than enough for the actions to pass successfully --- .github/workflows/releasebranch.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/releasebranch.yml b/.github/workflows/releasebranch.yml index f01e8577..1ffdbcaa 100644 --- a/.github/workflows/releasebranch.yml +++ b/.github/workflows/releasebranch.yml @@ -1,20 +1,26 @@ name: Merge release notes, create release branch on: - check_suite: - types: [completed] + pull_request: + types: [opened] jobs: make-release-branch: runs-on: ubuntu-latest - if: ${{ github.event.check_suite[conclusion] == 'success' && startsWith(github.event.check_suite[head_branch], 'notes-') }} + if: ${{ startsWith(github.event.pull_request.title, 'Release notes for version') && startsWith(github.event.pull_request.head.ref, 'notes-') }} + timeout-minutes: 30 steps: + - id: version + run: | + set -x + echo "::set-output name=version::`echo '${{ github.event.pull_request.head.ref }}' | cut -d'-' -f2`" - name: Merge PR - uses: UnforgivenPL/merge-pr@v1 + uses: UnforgivenPL/merge-pr@v2 with: repository: ${{ github.repository }} token: ${{ secrets.GITHUB_TOKEN }} - pr: ${{ github.event.check_suite[pull_requests][0].number }} + pr: ${{ github.event.number }} + delay: 300 must-have-labels: release - name: Create release branch uses: UnforgivenPL/push-branch@v2 From ac39ffa359b576acc5aca2698c60ffa486d0686a Mon Sep 17 00:00:00 2001 From: vaadin-miki Date: Sun, 21 Jun 2020 21:11:38 +0000 Subject: [PATCH 29/66] (bot) release notes updated for 0.7.0 --- superfields/release-notes.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/superfields/release-notes.md b/superfields/release-notes.md index 32a03984..1297a365 100644 --- a/superfields/release-notes.md +++ b/superfields/release-notes.md @@ -1,3 +1,20 @@ +# 0.7.0 - SuperTextField +## New features and enhancements +* \#122 - [SuperTextField, SuperTextArea and text selection API](https://api.github.com/repos/vaadin-miki/super-fields/issues/122) +* \#123 - [Add text selection API to existing components](https://api.github.com/repos/vaadin-miki/super-fields/issues/123) +* \#135 - [SuperTabs should have an option to wrap tabs](https://api.github.com/repos/vaadin-miki/super-fields/issues/135) +* \#141 - [Server-side date formatting for DatePattern](https://api.github.com/repos/vaadin-miki/super-fields/issues/141) +* \#152 - [Allow overriding default value in number fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/152) +## Changes to API +* \#123 - [Add text selection API to existing components](https://api.github.com/repos/vaadin-miki/super-fields/issues/123) +* \#147 - [HasId marker interface](https://api.github.com/repos/vaadin-miki/super-fields/issues/147) +## Bug fixes +* \#132 - [No deployment to Heroku](https://api.github.com/repos/vaadin-miki/super-fields/issues/132) +* \#136 - [setReadOnly has no effect on number fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/136) +* \#137 - [UnloadObserver.onDetach causes TypeError](https://api.github.com/repos/vaadin-miki/super-fields/issues/137) +* \#146 - [SuperTabs are difficult to style](https://api.github.com/repos/vaadin-miki/super-fields/issues/146) +* \#154 - [Number fields do not trigger focus/blur events](https://api.github.com/repos/vaadin-miki/super-fields/issues/154) + # 0.6.2 - Vaadin 14.2 compatibility ## New features and enhancements * \#124 - [Update Vaadin dependencies to 14.2](https://api.github.com/repos/vaadin-miki/super-fields/issues/124) From ab9bcca0ff867e531832704ce2716938854ad971 Mon Sep 17 00:00:00 2001 From: Miki Date: Mon, 22 Jun 2020 21:12:12 +0300 Subject: [PATCH 30/66] #171 DatePattern now in a separate package (#172) --- demo-v14/src/main/java/org/vaadin/miki/MainView.java | 4 ++-- superfields/release-notes.md | 1 + .../src/main/java/org/vaadin/miki/markers/HasDatePattern.java | 2 +- .../java/org/vaadin/miki/markers/WithDatePatternMixin.java | 2 +- .../miki/{superfields => shared}/dates/DatePattern.java | 2 +- .../miki/{superfields => shared}/dates/DatePatterns.java | 4 ++-- .../vaadin/miki/superfields/dates/DatePatternDelegate.java | 1 + .../vaadin/miki/superfields/dates/DatePatternJsGenerator.java | 2 ++ .../org/vaadin/miki/superfields/dates/SuperDatePicker.java | 1 + .../vaadin/miki/superfields/dates/SuperDateTimePicker.java | 1 + .../miki/superfields/dates/DatePatternDelegateTest.java | 1 + .../miki/superfields/dates/DatePatternJsGeneratorTest.java | 1 + 12 files changed, 15 insertions(+), 7 deletions(-) rename superfields/src/main/java/org/vaadin/miki/{superfields => shared}/dates/DatePattern.java (99%) rename superfields/src/main/java/org/vaadin/miki/{superfields => shared}/dates/DatePatterns.java (93%) diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainView.java b/demo-v14/src/main/java/org/vaadin/miki/MainView.java index 1f93bb3b..8d595cf5 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainView.java +++ b/demo-v14/src/main/java/org/vaadin/miki/MainView.java @@ -30,8 +30,8 @@ import org.vaadin.miki.markers.HasDatePattern; import org.vaadin.miki.markers.HasLocale; import org.vaadin.miki.markers.WithNullValueOptionallyAllowed; -import org.vaadin.miki.superfields.dates.DatePattern; -import org.vaadin.miki.superfields.dates.DatePatterns; +import org.vaadin.miki.shared.dates.DatePattern; +import org.vaadin.miki.shared.dates.DatePatterns; import org.vaadin.miki.superfields.dates.SuperDatePicker; import org.vaadin.miki.superfields.dates.SuperDateTimePicker; import org.vaadin.miki.superfields.itemgrid.ItemGrid; diff --git a/superfields/release-notes.md b/superfields/release-notes.md index 1297a365..1f3d06e9 100644 --- a/superfields/release-notes.md +++ b/superfields/release-notes.md @@ -8,6 +8,7 @@ ## Changes to API * \#123 - [Add text selection API to existing components](https://api.github.com/repos/vaadin-miki/super-fields/issues/123) * \#147 - [HasId marker interface](https://api.github.com/repos/vaadin-miki/super-fields/issues/147) +* \#171 - [DatePattern should be moved to a shared package](https://github.com/vaadin-miki/super-fields/issues/171) ## Bug fixes * \#132 - [No deployment to Heroku](https://api.github.com/repos/vaadin-miki/super-fields/issues/132) * \#136 - [setReadOnly has no effect on number fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/136) diff --git a/superfields/src/main/java/org/vaadin/miki/markers/HasDatePattern.java b/superfields/src/main/java/org/vaadin/miki/markers/HasDatePattern.java index 489d28a1..ce815f91 100644 --- a/superfields/src/main/java/org/vaadin/miki/markers/HasDatePattern.java +++ b/superfields/src/main/java/org/vaadin/miki/markers/HasDatePattern.java @@ -1,6 +1,6 @@ package org.vaadin.miki.markers; -import org.vaadin.miki.superfields.dates.DatePattern; +import org.vaadin.miki.shared.dates.DatePattern; /** * Marker interface for objects that have a {@link DatePattern}. diff --git a/superfields/src/main/java/org/vaadin/miki/markers/WithDatePatternMixin.java b/superfields/src/main/java/org/vaadin/miki/markers/WithDatePatternMixin.java index 86ed73dd..b8215d5a 100644 --- a/superfields/src/main/java/org/vaadin/miki/markers/WithDatePatternMixin.java +++ b/superfields/src/main/java/org/vaadin/miki/markers/WithDatePatternMixin.java @@ -1,6 +1,6 @@ package org.vaadin.miki.markers; -import org.vaadin.miki.superfields.dates.DatePattern; +import org.vaadin.miki.shared.dates.DatePattern; /** * Mixin interface to allow chaining {@link #setDatePattern(DatePattern)}. diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePattern.java b/superfields/src/main/java/org/vaadin/miki/shared/dates/DatePattern.java similarity index 99% rename from superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePattern.java rename to superfields/src/main/java/org/vaadin/miki/shared/dates/DatePattern.java index 6ce19ae6..6589425b 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePattern.java +++ b/superfields/src/main/java/org/vaadin/miki/shared/dates/DatePattern.java @@ -1,4 +1,4 @@ -package org.vaadin.miki.superfields.dates; +package org.vaadin.miki.shared.dates; import java.io.Serializable; import java.util.Objects; diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatterns.java b/superfields/src/main/java/org/vaadin/miki/shared/dates/DatePatterns.java similarity index 93% rename from superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatterns.java rename to superfields/src/main/java/org/vaadin/miki/shared/dates/DatePatterns.java index 88fccbbc..7763af49 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatterns.java +++ b/superfields/src/main/java/org/vaadin/miki/shared/dates/DatePatterns.java @@ -1,7 +1,7 @@ -package org.vaadin.miki.superfields.dates; +package org.vaadin.miki.shared.dates; /** - * Enumeration class with some common {@link DatePattern}s. + * Container class with some common {@link DatePattern}s. * @author miki * @since 2020-04-24 */ diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternDelegate.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternDelegate.java index 6a0ba097..6fd4e2b4 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternDelegate.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternDelegate.java @@ -3,6 +3,7 @@ import com.vaadin.flow.component.AttachEvent; import com.vaadin.flow.component.Component; import org.vaadin.miki.markers.HasDatePattern; +import org.vaadin.miki.shared.dates.DatePattern; import java.io.Serializable; import java.time.LocalDate; diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternJsGenerator.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternJsGenerator.java index 1e90503f..3b0ab4b3 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternJsGenerator.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/DatePatternJsGenerator.java @@ -1,5 +1,7 @@ package org.vaadin.miki.superfields.dates; +import org.vaadin.miki.shared.dates.DatePattern; + import java.util.EnumMap; import java.util.HashMap; import java.util.Map; diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java index 47a1a6a4..ddfb88c1 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDatePicker.java @@ -19,6 +19,7 @@ import org.vaadin.miki.markers.WithPlaceholderMixin; import org.vaadin.miki.markers.WithReceivingSelectionEventsFromClientMixin; import org.vaadin.miki.markers.WithValueMixin; +import org.vaadin.miki.shared.dates.DatePattern; import org.vaadin.miki.shared.text.TextSelectionDelegate; import java.time.LocalDate; diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java index 299bbb59..ee2204e0 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/dates/SuperDateTimePicker.java @@ -11,6 +11,7 @@ import org.vaadin.miki.markers.WithLabelMixin; import org.vaadin.miki.markers.WithLocaleMixin; import org.vaadin.miki.markers.WithValueMixin; +import org.vaadin.miki.shared.dates.DatePattern; import org.vaadin.miki.util.ReflectTools; import java.time.LocalDateTime; diff --git a/superfields/src/test/java/org/vaadin/miki/superfields/dates/DatePatternDelegateTest.java b/superfields/src/test/java/org/vaadin/miki/superfields/dates/DatePatternDelegateTest.java index 08e25387..def10d00 100644 --- a/superfields/src/test/java/org/vaadin/miki/superfields/dates/DatePatternDelegateTest.java +++ b/superfields/src/test/java/org/vaadin/miki/superfields/dates/DatePatternDelegateTest.java @@ -5,6 +5,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.vaadin.miki.shared.dates.DatePatterns; import java.time.LocalDate; import java.util.Locale; diff --git a/superfields/src/test/java/org/vaadin/miki/superfields/dates/DatePatternJsGeneratorTest.java b/superfields/src/test/java/org/vaadin/miki/superfields/dates/DatePatternJsGeneratorTest.java index 367dab3e..46ea8534 100644 --- a/superfields/src/test/java/org/vaadin/miki/superfields/dates/DatePatternJsGeneratorTest.java +++ b/superfields/src/test/java/org/vaadin/miki/superfields/dates/DatePatternJsGeneratorTest.java @@ -3,6 +3,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.vaadin.miki.shared.dates.DatePattern; public class DatePatternJsGeneratorTest { From c3a82815548c9123ad8791407b6e9a4e9589c654 Mon Sep 17 00:00:00 2001 From: Miki Date: Thu, 25 Jun 2020 15:33:09 +0300 Subject: [PATCH 31/66] 173 threadlocal unload observer (#175) #173 UnloadObserver is now thread-local singleton --- .../main/java/org/vaadin/miki/MainView.java | 6 ++++- .../superfields/unload/UnloadObserver.java | 27 ++++++++++++------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainView.java b/demo-v14/src/main/java/org/vaadin/miki/MainView.java index 8d595cf5..f30c8167 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainView.java +++ b/demo-v14/src/main/java/org/vaadin/miki/MainView.java @@ -24,6 +24,7 @@ import com.vaadin.flow.function.SerializableConsumer; import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; +import org.slf4j.LoggerFactory; import org.vaadin.miki.events.text.TextSelectionNotifier; import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; import org.vaadin.miki.markers.CanSelectText; @@ -266,7 +267,10 @@ private void buildUnloadObserver(Component component, Consumer call final Span description = new Span("This component optionally displays a browser-native window when leaving this app. Select the checkbox above and try to close the window or tab to see it in action."); final Span counterText = new Span("There were this many attempts to leave this app so far: "); final Span counter = new Span("0"); - ((UnloadObserver)component).addUnloadListener(event -> counter.setText(String.valueOf(Integer.parseInt(counter.getText())+1))); + ((UnloadObserver)component).addUnloadListener(event -> { + counter.setText(String.valueOf(Integer.parseInt(counter.getText()) + 1)); + LoggerFactory.getLogger(this.getClass()).info("Unload attempted, happened in {} and UnloadObserver is inside {}", this.getClass().getSimpleName(), event.getSource().getParent().orElseGet(()->this).getClass().getSimpleName()); + }); callback.accept(new Component[]{query, description, new HorizontalLayout(counterText, counter)}); } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java b/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java index 349109f2..c3352241 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java @@ -13,7 +13,7 @@ /** * Server-side component that listens to {@code beforeunload} events. * Based on the code by Kaspar Scherrer and Stuart Robinson. - * Warning: this class is a Singleton; the class is final, the constructors are private and there is at most one global instance. + * Warning: this class is a {@link ThreadLocal} singleton; the class is final, the constructors are private and there is at most one global instance per thread. * * @author Kaspar Scherrer, Stuart Robinson; adapted to web-component by miki * @since 2020-04-29 @@ -22,16 +22,16 @@ @Tag("unload-observer") public final class UnloadObserver extends PolymerTemplate implements WithIdMixin { - private static UnloadObserver instance = null; + private static final ThreadLocal INSTANCES = new ThreadLocal<>(); /** * Returns the current instance. Will create one using default no-arg constructor if none is present yet. * @return An instance of {@link UnloadObserver}. */ public static UnloadObserver get() { - if(instance == null) - instance = new UnloadObserver(); - return instance; + if(INSTANCES.get() == null) + INSTANCES.set(new UnloadObserver()); + return INSTANCES.get(); } /** @@ -40,10 +40,18 @@ public static UnloadObserver get() { * @return An instance of {@link UnloadObserver}. */ public static UnloadObserver get(boolean queryingOnUnload) { - if(instance == null) - instance = new UnloadObserver(queryingOnUnload); - else instance.setQueryingOnUnload(queryingOnUnload); - return instance; + if(INSTANCES.get() == null) + INSTANCES.set(new UnloadObserver(queryingOnUnload)); + else INSTANCES.get().setQueryingOnUnload(queryingOnUnload); + return INSTANCES.get(); + } + + /** + * Cleans up the thread-local variable. This method should be called when the unload observer is no longer needed. + */ + public static void remove() { + if(INSTANCES.get() != null) + INSTANCES.remove(); } private boolean queryingOnUnload; @@ -152,5 +160,4 @@ protected void fireUnloadEvent(UnloadEvent event) { public Registration addUnloadListener(UnloadListener listener) { return this.getEventBus().addListener(UnloadEvent.class, listener); } - } From 58ffe0274622d18b9327fb786371e81d5653821a Mon Sep 17 00:00:00 2001 From: Miki Date: Sat, 27 Jun 2020 00:41:11 +0300 Subject: [PATCH 32/66] #170 done (#177) UnloadObserver now broadcasts an event even when not querying --- .../src/main/java/org/vaadin/miki/MainView.java | 5 +++-- .../miki/superfields/unload/UnloadEvent.java | 15 ++++++++++++++- .../miki/superfields/unload/UnloadObserver.java | 16 ++++++++++++++-- .../resources/frontend/unload-observer.js | 14 ++++++++------ 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainView.java b/demo-v14/src/main/java/org/vaadin/miki/MainView.java index f30c8167..711e4957 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainView.java +++ b/demo-v14/src/main/java/org/vaadin/miki/MainView.java @@ -268,8 +268,9 @@ private void buildUnloadObserver(Component component, Consumer call final Span counterText = new Span("There were this many attempts to leave this app so far: "); final Span counter = new Span("0"); ((UnloadObserver)component).addUnloadListener(event -> { - counter.setText(String.valueOf(Integer.parseInt(counter.getText()) + 1)); - LoggerFactory.getLogger(this.getClass()).info("Unload attempted, happened in {} and UnloadObserver is inside {}", this.getClass().getSimpleName(), event.getSource().getParent().orElseGet(()->this).getClass().getSimpleName()); + if(event.isBecauseOfQuerying()) + counter.setText(String.valueOf(Integer.parseInt(counter.getText()) + 1)); + LoggerFactory.getLogger(this.getClass()).info("Unload event; attempt? {}; captured in {} and UnloadObserver is inside {}", event.isBecauseOfQuerying(), this.getClass().getSimpleName(), event.getSource().getParent().orElse(this).getClass().getSimpleName()); }); callback.accept(new Component[]{query, description, new HorizontalLayout(counterText, counter)}); diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadEvent.java b/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadEvent.java index 69c2e8d2..600ef3e2 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadEvent.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadEvent.java @@ -4,18 +4,31 @@ /** * Server-side event class associated with {@code beforeunload} event happening in the client-side. + * Can optionally prompt the user before leaving the page. * @author miki * @since 2020-04-29 */ public class UnloadEvent extends ComponentEvent { + private final boolean becauseOfQuerying; + /** * Creates a new event using the given source and indicator whether the * event originated from the client side or the server side. * * @param source the source component + * @param attempted when {@code true}, the event is fired in response to querying before unloading; {@code false} otherwise. */ - public UnloadEvent(UnloadObserver source) { + public UnloadEvent(UnloadObserver source, boolean attempted) { super(source, true); + this.becauseOfQuerying = attempted; + } + + /** + * Checks whether or not the event has been fired in response to querying the user on {@code beforeunload} browser event. + * @return {@code true} when event is in response to querying the user on {@code beforeunload}, {@code false} otherwise. + */ + public boolean isBecauseOfQuerying() { + return becauseOfQuerying; } } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java b/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java index c3352241..153db333 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java @@ -13,8 +13,15 @@ /** * Server-side component that listens to {@code beforeunload} events. * Based on the code by Kaspar Scherrer and Stuart Robinson. + * This component will broadcast events on {@code beforeunload} event in the browser. If {@link #isQueryingOnUnload()} + * is {@code true}, before the event the user will be prompted about leaving the page. However, there is no way to find out what the user selected. + * If {@link #isQueryingOnUnload()} is {@code false}, the event on the server will be called just before the page is unloaded. + * Note that the component must be present in the DOM structure in the browser for the event to be received on the server. + * * Warning: this class is a {@link ThreadLocal} singleton; the class is final, the constructors are private and there is at most one global instance per thread. * + * Warning: when the page is unloaded, the thread-local instance should be removed to prevent memory leaks. See {@link #remove()}. + * * @author Kaspar Scherrer, Stuart Robinson; adapted to web-component by miki * @since 2020-04-29 */ @@ -47,7 +54,7 @@ public static UnloadObserver get(boolean queryingOnUnload) { } /** - * Cleans up the thread-local variable. This method should be called when the unload observer is no longer needed. + * Cleans up the thread-local variable. This method is called automatically when the component receives {@code unload} event. */ public static void remove() { if(INSTANCES.get() != null) @@ -139,9 +146,14 @@ protected void onDetach(DetachEvent detachEvent) { super.onDetach(detachEvent); } + @ClientCallable + private void unloadHappened() { + this.fireUnloadEvent(new UnloadEvent(this, false)); + } + @ClientCallable private void unloadAttempted() { - this.fireUnloadEvent(new UnloadEvent(this)); + this.fireUnloadEvent(new UnloadEvent(this, true)); } /** diff --git a/superfields/src/main/resources/META-INF/resources/frontend/unload-observer.js b/superfields/src/main/resources/META-INF/resources/frontend/unload-observer.js index fb9ee7e2..ea6b6f4b 100644 --- a/superfields/src/main/resources/META-INF/resources/frontend/unload-observer.js +++ b/superfields/src/main/resources/META-INF/resources/frontend/unload-observer.js @@ -23,14 +23,14 @@ export class UnloadObserver extends PolymerElement { const src = this; if (window.Vaadin.unloadObserver === undefined) { window.Vaadin.unloadObserver = { - handler: undefined + attemptHandler: undefined } } - if (window.Vaadin.unloadObserver.handler !== undefined) { - window.removeEventListener('beforeunload', window.Vaadin.unloadObserver.handler); + if (window.Vaadin.unloadObserver.attemptHandler !== undefined) { + window.removeEventListener('beforeunload', window.Vaadin.unloadObserver.attemptHandler); } - window.Vaadin.unloadObserver.handler = event => src.unloadHappened(src, event); - window.addEventListener('beforeunload', window.Vaadin.unloadObserver.handler); + window.Vaadin.unloadObserver.attemptHandler = event => src.unloadAttempted(src, event); + window.addEventListener('beforeunload', window.Vaadin.unloadObserver.attemptHandler); } /** @@ -38,14 +38,16 @@ export class UnloadObserver extends PolymerElement { * @param source An unload observer. * @param event Event that happened. */ - unloadHappened(source, event) { + unloadAttempted(source, event) { if (window.Vaadin.unloadObserver.query) { + console.log("UO: responding to unload attempt..."); event.preventDefault(); event.returnValue = ''; if (source.$server) { source.$server.unloadAttempted(); } } + else source.$server.unloadHappened(); } /** From cbcfca6d59fc4b82e6ad074e02263675c15dbd5c Mon Sep 17 00:00:00 2001 From: Miki Date: Wed, 1 Jul 2020 16:42:03 +0300 Subject: [PATCH 33/66] #178 UnloadObserver is now UI-scoped singleton (#179) using ComponentUtil.getData/setData to keep the instance associated with a given UI creating UnloadObserver does not add it anywhere, that still needs to be done manually also updated demo app to reflect changes --- .../main/java/org/vaadin/miki/MainView.java | 2 +- .../superfields/unload/UnloadObserver.java | 46 +++++++++---------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainView.java b/demo-v14/src/main/java/org/vaadin/miki/MainView.java index 711e4957..58c9525a 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainView.java +++ b/demo-v14/src/main/java/org/vaadin/miki/MainView.java @@ -341,7 +341,7 @@ public MainView() { ); this.components.put(ObservedField.class, new ObservedField()); this.components.put(ComponentObserver.class, new ComponentObserver()); - this.components.put(UnloadObserver.class, UnloadObserver.get(false)); + this.components.put(UnloadObserver.class, UnloadObserver.get().withoutQueryingOnUnload()); this.components.put(ItemGrid.class, new ItemGrid>( null, () -> { diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java b/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java index 153db333..644a469b 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java @@ -2,8 +2,10 @@ import com.vaadin.flow.component.AttachEvent; import com.vaadin.flow.component.ClientCallable; +import com.vaadin.flow.component.ComponentUtil; import com.vaadin.flow.component.DetachEvent; import com.vaadin.flow.component.Tag; +import com.vaadin.flow.component.UI; import com.vaadin.flow.component.dependency.JsModule; import com.vaadin.flow.component.polymertemplate.PolymerTemplate; import com.vaadin.flow.shared.Registration; @@ -18,47 +20,41 @@ * If {@link #isQueryingOnUnload()} is {@code false}, the event on the server will be called just before the page is unloaded. * Note that the component must be present in the DOM structure in the browser for the event to be received on the server. * - * Warning: this class is a {@link ThreadLocal} singleton; the class is final, the constructors are private and there is at most one global instance per thread. + * Warning: this class is pretty much a {@link UI}-scoped singleton; the class is final, the constructors are private and there is at most one global instance per UI. * - * Warning: when the page is unloaded, the thread-local instance should be removed to prevent memory leaks. See {@link #remove()}. - * - * @author Kaspar Scherrer, Stuart Robinson; adapted to web-component by miki + * @author Kaspar Scherrer, Stuart Robinson; adapted to web-component by miki; bugfixing and enhancements by Jean-François Lamy * @since 2020-04-29 */ @JsModule("./unload-observer.js") @Tag("unload-observer") public final class UnloadObserver extends PolymerTemplate implements WithIdMixin { - private static final ThreadLocal INSTANCES = new ThreadLocal<>(); - /** - * Returns the current instance. Will create one using default no-arg constructor if none is present yet. + * Returns or creates an instance for current UI. + * The result is associated with the UI, but not added to any of its components. * @return An instance of {@link UnloadObserver}. + * @throws IllegalStateException if there is no current {@link UI}. */ public static UnloadObserver get() { - if(INSTANCES.get() == null) - INSTANCES.set(new UnloadObserver()); - return INSTANCES.get(); + UI ui = UI.getCurrent(); + if(ui == null) + throw new IllegalStateException("there is no UI available to create UnloadObserver for"); + return get(ui); } /** - * Returns the current instance. Will create one if needed and set its {@link #setQueryingOnUnload(boolean)}. - * @param queryingOnUnload Whether or not query at page close. + * Returns or creates an instance for a given UI. + * The result is associated with the UI, but not added to any of its components. + * @param ui A {@link UI} to register the instance of {@link UnloadObserver} in. Must not be {@code null}. * @return An instance of {@link UnloadObserver}. */ - public static UnloadObserver get(boolean queryingOnUnload) { - if(INSTANCES.get() == null) - INSTANCES.set(new UnloadObserver(queryingOnUnload)); - else INSTANCES.get().setQueryingOnUnload(queryingOnUnload); - return INSTANCES.get(); - } - - /** - * Cleans up the thread-local variable. This method is called automatically when the component receives {@code unload} event. - */ - public static void remove() { - if(INSTANCES.get() != null) - INSTANCES.remove(); + public static UnloadObserver get(UI ui) { + UnloadObserver instance = ComponentUtil.getData(ui, UnloadObserver.class); + if(instance == null) { + instance = new UnloadObserver(); + ComponentUtil.setData(ui, UnloadObserver.class, instance); + } + return instance; } private boolean queryingOnUnload; From 187eb8875cfb03d68e96b40e517e2ce6055685d0 Mon Sep 17 00:00:00 2001 From: vaadin-miki Date: Wed, 1 Jul 2020 20:32:44 +0000 Subject: [PATCH 34/66] (bot) release notes updated for 0.7.1 --- superfields/release-notes.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/superfields/release-notes.md b/superfields/release-notes.md index 1f3d06e9..d89d597f 100644 --- a/superfields/release-notes.md +++ b/superfields/release-notes.md @@ -1,3 +1,11 @@ +# 0.7.1 - Fixes to UnloadObserver +## New features and enhancements +* \#170 - [UnloadObserver should always send an event before unloading](https://api.github.com/repos/vaadin-miki/super-fields/issues/170) +## Changes to API +(nothing reported) +## Bug fixes +* \#178 - [UnloadObserver should belong to the UI that will be unloaded.](https://api.github.com/repos/vaadin-miki/super-fields/issues/178) + # 0.7.0 - SuperTextField ## New features and enhancements * \#122 - [SuperTextField, SuperTextArea and text selection API](https://api.github.com/repos/vaadin-miki/super-fields/issues/122) From 9aef510ff088a9691667594e27f5efa59d784423 Mon Sep 17 00:00:00 2001 From: Miki Date: Fri, 3 Jul 2020 18:22:36 +0300 Subject: [PATCH 35/66] done #182 and #183 #182 updated README.md to be in line with the code #183 two new methods: one for returning the UnloadObserver attached to a given Component, one for attaching to current UI --- superfields/README.md | 4 +- .../superfields/unload/UnloadObserver.java | 47 +++++++++++ .../miki/superfields/unload/SampleView.java | 13 +++ .../unload/UnloadObserverTest.java | 80 +++++++++++++++++++ 4 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 superfields/src/test/java/org/vaadin/miki/superfields/unload/SampleView.java create mode 100644 superfields/src/test/java/org/vaadin/miki/superfields/unload/UnloadObserverTest.java diff --git a/superfields/README.md b/superfields/README.md index b61629ea..4ec70ece 100644 --- a/superfields/README.md +++ b/superfields/README.md @@ -94,6 +94,6 @@ A boolean field that changes its value (`true` or `false`) depending on whether A component that listens and reacts to browser's `beforeunload` events that happen for example when browser window/tab is closed. The support [varies between browsers](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event), but in general is quite good. This should work with at least the major browsers. -**Please note**: This component is a singleton - there can be only one instance of it. As such, please refrain from adding the same instance into multiple layouts. +**Please note**: This component is basically a UI-scoped singleton - there can be only one instance of it per active UI. As such, please refrain from adding the same instance into multiple layouts. -The code is based on solution [posted by Kaspar Scherrer and Stuart Robinson](https://vaadin.com/forum/thread/17523194/unsaved-changes-detect-page-exit-or-reload). It does not work with `` or `Anchor` as download links, so please use [FileDownloadWrapper](https://vaadin.com/directory/component/file-download-wrapper/discussions) for that. +The code is based on solution [posted by Kaspar Scherrer and Stuart Robinson](https://vaadin.com/forum/thread/17523194/unsaved-changes-detect-page-exit-or-reload) (with invaluable feedback from Jean-François Lamy). It does not work with `` or `Anchor` as download links, so please use [FileDownloadWrapper](https://vaadin.com/directory/component/file-download-wrapper/discussions) for that. diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java b/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java index 644a469b..2bb40884 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/unload/UnloadObserver.java @@ -2,8 +2,10 @@ import com.vaadin.flow.component.AttachEvent; import com.vaadin.flow.component.ClientCallable; +import com.vaadin.flow.component.Component; import com.vaadin.flow.component.ComponentUtil; import com.vaadin.flow.component.DetachEvent; +import com.vaadin.flow.component.HasComponents; import com.vaadin.flow.component.Tag; import com.vaadin.flow.component.UI; import com.vaadin.flow.component.dependency.JsModule; @@ -57,6 +59,51 @@ public static UnloadObserver get(UI ui) { return instance; } + /** + * Returns or creates an instance for current UI and attaches that instance to the UI, if not yet attached. + * The result is associated with the UI and added to it directly. Identical to calling {@link #getAttached(Component)} with {@code UI.getCurrent()}. + * @return An instance of {@link UnloadObserver}. + */ + public static UnloadObserver getAttached() { + return getAttached(UI.getCurrent()); + } + + /** + * Returns or creates an instance for the UI associated with given {@code parent} and attaches that instance to {@code parent}. + * If the instance was already created and belonged to some other parent and that parent allows removing components, an attempt will be made to + * remove the instance before adding it to the new parent. If that fails, an {@link IllegalStateException} will be thrown. + * If the UI associated with {@code parent} is {@code null}, an {@link IllegalArgumentException} will be thrown. + * @param parent A {@link Component} to add the {@link UnloadObserver} to. Must not be {@code null}. + * @param Generic type to ensure the parent can have other components added to it. + * @return An instance of {@link UnloadObserver}. + * @throws IllegalStateException when an instance of {@link UnloadObserver} is attached to a component it cannot be removed from + * @throws IllegalArgumentException when the {@link Component#getUI()} for {@code parent} is not present + */ + public static UnloadObserver getAttached(C parent) { + if(parent == null) + throw new NullPointerException("parent component to attach UnloadObserver to must not be null"); + if(!parent.getUI().isPresent()) + throw new IllegalArgumentException("parent component is not attached to any UI, hence UnloadObserver cannot be added to it"); + + @SuppressWarnings("squid:S3655") // the check is done just a few lines above + UnloadObserver observer = get(parent.getUI().get()); + // if the observer is already attached to something, remove it from there - unless, of course, it is the same parent + if(observer.getParent().isPresent()) { + @SuppressWarnings("squid:S3655") // the check is done just a line above + Component currentParent = observer.getParent().get(); + if(currentParent != parent) { + if(!(currentParent instanceof HasComponents)) + throw new IllegalStateException("UnloadObserver is currently attached to "+currentParent.getClass().getName()+" which is not HasComponents and cannot be automatically removed"); + else { + ((HasComponents) currentParent).remove(observer); + parent.add(observer); + } + } + } + else parent.add(observer); + return observer; + } + private boolean queryingOnUnload; private boolean clientInitialised; diff --git a/superfields/src/test/java/org/vaadin/miki/superfields/unload/SampleView.java b/superfields/src/test/java/org/vaadin/miki/superfields/unload/SampleView.java new file mode 100644 index 00000000..e51dc870 --- /dev/null +++ b/superfields/src/test/java/org/vaadin/miki/superfields/unload/SampleView.java @@ -0,0 +1,13 @@ +package org.vaadin.miki.superfields.unload; + +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.router.Route; + +/** + * A dummy view for testing. + * @author miki + * @since 2020-07-03 + */ +@Route("") +public class SampleView extends VerticalLayout { +} diff --git a/superfields/src/test/java/org/vaadin/miki/superfields/unload/UnloadObserverTest.java b/superfields/src/test/java/org/vaadin/miki/superfields/unload/UnloadObserverTest.java new file mode 100644 index 00000000..4d6703ea --- /dev/null +++ b/superfields/src/test/java/org/vaadin/miki/superfields/unload/UnloadObserverTest.java @@ -0,0 +1,80 @@ +package org.vaadin.miki.superfields.unload; + +import com.github.mvysny.kaributesting.v10.MockVaadin; +import com.github.mvysny.kaributesting.v10.Routes; +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.UI; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Optional; + +public class UnloadObserverTest { + + @Before + public void setUp() { + final Routes routes = new Routes(); + routes.autoDiscoverViews(); + MockVaadin.setup(routes); + } + + @After + public void tearDown() { + MockVaadin.tearDown(); + } + + @Test + public void testCreatingUnattached() { + Assert.assertNotNull("there should be a UI for current thread", UI.getCurrent()); + UnloadObserver instance = UnloadObserver.get(); + Assert.assertNotNull("there should be a non-null instance of unload observer", instance); + UnloadObserver second = UnloadObserver.get(); + Assert.assertNotNull("calling get() second time should give a non-null result", second); + Assert.assertSame("both instances should be the same", instance, second); + Assert.assertFalse("unload observer should not be attached to anything", instance.getParent().isPresent()); + Assert.assertFalse("unload observer should not be part of any UI", instance.getUI().isPresent()); + } + + private void assertValidUnloadObserver(UnloadObserver instance, UI ui, Component parent) { + Assert.assertTrue("unload observer should be attached to something", instance.getParent().isPresent()); + Assert.assertSame("unload observer should be attached to given parent", instance.getParent().get(), parent); + Assert.assertTrue("unload observer should be part of some UI", instance.getUI().isPresent()); + Assert.assertSame("unload observer should be part of given UI", instance.getUI().get(), ui); + + UnloadObserver second = UnloadObserver.getAttached(); + Assert.assertSame("getting attached should return the same object", instance, second); + } + + @Test + public void testCreatingAttachedToUI() { + Assert.assertNotNull("there should be a UI for current thread", UI.getCurrent()); + UnloadObserver instance = UnloadObserver.getAttached(); + Assert.assertNotNull("there should be a non-null instance of unload observer", instance); + UnloadObserver second = UnloadObserver.get(); + Assert.assertNotNull("calling get() second time should give a non-null result", second); + Assert.assertSame("both instances should be the same", instance, second); + this.assertValidUnloadObserver(instance, UI.getCurrent(), UI.getCurrent()); + } + + @Test + public void testCreatingAttachedToAComponent() { + UI.getCurrent().navigate(""); // go to sample view + Optional perhapsView = UI.getCurrent().getChildren().filter(SampleView.class::isInstance).map(SampleView.class::cast).findFirst(); + Assert.assertTrue("a view should have been found", perhapsView.isPresent()); + SampleView view = perhapsView.get(); + UnloadObserver instance = UnloadObserver.getAttached(view); + this.assertValidUnloadObserver(instance, UI.getCurrent(), view); + + UnloadObserver second = UnloadObserver.get(); + Assert.assertSame("call to get() should result in already attached observer", instance, second); + + // now attaching from view to UI + second = UnloadObserver.getAttached(); + Assert.assertSame("call to getAttached() should return previous instance, but with changed properties", instance, second); + this.assertValidUnloadObserver(instance, UI.getCurrent(), UI.getCurrent()); + Assert.assertTrue("view should no longer contain the unload observer", view.getChildren().noneMatch(component -> component == instance)); + } + +} \ No newline at end of file From dd837d74ca5b332174aac88be2a9ba75bcc3649b Mon Sep 17 00:00:00 2001 From: Miki Date: Sat, 4 Jul 2020 19:24:19 +0300 Subject: [PATCH 36/66] #174 done (#185) demo app now has views (each tab is its own view) --- demo-v14/frontend/styles/demo-styles.css | 4 + ...ainView.java => DemoComponentFactory.java} | 214 +++++++++--------- .../main/java/org/vaadin/miki/DemoPage.java | 43 ++++ .../main/java/org/vaadin/miki/InfoPage.java | 4 + .../main/java/org/vaadin/miki/MainLayout.java | 58 +++++ 5 files changed, 218 insertions(+), 105 deletions(-) rename demo-v14/src/main/java/org/vaadin/miki/{MainView.java => DemoComponentFactory.java} (87%) create mode 100644 demo-v14/src/main/java/org/vaadin/miki/DemoPage.java create mode 100644 demo-v14/src/main/java/org/vaadin/miki/MainLayout.java diff --git a/demo-v14/frontend/styles/demo-styles.css b/demo-v14/frontend/styles/demo-styles.css index a67ec115..4a6939ae 100644 --- a/demo-v14/frontend/styles/demo-styles.css +++ b/demo-v14/frontend/styles/demo-styles.css @@ -65,3 +65,7 @@ span.highlighted { padding: 1em; margin: 1em; } + +.tab-icon { + margin-right: 5px; +} \ No newline at end of file diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainView.java b/demo-v14/src/main/java/org/vaadin/miki/DemoComponentFactory.java similarity index 87% rename from demo-v14/src/main/java/org/vaadin/miki/MainView.java rename to demo-v14/src/main/java/org/vaadin/miki/DemoComponentFactory.java index 58c9525a..32b75502 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainView.java +++ b/demo-v14/src/main/java/org/vaadin/miki/DemoComponentFactory.java @@ -7,23 +7,20 @@ import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.checkbox.Checkbox; import com.vaadin.flow.component.combobox.ComboBox; -import com.vaadin.flow.component.dependency.CssImport; import com.vaadin.flow.component.html.Div; import com.vaadin.flow.component.html.Paragraph; import com.vaadin.flow.component.html.Span; import com.vaadin.flow.component.icon.Icon; import com.vaadin.flow.component.icon.VaadinIcon; import com.vaadin.flow.component.notification.Notification; +import com.vaadin.flow.component.orderedlayout.FlexComponent; import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; import com.vaadin.flow.component.radiobutton.RadioButtonGroup; -import com.vaadin.flow.component.tabs.Tab; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.textfield.TextFieldVariant; import com.vaadin.flow.function.SerializableBiConsumer; import com.vaadin.flow.function.SerializableConsumer; -import com.vaadin.flow.router.PageTitle; -import com.vaadin.flow.router.Route; import org.slf4j.LoggerFactory; import org.vaadin.miki.events.text.TextSelectionNotifier; import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; @@ -53,6 +50,8 @@ import java.time.LocalDate; import java.time.LocalDateTime; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Locale; @@ -61,24 +60,20 @@ import java.util.function.Supplier; /** - * Demo app for various SuperFields and other components. + * Stores information about components to demo. + * This is a singleton. * @author miki - * @since 2020-04-07 + * @since 2020-07-04 */ -@CssImport("./styles/demo-styles.css") -@CssImport(value = "./styles/super-number-fields-styles.css", themeFor = "vaadin-text-field") -@CssImport(value = "./styles/super-tabs-styles.css", themeFor = "vaadin-tabs") -@Route -@PageTitle("SuperFields Demo") -public class MainView extends VerticalLayout { +public final class DemoComponentFactory { private static final int NOTIFICATION_TIME = 1500; - private final Map, Component> components = new LinkedHashMap<>(); + private static final DemoComponentFactory INSTANCE = new DemoComponentFactory(); - private final Map, SerializableConsumer> afterLocaleChange = new HashMap<>(); - - private final Map, SerializableBiConsumer>> contentBuilders = new LinkedHashMap<>(); + public static DemoComponentFactory get() { + return INSTANCE; + } private static Component generateParagraph(Class type, int row, int column) { Paragraph result = new Paragraph(type.getSimpleName()); @@ -100,6 +95,81 @@ private static Component generateDiv(Class type, int row, i }).withId(type.getSimpleName()+"-"+row+"-"+column); } + private final Map, Component> components = new LinkedHashMap<>(); + + private final Map, SerializableBiConsumer>> contentBuilders = new LinkedHashMap<>(); + + private final Map, SerializableConsumer> afterLocaleChange = new HashMap<>(); + + private DemoComponentFactory() { + this.components.put(SuperIntegerField.class, new SuperIntegerField("Integer (6 digits):").withMaximumIntegerDigits(6)); + this.components.put(SuperLongField.class, new SuperLongField("Long (11 digits):").withMaximumIntegerDigits(11).withId("long")); + this.components.put(SuperDoubleField.class, new SuperDoubleField("Double (8 + 4 digits):").withMaximumIntegerDigits(8).withMaximumFractionDigits(4)); + this.components.put(SuperBigDecimalField.class, new SuperBigDecimalField("Big decimal (12 + 3 digits):").withMaximumIntegerDigits(12).withMaximumFractionDigits(3).withMinimumFractionDigits(1).withId("big-decimal")); + this.components.put(SuperDatePicker.class, new SuperDatePicker("Pick a date:").withDatePattern(DatePatterns.YYYY_MM_DD).withValue(LocalDate.now())); + this.components.put(SuperDateTimePicker.class, new SuperDateTimePicker("Pick a date and time:").withDatePattern(DatePatterns.M_D_YYYY_SLASH).withValue(LocalDateTime.now())); + this.components.put(SuperTextField.class, new SuperTextField("Type something:").withPlaceholder("(nothing typed)").withId("super-text-field")); + this.components.put(SuperTextArea.class, new SuperTextArea("Type a lot of something:").withPlaceholder("(nothing typed)").withId("super-text-area")); + this.components.put(SuperTabs.class, new SuperTabs((Supplier) HorizontalLayout::new) + .withTabContentGenerator(s -> new Paragraph("Did you know? All SuperFields are "+s)) + .withItems( + "Java friendly", "Super-configurable", "Open source", + "Fun to use", "Reasonably well documented" + ).withId("super-tabs") + ); + this.components.put(ObservedField.class, new ObservedField()); + this.components.put(ComponentObserver.class, new ComponentObserver()); + this.components.put(UnloadObserver.class, UnloadObserver.get().withoutQueryingOnUnload()); + this.components.put(ItemGrid.class, new ItemGrid>( + null, + () -> { + VerticalLayout result = new VerticalLayout(); + result.setSpacing(true); + result.setPadding(true); + result.setAlignItems(FlexComponent.Alignment.STRETCH); + result.setWidthFull(); + return result; + }, + DemoComponentFactory::generateParagraph, + event -> { + if (event.isSelected()) + event.getCellInformation().getComponent().getElement().getClassList().add("selected"); + else event.getCellInformation().getComponent().getElement().getClassList().remove("selected"); + }, + SuperIntegerField.class, SuperLongField.class, SuperDoubleField.class, + SuperBigDecimalField.class, SuperDatePicker.class, SuperDateTimePicker.class, + SuperTabs.class, LazyLoad.class, ObservedField.class, + ComponentObserver.class, UnloadObserver.class, ItemGrid.class + ) + .withRowComponentGenerator(rowNumber -> { + HorizontalLayout result = new HorizontalLayout(); + result.setSpacing(true); + result.setAlignItems(FlexComponent.Alignment.CENTER); + result.setPadding(true); + return result; + }) + ); + + this.contentBuilders.put(CanSelectText.class, this::buildCanSelectText); + this.contentBuilders.put(HasValue.class, this::buildHasValue); + this.contentBuilders.put(AbstractSuperNumberField.class, this::buildAbstractSuperNumberField); + this.contentBuilders.put(WithNullValueOptionallyAllowed.class, this::buildNullValueOptionallyAllowed); + this.contentBuilders.put(HasLocale.class, this::buildHasLocale); + this.contentBuilders.put(ItemGrid.class, this::buildItemGrid); + this.contentBuilders.put(HasDatePattern.class, this::buildHasDatePattern); + this.contentBuilders.put(SuperTabs.class, this::buildSuperTabs); + this.contentBuilders.put(ObservedField.class, this::buildObservedField); + this.contentBuilders.put(ComponentObserver.class, this::buildIntersectionObserver); + this.contentBuilders.put(UnloadObserver.class, this::buildUnloadObserver); + this.contentBuilders.put(FocusNotifier.class, this::buildFocusNotifier); + this.contentBuilders.put(BlurNotifier.class, this::buildBlurNotifier); + + this.afterLocaleChange.put(SuperIntegerField.class, o -> ((SuperIntegerField)o).setMaximumIntegerDigits(6)); + this.afterLocaleChange.put(SuperLongField.class, o -> ((SuperLongField)o).setMaximumIntegerDigits(11)); + this.afterLocaleChange.put(SuperDoubleField.class, o -> ((SuperDoubleField)o).withMaximumIntegerDigits(8).setMaximumFractionDigits(4)); + this.afterLocaleChange.put(SuperBigDecimalField.class, o -> ((SuperBigDecimalField)o).withMaximumIntegerDigits(12).withMaximumFractionDigits(3).setMinimumFractionDigits(1)); + } + private void buildAbstractSuperNumberField(Component component, Consumer callback) { final Checkbox autoselect = new Checkbox("Select automatically on focus?"); autoselect.addValueChangeListener(event -> ((AbstractSuperNumberField) component).setAutoselect(event.getValue())); @@ -130,7 +200,7 @@ private void buildAbstractSuperNumberField(Component component, Consumer callback) { ((FocusNotifier)component).addFocusListener(event -> - Notification.show("Component "+component.getClass().getSimpleName()+" received focus.", NOTIFICATION_TIME, Notification.Position.BOTTOM_END) + Notification.show("Component "+component.getClass().getSimpleName()+" received focus.", NOTIFICATION_TIME, Notification.Position.BOTTOM_END) ); callback.accept(new Component[]{new Span("Focus the demo component to see a notification.")}); } @@ -169,7 +239,7 @@ private void buildCanSelectText(Component component, Consumer callb final Button selectAll = new Button("Select all", event -> ((CanSelectText)component).selectAll()); final Button selectNone = new Button("Select none", event -> ((CanSelectText)component).selectNone()); final HorizontalLayout layout = new HorizontalLayout(new Span("Type something in the field, then click one of the buttons:"), selectAll, selectNone); - layout.setAlignItems(Alignment.CENTER); + layout.setAlignItems(FlexComponent.Alignment.CENTER); callback.accept(new Component[]{ layout }); @@ -200,7 +270,7 @@ private void buildItemGrid(Component component, Consumer callback) final Checkbox alternate = new Checkbox("Display lazy loading cells?", event -> ((ItemGrid>)component).setCellGenerator( - event.getValue() ? MainView::generateDiv : MainView::generateParagraph + event.getValue() ? DemoComponentFactory::generateDiv : DemoComponentFactory::generateParagraph ) ); @@ -220,7 +290,7 @@ private void buildHasDatePattern(Component component, Consumer call icon.setColor("green"); icon.getElement().setAttribute("title", "Setting pattern does not work out of the box for SuperDateTimePicker if it is in an invisible layout. See issue #87, https://github.com/vaadin-miki/super-fields/issues/87."); clearPatternOrContainer = new HorizontalLayout(clearPattern, icon); - ((HorizontalLayout)clearPatternOrContainer).setAlignItems(Alignment.CENTER); + ((HorizontalLayout)clearPatternOrContainer).setAlignItems(FlexComponent.Alignment.CENTER); } patterns.addValueChangeListener(event -> { ((HasDatePattern) component).setDatePattern(event.getValue()); @@ -270,7 +340,7 @@ private void buildUnloadObserver(Component component, Consumer call ((UnloadObserver)component).addUnloadListener(event -> { if(event.isBecauseOfQuerying()) counter.setText(String.valueOf(Integer.parseInt(counter.getText()) + 1)); - LoggerFactory.getLogger(this.getClass()).info("Unload event; attempt? {}; captured in {} and UnloadObserver is inside {}", event.isBecauseOfQuerying(), this.getClass().getSimpleName(), event.getSource().getParent().orElse(this).getClass().getSimpleName()); + LoggerFactory.getLogger(this.getClass()).info("Unload event; attempt? {}; captured in {} and UnloadObserver is inside {}", event.isBecauseOfQuerying(), this.getClass().getSimpleName(), event.getSource().getParent().orElse(new Span()).getClass().getSimpleName()); }); callback.accept(new Component[]{query, description, new HorizontalLayout(counterText, counter)}); @@ -289,7 +359,24 @@ private void buildSuperTabs(Component component, Consumer callback) callback.accept(new Component[]{multilineTabs, tabHandlers}); } - private Component buildContentsFor(Class type) { + private void onAnyValueChanged(HasValue.ValueChangeEvent valueChangeEvent) { + Notification.show(String.format("%s changed value to %s", valueChangeEvent.getHasValue().getClass().getSimpleName(), valueChangeEvent.getValue())); + } + + /** + * Returns the collection of {@link Component} types. + * @return Unmodifiable collection of classes. + */ + public Collection> getDemoableComponentTypes() { + return Collections.unmodifiableCollection(this.components.keySet()); + } + + /** + * Builds the page for a given component type. + * @param type Type of component to build page for. + * @return A demo page. + */ + public Component buildDemoPageFor(Class type) { Component component = this.components.get(type); component.getElement().getClassList().add("demo"); Div result = new Div(); @@ -319,87 +406,4 @@ private Component buildContentsFor(Class type) { return result; } - private void onAnyValueChanged(HasValue.ValueChangeEvent valueChangeEvent) { - Notification.show(String.format("%s changed value to %s", valueChangeEvent.getHasValue().getClass().getSimpleName(), valueChangeEvent.getValue())); - } - - public MainView() { - this.components.put(SuperIntegerField.class, new SuperIntegerField("Integer (6 digits):").withMaximumIntegerDigits(6)); - this.components.put(SuperLongField.class, new SuperLongField("Long (11 digits):").withMaximumIntegerDigits(11).withId("long")); - this.components.put(SuperDoubleField.class, new SuperDoubleField("Double (8 + 4 digits):").withMaximumIntegerDigits(8).withMaximumFractionDigits(4)); - this.components.put(SuperBigDecimalField.class, new SuperBigDecimalField("Big decimal (12 + 3 digits):").withMaximumIntegerDigits(12).withMaximumFractionDigits(3).withMinimumFractionDigits(1).withId("big-decimal")); - this.components.put(SuperDatePicker.class, new SuperDatePicker("Pick a date:").withDatePattern(DatePatterns.YYYY_MM_DD).withValue(LocalDate.now())); - this.components.put(SuperDateTimePicker.class, new SuperDateTimePicker("Pick a date and time:").withDatePattern(DatePatterns.M_D_YYYY_SLASH).withValue(LocalDateTime.now())); - this.components.put(SuperTextField.class, new SuperTextField("Type something:").withPlaceholder("(nothing typed)").withId("super-text-field")); - this.components.put(SuperTextArea.class, new SuperTextArea("Type a lot of something:").withPlaceholder("(nothing typed)").withId("super-text-area")); - this.components.put(SuperTabs.class, new SuperTabs((Supplier) HorizontalLayout::new) - .withTabContentGenerator(s -> new Paragraph("Did you know? All SuperFields are "+s)) - .withItems( - "Java friendly", "Super-configurable", "Open source", - "Fun to use", "Reasonably well documented" - ).withId("super-tabs") - ); - this.components.put(ObservedField.class, new ObservedField()); - this.components.put(ComponentObserver.class, new ComponentObserver()); - this.components.put(UnloadObserver.class, UnloadObserver.get().withoutQueryingOnUnload()); - this.components.put(ItemGrid.class, new ItemGrid>( - null, - () -> { - VerticalLayout result = new VerticalLayout(); - result.setSpacing(true); - result.setPadding(true); - result.setAlignItems(Alignment.STRETCH); - result.setWidthFull(); - return result; - }, - MainView::generateParagraph, - event -> { - if (event.isSelected()) - event.getCellInformation().getComponent().getElement().getClassList().add("selected"); - else event.getCellInformation().getComponent().getElement().getClassList().remove("selected"); - }, - SuperIntegerField.class, SuperLongField.class, SuperDoubleField.class, - SuperBigDecimalField.class, SuperDatePicker.class, SuperDateTimePicker.class, - SuperTabs.class, LazyLoad.class, ObservedField.class, - ComponentObserver.class, UnloadObserver.class, ItemGrid.class - ) - .withRowComponentGenerator(rowNumber -> { - HorizontalLayout result = new HorizontalLayout(); - result.setSpacing(true); - result.setAlignItems(Alignment.CENTER); - result.setPadding(true); - return result; - }) - ); - - this.contentBuilders.put(CanSelectText.class, this::buildCanSelectText); - this.contentBuilders.put(HasValue.class, this::buildHasValue); - this.contentBuilders.put(AbstractSuperNumberField.class, this::buildAbstractSuperNumberField); - this.contentBuilders.put(WithNullValueOptionallyAllowed.class, this::buildNullValueOptionallyAllowed); - this.contentBuilders.put(HasLocale.class, this::buildHasLocale); - this.contentBuilders.put(ItemGrid.class, this::buildItemGrid); - this.contentBuilders.put(HasDatePattern.class, this::buildHasDatePattern); - this.contentBuilders.put(SuperTabs.class, this::buildSuperTabs); - this.contentBuilders.put(ObservedField.class, this::buildObservedField); - this.contentBuilders.put(ComponentObserver.class, this::buildIntersectionObserver); - this.contentBuilders.put(UnloadObserver.class, this::buildUnloadObserver); - this.contentBuilders.put(FocusNotifier.class, this::buildFocusNotifier); - this.contentBuilders.put(BlurNotifier.class, this::buildBlurNotifier); - - this.afterLocaleChange.put(SuperIntegerField.class, o -> ((SuperIntegerField)o).setMaximumIntegerDigits(6)); - this.afterLocaleChange.put(SuperLongField.class, o -> ((SuperLongField)o).setMaximumIntegerDigits(11)); - this.afterLocaleChange.put(SuperDoubleField.class, o -> ((SuperDoubleField)o).withMaximumIntegerDigits(8).setMaximumFractionDigits(4)); - this.afterLocaleChange.put(SuperBigDecimalField.class, o -> ((SuperBigDecimalField)o).withMaximumIntegerDigits(12).withMaximumFractionDigits(3).setMinimumFractionDigits(1)); - - final SuperTabs> tabs = new SuperTabs>( - type -> new Tab(type.getSimpleName()), - this::buildContentsFor - ); - - tabs.addTab(MainView.class, new Tab(new Icon(VaadinIcon.INFO_CIRCLE), new Span("SuperFields demo")), new InfoPage()); - - tabs.addTab(this.components.keySet().toArray(new Class[0])); - - this.add(tabs); - } } diff --git a/demo-v14/src/main/java/org/vaadin/miki/DemoPage.java b/demo-v14/src/main/java/org/vaadin/miki/DemoPage.java new file mode 100644 index 00000000..dab5c6e5 --- /dev/null +++ b/demo-v14/src/main/java/org/vaadin/miki/DemoPage.java @@ -0,0 +1,43 @@ +package org.vaadin.miki; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.html.Span; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.router.BeforeEvent; +import com.vaadin.flow.router.HasDynamicTitle; +import com.vaadin.flow.router.HasUrlParameter; +import com.vaadin.flow.router.Route; + +/** + * Page that shows a demo of a component. + * @author miki + * @since 2020-07-04 + */ +@Route(value = "demo", layout = MainLayout.class) +public class DemoPage extends VerticalLayout implements HasUrlParameter, HasDynamicTitle { + + private Class componentType; + + @Override + public void setParameter(BeforeEvent event, String parameter) { + this.removeAll(); + DemoComponentFactory.get().getDemoableComponentTypes().stream() + .filter(type -> type.getSimpleName().equalsIgnoreCase(parameter)) + .findFirst().ifPresentOrElse(this::buildDemoPageFor, this::buildErrorPage); + } + + private void buildDemoPageFor(Class type) { + this.componentType = type; + this.add(DemoComponentFactory.get().buildDemoPageFor(type)); + } + + private void buildErrorPage() { + this.componentType = null; + this.add(new Span("You are seeing this because there was a problem in navigating to the demo page for your selected component.")); + } + + @Override + public String getPageTitle() { + return this.componentType == null ? "SuperFields - Error page" : "SuperFields - Demo for "+this.componentType.getSimpleName(); + } +} diff --git a/demo-v14/src/main/java/org/vaadin/miki/InfoPage.java b/demo-v14/src/main/java/org/vaadin/miki/InfoPage.java index f1fa5589..1948ed25 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/InfoPage.java +++ b/demo-v14/src/main/java/org/vaadin/miki/InfoPage.java @@ -3,12 +3,16 @@ import com.vaadin.flow.component.html.Anchor; import com.vaadin.flow.component.html.Span; import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; /** * Information about the demo, its organisation and components. * @author miki * @since 2020-06-03 */ +@Route(value = "", layout = MainLayout.class) +@PageTitle("SuperFields - Demo App") public class InfoPage extends VerticalLayout { public InfoPage() { diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainLayout.java b/demo-v14/src/main/java/org/vaadin/miki/MainLayout.java new file mode 100644 index 00000000..0a22a5d6 --- /dev/null +++ b/demo-v14/src/main/java/org/vaadin/miki/MainLayout.java @@ -0,0 +1,58 @@ +package org.vaadin.miki; + +import com.vaadin.flow.component.dependency.CssImport; +import com.vaadin.flow.component.html.Span; +import com.vaadin.flow.component.icon.Icon; +import com.vaadin.flow.component.icon.VaadinIcon; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.component.tabs.Tab; +import com.vaadin.flow.component.tabs.Tabs; +import com.vaadin.flow.router.AfterNavigationEvent; +import com.vaadin.flow.router.AfterNavigationObserver; +import com.vaadin.flow.router.RouterLayout; +import com.vaadin.flow.router.RouterLink; + +import java.util.HashMap; +import java.util.Map; + +/** + * Main layout of the application. + * @author miki + * @since 2020-07-04 + */ +@CssImport("./styles/demo-styles.css") +@CssImport(value = "./styles/super-number-fields-styles.css", themeFor = "vaadin-text-field") +@CssImport(value = "./styles/super-tabs-styles.css", themeFor = "vaadin-tabs") +public class MainLayout extends VerticalLayout implements RouterLayout, AfterNavigationObserver { + + private final Tabs navigationTabs = new Tabs(); + + private final Map tabs = new HashMap<>(); + + public MainLayout() { + // set up tabs + this.navigationTabs.setWidthFull(); + final RouterLink infoLink = new RouterLink(); + infoLink.setRoute(InfoPage.class); + final Icon icon = new Icon(VaadinIcon.INFO_CIRCLE); + icon.setSize("16px"); + icon.setColor("blue"); + icon.addClassName("tab-icon"); + infoLink.add(icon, new Span("SuperFields demo")); + this.navigationTabs.add(new Tab(infoLink)); + DemoComponentFactory.get().getDemoableComponentTypes().stream().map(type -> { + Tab tab = new Tab(new RouterLink(type.getSimpleName(), DemoPage.class, type.getSimpleName().toLowerCase())); + this.tabs.put(type.getSimpleName().toLowerCase(), tab); + return tab; + }).forEach(this.navigationTabs::add); + this.add(this.navigationTabs); + } + + @Override + public void afterNavigation(AfterNavigationEvent event) { + if(event.getLocation().getPath().isEmpty()) + this.navigationTabs.setSelectedIndex(0); + else + this.navigationTabs.setSelectedTab(this.tabs.get(event.getLocation().getSegments().get(1))); + } +} From e70d813d0822ede1800f3a2c1a41fa3b7f39417b Mon Sep 17 00:00:00 2001 From: vaadin-miki Date: Sat, 4 Jul 2020 16:44:20 +0000 Subject: [PATCH 37/66] (bot) release notes updated for 0.7.2 --- superfields/release-notes.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/superfields/release-notes.md b/superfields/release-notes.md index d89d597f..e03988ef 100644 --- a/superfields/release-notes.md +++ b/superfields/release-notes.md @@ -1,3 +1,11 @@ +# 0.7.2 - UI-scoped UnloadObserver +## New features and enhancements +(nothing reported) +## Changes to API +* \#183 - [Introduce UnloadObserver.get(Component)](https://api.github.com/repos/vaadin-miki/super-fields/issues/183) +## Bug fixes + + # 0.7.1 - Fixes to UnloadObserver ## New features and enhancements * \#170 - [UnloadObserver should always send an event before unloading](https://api.github.com/repos/vaadin-miki/super-fields/issues/170) From 677592f7d46c02ce485834b1db80fe7ae4b6ce5a Mon Sep 17 00:00:00 2001 From: Miki Date: Mon, 6 Jul 2020 16:07:09 +0300 Subject: [PATCH 38/66] #188 fixes to automated release-notes.md creation (#190) now using proper links and explicitly removing all empty lines --- .github/workflows/releasenotes.yml | 4 +- superfields/release-notes.md | 103 ++++++++++++++--------------- 2 files changed, 52 insertions(+), 55 deletions(-) diff --git a/.github/workflows/releasenotes.yml b/.github/workflows/releasenotes.yml index f0c946ce..ee06090b 100644 --- a/.github/workflows/releasenotes.yml +++ b/.github/workflows/releasenotes.yml @@ -24,7 +24,7 @@ jobs: with: ref: notes-${{ steps.version.outputs.version }} - name: Create milestone notes - uses: UnforgivenPL/milestone-notes@v1 + uses: UnforgivenPL/milestone-notes@v2 with: match-milestone: "^${{ steps.version.outputs.version }} " repository: ${{ github.repository }} @@ -38,7 +38,7 @@ jobs: - name: Update release notes run: | echo -e "\n" | cat milestone-notes.md - superfields/release-notes.md > superfields/release-notes.md.new - awk 'NF' superfields/release-notes.md.new + sed -i -e "/^$/d" milestone-notes.md.new mv superfields/release-notes.md.new superfields/release-notes.md - name: Remove milestone notes run: rm milestone-notes.md diff --git a/superfields/release-notes.md b/superfields/release-notes.md index e03988ef..b96eb7b8 100644 --- a/superfields/release-notes.md +++ b/superfields/release-notes.md @@ -2,113 +2,110 @@ ## New features and enhancements (nothing reported) ## Changes to API -* \#183 - [Introduce UnloadObserver.get(Component)](https://api.github.com/repos/vaadin-miki/super-fields/issues/183) +* \#183 - [Introduce UnloadObserver.get(Component)](https://www.github.com/vaadin-miki/super-fields/issues/183) ## Bug fixes - - +(nothing reported) # 0.7.1 - Fixes to UnloadObserver ## New features and enhancements -* \#170 - [UnloadObserver should always send an event before unloading](https://api.github.com/repos/vaadin-miki/super-fields/issues/170) +* \#170 - [UnloadObserver should always send an event before unloading](https://www.github.com/vaadin-miki/super-fields/issues/170) ## Changes to API (nothing reported) ## Bug fixes -* \#178 - [UnloadObserver should belong to the UI that will be unloaded.](https://api.github.com/repos/vaadin-miki/super-fields/issues/178) - +* \#178 - [UnloadObserver should belong to the UI that will be unloaded.](https://www.github.com/vaadin-miki/super-fields/issues/178) # 0.7.0 - SuperTextField ## New features and enhancements -* \#122 - [SuperTextField, SuperTextArea and text selection API](https://api.github.com/repos/vaadin-miki/super-fields/issues/122) -* \#123 - [Add text selection API to existing components](https://api.github.com/repos/vaadin-miki/super-fields/issues/123) -* \#135 - [SuperTabs should have an option to wrap tabs](https://api.github.com/repos/vaadin-miki/super-fields/issues/135) -* \#141 - [Server-side date formatting for DatePattern](https://api.github.com/repos/vaadin-miki/super-fields/issues/141) -* \#152 - [Allow overriding default value in number fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/152) +* \#122 - [SuperTextField, SuperTextArea and text selection API](https://www.github.com/vaadin-miki/super-fields/issues/122) +* \#123 - [Add text selection API to existing components](https://www.github.com/vaadin-miki/super-fields/issues/123) +* \#135 - [SuperTabs should have an option to wrap tabs](https://www.github.com/vaadin-miki/super-fields/issues/135) +* \#141 - [Server-side date formatting for DatePattern](https://www.github.com/vaadin-miki/super-fields/issues/141) +* \#152 - [Allow overriding default value in number fields](https://www.github.com/vaadin-miki/super-fields/issues/152) ## Changes to API -* \#123 - [Add text selection API to existing components](https://api.github.com/repos/vaadin-miki/super-fields/issues/123) -* \#147 - [HasId marker interface](https://api.github.com/repos/vaadin-miki/super-fields/issues/147) +* \#123 - [Add text selection API to existing components](https://www.github.com/vaadin-miki/super-fields/issues/123) +* \#147 - [HasId marker interface](https://www.github.com/vaadin-miki/super-fields/issues/147) * \#171 - [DatePattern should be moved to a shared package](https://github.com/vaadin-miki/super-fields/issues/171) ## Bug fixes -* \#132 - [No deployment to Heroku](https://api.github.com/repos/vaadin-miki/super-fields/issues/132) -* \#136 - [setReadOnly has no effect on number fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/136) -* \#137 - [UnloadObserver.onDetach causes TypeError](https://api.github.com/repos/vaadin-miki/super-fields/issues/137) -* \#146 - [SuperTabs are difficult to style](https://api.github.com/repos/vaadin-miki/super-fields/issues/146) -* \#154 - [Number fields do not trigger focus/blur events](https://api.github.com/repos/vaadin-miki/super-fields/issues/154) - +* \#132 - [No deployment to Heroku](https://www.github.com/vaadin-miki/super-fields/issues/132) +* \#136 - [setReadOnly has no effect on number fields](https://www.github.com/vaadin-miki/super-fields/issues/136) +* \#137 - [UnloadObserver.onDetach causes TypeError](https://www.github.com/vaadin-miki/super-fields/issues/137) +* \#146 - [SuperTabs are difficult to style](https://www.github.com/vaadin-miki/super-fields/issues/146) +* \#154 - [Number fields do not trigger focus/blur events](https://www.github.com/vaadin-miki/super-fields/issues/154) # 0.6.2 - Vaadin 14.2 compatibility ## New features and enhancements -* \#124 - [Update Vaadin dependencies to 14.2](https://api.github.com/repos/vaadin-miki/super-fields/issues/124) +* \#124 - [Update Vaadin dependencies to 14.2](https://www.github.com/vaadin-miki/super-fields/issues/124) ## Changes to API -* \#127 - [WithIdMixin is missing from number fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/127) +* \#127 - [WithIdMixin is missing from number fields](https://www.github.com/vaadin-miki/super-fields/issues/127) ## Bug fixes -* \#126 - [Number fields cannot be easily styled](https://api.github.com/repos/vaadin-miki/super-fields/issues/126) -* \#127 - [WithIdMixin is missing from number fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/127) +* \#126 - [Number fields cannot be easily styled](https://www.github.com/vaadin-miki/super-fields/issues/126) +* \#127 - [WithIdMixin is missing from number fields](https://www.github.com/vaadin-miki/super-fields/issues/127) # 0.6.1 - Release process improvement ## New features and enhancements -* \#107 - [Generate release notes from a milestone](https://api.github.com/repos/vaadin-miki/super-fields/issues/107) +* \#107 - [Generate release notes from a milestone](https://www.github.com/vaadin-miki/super-fields/issues/107) ## Changes to API (nothing reported) ## Bug fixes -* \#105 - [Removing date (time) picker and adding it back in the dom resets the display pattern](https://api.github.com/repos/vaadin-miki/super-fields/issues/105) +* \#105 - [Removing date (time) picker and adding it back in the dom resets the display pattern](https://www.github.com/vaadin-miki/super-fields/issues/105) # 0.6 - ComponentObserver and UnloadObserver ## New features and enhancements -* \#66 - [A field that changes value on becoming shown and hidden](https://api.github.com/repos/vaadin-miki/super-fields/issues/66) -* \#69 - [ComponentObserver - reusing client-side IntersectionObserver as a server-side component](https://api.github.com/repos/vaadin-miki/super-fields/issues/69) -* \#75 - [Component for encapsulating beforeunload events](https://api.github.com/repos/vaadin-miki/super-fields/issues/75) -* \#80 - [Expand SuperTabs to work also with removing tab contents](https://api.github.com/repos/vaadin-miki/super-fields/issues/80) -* \#82 - [Allow overriding default container in SuperTabs](https://api.github.com/repos/vaadin-miki/super-fields/issues/82) +* \#66 - [A field that changes value on becoming shown and hidden](https://www.github.com/vaadin-miki/super-fields/issues/66) +* \#69 - [ComponentObserver - reusing client-side IntersectionObserver as a server-side component](https://www.github.com/vaadin-miki/super-fields/issues/69) +* \#75 - [Component for encapsulating beforeunload events](https://www.github.com/vaadin-miki/super-fields/issues/75) +* \#80 - [Expand SuperTabs to work also with removing tab contents](https://www.github.com/vaadin-miki/super-fields/issues/80) +* \#82 - [Allow overriding default container in SuperTabs](https://www.github.com/vaadin-miki/super-fields/issues/82) ## Changes to API -* \#76 - [Make Vaadin dependencies not transitive](https://api.github.com/repos/vaadin-miki/super-fields/issues/76) -* \#85 - [Add WithItems also to ItemGrid](https://api.github.com/repos/vaadin-miki/super-fields/issues/85) -* \#86 - [Create WithValue to allow chaining setValue calls](https://api.github.com/repos/vaadin-miki/super-fields/issues/86) -* \#89 - [Expose DatePicker and TimePicker in SuperDateTimePicker](https://api.github.com/repos/vaadin-miki/super-fields/issues/89) -* \#92 - [Add WithIdMixin to all components](https://api.github.com/repos/vaadin-miki/super-fields/issues/92) +* \#76 - [Make Vaadin dependencies not transitive](https://www.github.com/vaadin-miki/super-fields/issues/76) +* \#85 - [Add WithItems also to ItemGrid](https://www.github.com/vaadin-miki/super-fields/issues/85) +* \#86 - [Create WithValue to allow chaining setValue calls](https://www.github.com/vaadin-miki/super-fields/issues/86) +* \#89 - [Expose DatePicker and TimePicker in SuperDateTimePicker](https://www.github.com/vaadin-miki/super-fields/issues/89) +* \#92 - [Add WithIdMixin to all components](https://www.github.com/vaadin-miki/super-fields/issues/92) ## Bug fixes -* \#81 - [Setting date display pattern does not work out-of-the-box](https://api.github.com/repos/vaadin-miki/super-fields/issues/81) -* \#83 - [SuperTabs should implement HasItems](https://api.github.com/repos/vaadin-miki/super-fields/issues/83) -* \#90 - [SuperTabs should be using removing handler by default](https://api.github.com/repos/vaadin-miki/super-fields/issues/90) -* \#93 - ["this.observer is undefined" after ObservedField is removed from dom and added again](https://api.github.com/repos/vaadin-miki/super-fields/issues/93) -* \#98 - [Vaadin production mode not included](https://api.github.com/repos/vaadin-miki/super-fields/issues/98) +* \#81 - [Setting date display pattern does not work out-of-the-box](https://www.github.com/vaadin-miki/super-fields/issues/81) +* \#83 - [SuperTabs should implement HasItems](https://www.github.com/vaadin-miki/super-fields/issues/83) +* \#90 - [SuperTabs should be using removing handler by default](https://www.github.com/vaadin-miki/super-fields/issues/90) +* \#93 - ["this.observer is undefined" after ObservedField is removed from dom and added again](https://www.github.com/vaadin-miki/super-fields/issues/93) +* \#98 - [Vaadin production mode not included](https://www.github.com/vaadin-miki/super-fields/issues/98) # 0.5.1 - Fix maven dependencies ## New features and enhancements (nothing reported) ## Changes to API (nothing reported) ## Bug fixes -* \#70 - [Parent pom unavailable for Directory downloads](https://api.github.com/repos/vaadin-miki/super-fields/issues/70) +* \#70 - [Parent pom unavailable for Directory downloads](https://www.github.com/vaadin-miki/super-fields/issues/70) # 0.5 - LazyLoad ## New features and enhancements -* \#50 - [Investigate lazy loading for ItemGrid](https://api.github.com/repos/vaadin-miki/super-fields/issues/50) -* \#51 - [Custom date formatting for date components](https://api.github.com/repos/vaadin-miki/super-fields/issues/51) +* \#50 - [Investigate lazy loading for ItemGrid](https://www.github.com/vaadin-miki/super-fields/issues/50) +* \#51 - [Custom date formatting for date components](https://www.github.com/vaadin-miki/super-fields/issues/51) ## Changes to API (nothing reported) ## Bug fixes -* \#56 - [Set width to full in number fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/56) +* \#56 - [Set width to full in number fields](https://www.github.com/vaadin-miki/super-fields/issues/56) # 0.4 - ItemGrid ## New features and enhancements -* \#34 - [Basic version of `ItemGrid`](https://api.github.com/repos/vaadin-miki/super-fields/issues/34) +* \#34 - [Basic version of `ItemGrid`](https://www.github.com/vaadin-miki/super-fields/issues/34) ## Changes to API (nothing reported) ## Bug fixes (nothing reported) # 0.3 - SuperTabs ## New features and enhancements -* \#26 - [SuperTabs](https://api.github.com/repos/vaadin-miki/super-fields/issues/26) +* \#26 - [SuperTabs](https://www.github.com/vaadin-miki/super-fields/issues/26) ## Changes to API -* \#30 - [Add .withXYZ methods to all fields](https://api.github.com/repos/vaadin-miki/super-fields/issues/30) +* \#30 - [Add .withXYZ methods to all fields](https://www.github.com/vaadin-miki/super-fields/issues/30) ## Bug fixes (nothing reported) # 0.2 - Date components ## New features and enhancements -* \#12 - [SuperDatePicker](https://api.github.com/repos/vaadin-miki/super-fields/issues/12) -* \#20 - [SuperDateTimePicker](https://api.github.com/repos/vaadin-miki/super-fields/issues/20) +* \#12 - [SuperDatePicker](https://www.github.com/vaadin-miki/super-fields/issues/12) +* \#20 - [SuperDateTimePicker](https://www.github.com/vaadin-miki/super-fields/issues/20) ## Changes to API (nothing reported) ## Bug fixes (nothing reported) # 0.1 - Number fields ## New features and enhancements -* \#2 - [SuperDoubleField](https://api.github.com/repos/vaadin-miki/super-fields/issues/2) -* \#4 - [SuperIntegerField and SuperLongField](https://api.github.com/repos/vaadin-miki/super-fields/issues/4) -* \#5 - [SuperBigDecimalField](https://api.github.com/repos/vaadin-miki/super-fields/issues/5) +* \#2 - [SuperDoubleField](https://www.github.com/vaadin-miki/super-fields/issues/2) +* \#4 - [SuperIntegerField and SuperLongField](https://www.github.com/vaadin-miki/super-fields/issues/4) +* \#5 - [SuperBigDecimalField](https://www.github.com/vaadin-miki/super-fields/issues/5) ## Changes to API (nothing reported) ## Bug fixes -* \#10 - [Max integer length does not work if it is a multiplication of grouping size](https://api.github.com/repos/vaadin-miki/super-fields/issues/10) \ No newline at end of file +* \#10 - [Max integer length does not work if it is a multiplication of grouping size](https://www.github.com/vaadin-miki/super-fields/issues/10) \ No newline at end of file From 7314c228a11119b31c346773f23bb2a8f6b634d1 Mon Sep 17 00:00:00 2001 From: Miki Date: Mon, 6 Jul 2020 18:11:19 +0300 Subject: [PATCH 39/66] #189 done, #191 fixed in the process (#192) added new constructor to number fields that takes default value and label --- .../org/vaadin/miki/DemoComponentFactory.java | 21 ++++++++----------- .../main/java/org/vaadin/miki/DemoPage.java | 6 ++++-- .../main/java/org/vaadin/miki/MainLayout.java | 4 +++- .../numbers/AbstractSuperNumberField.java | 5 ++++- .../numbers/SuperBigDecimalField.java | 9 ++++++++ .../superfields/numbers/SuperDoubleField.java | 11 +++++++++- .../numbers/SuperIntegerField.java | 11 +++++++++- .../superfields/numbers/SuperLongField.java | 13 ++++++++++-- 8 files changed, 60 insertions(+), 20 deletions(-) diff --git a/demo-v14/src/main/java/org/vaadin/miki/DemoComponentFactory.java b/demo-v14/src/main/java/org/vaadin/miki/DemoComponentFactory.java index 32b75502..230438e7 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/DemoComponentFactory.java +++ b/demo-v14/src/main/java/org/vaadin/miki/DemoComponentFactory.java @@ -61,7 +61,6 @@ /** * Stores information about components to demo. - * This is a singleton. * @author miki * @since 2020-07-04 */ @@ -69,10 +68,8 @@ public final class DemoComponentFactory { private static final int NOTIFICATION_TIME = 1500; - private static final DemoComponentFactory INSTANCE = new DemoComponentFactory(); - public static DemoComponentFactory get() { - return INSTANCE; + return new DemoComponentFactory(); } private static Component generateParagraph(Class type, int row, int column) { @@ -102,10 +99,10 @@ private static Component generateDiv(Class type, int row, i private final Map, SerializableConsumer> afterLocaleChange = new HashMap<>(); private DemoComponentFactory() { - this.components.put(SuperIntegerField.class, new SuperIntegerField("Integer (6 digits):").withMaximumIntegerDigits(6)); - this.components.put(SuperLongField.class, new SuperLongField("Long (11 digits):").withMaximumIntegerDigits(11).withId("long")); - this.components.put(SuperDoubleField.class, new SuperDoubleField("Double (8 + 4 digits):").withMaximumIntegerDigits(8).withMaximumFractionDigits(4)); - this.components.put(SuperBigDecimalField.class, new SuperBigDecimalField("Big decimal (12 + 3 digits):").withMaximumIntegerDigits(12).withMaximumFractionDigits(3).withMinimumFractionDigits(1).withId("big-decimal")); + this.components.put(SuperIntegerField.class, new SuperIntegerField(null, "Integer (6 digits):").withMaximumIntegerDigits(6)); + this.components.put(SuperLongField.class, new SuperLongField(null, "Long (11 digits):").withMaximumIntegerDigits(11).withId("long")); + this.components.put(SuperDoubleField.class, new SuperDoubleField(null, "Double (8 + 4 digits):").withMaximumIntegerDigits(8).withMaximumFractionDigits(4)); + this.components.put(SuperBigDecimalField.class, new SuperBigDecimalField(null, "Big decimal (12 + 3 digits):").withMaximumIntegerDigits(12).withMaximumFractionDigits(3).withMinimumFractionDigits(1).withId("big-decimal")); this.components.put(SuperDatePicker.class, new SuperDatePicker("Pick a date:").withDatePattern(DatePatterns.YYYY_MM_DD).withValue(LocalDate.now())); this.components.put(SuperDateTimePicker.class, new SuperDateTimePicker("Pick a date and time:").withDatePattern(DatePatterns.M_D_YYYY_SLASH).withValue(LocalDateTime.now())); this.components.put(SuperTextField.class, new SuperTextField("Type something:").withPlaceholder("(nothing typed)").withId("super-text-field")); @@ -377,15 +374,15 @@ public Collection> getDemoableComponentTypes() { * @return A demo page. */ public Component buildDemoPageFor(Class type) { - Component component = this.components.get(type); + final Component component = this.components.get(type); component.getElement().getClassList().add("demo"); - Div result = new Div(); + final Div result = new Div(); result.setSizeUndefined(); result.addClassName("component-page"); - VerticalLayout componentSection = new VerticalLayout(); + final VerticalLayout componentSection = new VerticalLayout(); componentSection.setSizeUndefined(); componentSection.addClassName("component-section"); - Span title = new Span("Demo page of "+component.getClass().getSimpleName()); + final Span title = new Span("Demo page of "+component.getClass().getSimpleName()); title.addClassName("section-header"); title.addClassName("component-header"); componentSection.add(title, component); diff --git a/demo-v14/src/main/java/org/vaadin/miki/DemoPage.java b/demo-v14/src/main/java/org/vaadin/miki/DemoPage.java index dab5c6e5..9cab4853 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/DemoPage.java +++ b/demo-v14/src/main/java/org/vaadin/miki/DemoPage.java @@ -16,19 +16,21 @@ @Route(value = "demo", layout = MainLayout.class) public class DemoPage extends VerticalLayout implements HasUrlParameter, HasDynamicTitle { + private final DemoComponentFactory demoComponentFactory = DemoComponentFactory.get(); + private Class componentType; @Override public void setParameter(BeforeEvent event, String parameter) { this.removeAll(); - DemoComponentFactory.get().getDemoableComponentTypes().stream() + this.demoComponentFactory.getDemoableComponentTypes().stream() .filter(type -> type.getSimpleName().equalsIgnoreCase(parameter)) .findFirst().ifPresentOrElse(this::buildDemoPageFor, this::buildErrorPage); } private void buildDemoPageFor(Class type) { this.componentType = type; - this.add(DemoComponentFactory.get().buildDemoPageFor(type)); + this.add(this.demoComponentFactory.buildDemoPageFor(type)); } private void buildErrorPage() { diff --git a/demo-v14/src/main/java/org/vaadin/miki/MainLayout.java b/demo-v14/src/main/java/org/vaadin/miki/MainLayout.java index 0a22a5d6..d7c84590 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/MainLayout.java +++ b/demo-v14/src/main/java/org/vaadin/miki/MainLayout.java @@ -29,6 +29,8 @@ public class MainLayout extends VerticalLayout implements RouterLayout, AfterNav private final Map tabs = new HashMap<>(); + private final DemoComponentFactory demoComponentFactory = DemoComponentFactory.get(); + public MainLayout() { // set up tabs this.navigationTabs.setWidthFull(); @@ -40,7 +42,7 @@ public MainLayout() { icon.addClassName("tab-icon"); infoLink.add(icon, new Span("SuperFields demo")); this.navigationTabs.add(new Tab(infoLink)); - DemoComponentFactory.get().getDemoableComponentTypes().stream().map(type -> { + this.demoComponentFactory.getDemoableComponentTypes().stream().map(type -> { Tab tab = new Tab(new RouterLink(type.getSimpleName(), DemoPage.class, type.getSimpleName().toLowerCase())); this.tabs.put(type.getSimpleName().toLowerCase(), tab); return tab; diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java index d1990945..bfc4fe5f 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/AbstractSuperNumberField.java @@ -121,6 +121,9 @@ protected AbstractSuperNumberField(T defaultValue, SerializablePredicate nega this.negativityPredicate = negativityPredicate; this.turnToPositiveOperator = turnToPositiveOperator; + if(defaultValue == null) + this.setNullValueAllowed(true); + this.locale = locale; this.format = this.getFormat(locale); if(maxFractionDigits >= 0) @@ -620,7 +623,7 @@ public SELF withReceivingSelectionEventsFromClient(boolean receivingSelectionEve } @Override - public void setNullValueAllowed(boolean allowingNullValue) { + public final void setNullValueAllowed(boolean allowingNullValue) { this.nullValueAllowed = allowingNullValue; if(!allowingNullValue && this.getRawValue().isEmpty()) this.setValue(this.getEmptyValue()); diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperBigDecimalField.java b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperBigDecimalField.java index 9cf293fc..5de285b3 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperBigDecimalField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperBigDecimalField.java @@ -57,6 +57,15 @@ public SuperBigDecimalField(String label, Locale locale) { this(label, locale, -1); } + /** + * Constructs the field with given default value and label, and with default {@link Locale}. + * @param defaultValue Default value. + * @param label Label that accompanies the field. + */ + public SuperBigDecimalField(BigDecimal defaultValue, String label) { + this(defaultValue, label, Locale.getDefault(), -1); + } + /** * Constructs the field with {@link BigDecimal#ZERO} as the default value.. * @param label Label accompanying the field. diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperDoubleField.java b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperDoubleField.java index d103d4e5..3647e3fb 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperDoubleField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperDoubleField.java @@ -56,6 +56,15 @@ public SuperDoubleField(String label, Locale locale) { this(label, locale, -1); } + /** + * Constructs the field with given default value and label, and with default {@link Locale}. + * @param defaultValue Default value. + * @param label Label that accompanies the field. + */ + public SuperDoubleField(Double defaultValue, String label) { + this(defaultValue, label, Locale.getDefault(), -1); + } + /** * Constructs the field with zero as the default value.. * @param label Label accompanying the field. @@ -73,7 +82,7 @@ public SuperDoubleField(String label, Locale locale, int maxFractionDigits) { * @param locale Locale to use for formatting. * @param maxFractionDigits Maximum number of fraction digits allowed (overwrites setting found in {@code locale}. */ - public SuperDoubleField(double defaultValue, String label, Locale locale, int maxFractionDigits) { + public SuperDoubleField(Double defaultValue, String label, Locale locale, int maxFractionDigits) { super(defaultValue, d -> d < 0.0d, Math::abs, label, locale, maxFractionDigits); } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperIntegerField.java b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperIntegerField.java index 011cf7c3..02ebde85 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperIntegerField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperIntegerField.java @@ -47,13 +47,22 @@ public SuperIntegerField(String label, Locale locale) { this(0, label, locale); } + /** + * Constructs the field with given default value and label, and with default {@link Locale}. + * @param defaultValue Default value. + * @param label Label that accompanies the field. + */ + public SuperIntegerField(Integer defaultValue, String label) { + this(defaultValue, label, Locale.getDefault()); + } + /** * Constructs the field. * @param defaultValue Default value. * @param label Label that accompanies the field. * @param locale Locale to use for formatting. */ - public SuperIntegerField(int defaultValue, String label, Locale locale) { + public SuperIntegerField(Integer defaultValue, String label, Locale locale) { super(defaultValue, d -> d < 0, Math::abs, label, locale, 0); } diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperLongField.java b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperLongField.java index b0748289..ed802633 100644 --- a/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperLongField.java +++ b/superfields/src/main/java/org/vaadin/miki/superfields/numbers/SuperLongField.java @@ -44,7 +44,16 @@ public SuperLongField(String label) { * @param locale Locale to use for formatting. */ public SuperLongField(String label, Locale locale) { - this(0, label, locale); + this(0L, label, locale); + } + + /** + * Constructs the field with given default value and label, and with default {@link Locale}. + * @param defaultValue Default value. + * @param label Label that accompanies the field. + */ + public SuperLongField(Long defaultValue, String label) { + this(defaultValue, label, Locale.getDefault()); } /** @@ -53,7 +62,7 @@ public SuperLongField(String label, Locale locale) { * @param label Label that accompanies the field. * @param locale Locale to use for formatting. */ - public SuperLongField(long defaultValue, String label, Locale locale) { + public SuperLongField(Long defaultValue, String label, Locale locale) { super(defaultValue, d -> d < 0, Math::abs, label, locale, 0); } From 558f31e03c218ccdbb7371127b1cc9f55b30861c Mon Sep 17 00:00:00 2001 From: Miki Date: Mon, 6 Jul 2020 18:26:50 +0300 Subject: [PATCH 40/66] #188 fixed wrong path (#193) --- .github/workflows/releasenotes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/releasenotes.yml b/.github/workflows/releasenotes.yml index ee06090b..5fd702ab 100644 --- a/.github/workflows/releasenotes.yml +++ b/.github/workflows/releasenotes.yml @@ -38,7 +38,7 @@ jobs: - name: Update release notes run: | echo -e "\n" | cat milestone-notes.md - superfields/release-notes.md > superfields/release-notes.md.new - sed -i -e "/^$/d" milestone-notes.md.new + sed -i -e "/^$/d" superfields/release-notes.md.new mv superfields/release-notes.md.new superfields/release-notes.md - name: Remove milestone notes run: rm milestone-notes.md From 8b04d63cd93ad3e923ca146c607cf851bdea7241 Mon Sep 17 00:00:00 2001 From: vaadin-miki Date: Mon, 6 Jul 2020 15:35:18 +0000 Subject: [PATCH 41/66] (bot) release notes updated for 0.7.3 --- superfields/release-notes.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/superfields/release-notes.md b/superfields/release-notes.md index b96eb7b8..a32aefa2 100644 --- a/superfields/release-notes.md +++ b/superfields/release-notes.md @@ -1,3 +1,10 @@ +# 0.7.3 - Null as default value in number fields +## New features and enhancements +(nothing reported) +## Changes to API +* \#189 - [Number fields constructors should allow null as default value](https://github.com/vaadin-miki/super-fields/issues/189) +## Bug fixes +* \#189 - [Number fields constructors should allow null as default value](https://github.com/vaadin-miki/super-fields/issues/189) # 0.7.2 - UI-scoped UnloadObserver ## New features and enhancements (nothing reported) From 76306863d662d089f008bca562b44d7cf51aa8dd Mon Sep 17 00:00:00 2001 From: Miki Date: Wed, 8 Jul 2020 21:03:42 +0300 Subject: [PATCH 42/66] #160 done (#197) MultiClickButton ready, together with bunch of other related classes and concepts (including state, a Serializable object that encapsulates state of a given object) --- demo-v14/frontend/styles/demo-styles.css | 2 +- .../org/vaadin/miki/DemoComponentFactory.java | 19 ++ .../events/click/ComponentClickEvent.java | 39 +++ .../events/click/ComponentClickListener.java | 15 ++ .../events/click/ComponentClickNotifier.java | 21 ++ .../miki/events/state/StateChangeEvent.java | 38 +++ .../events/state/StateChangeListener.java | 16 ++ .../events/state/StateChangeNotifier.java | 26 ++ .../org/vaadin/miki/markers/Clickable.java | 17 ++ .../miki/markers/HasComponentAsIcon.java | 24 ++ .../java/org/vaadin/miki/markers/HasIcon.java | 24 ++ .../org/vaadin/miki/markers/HasState.java | 22 ++ .../markers/WithComponentAsIconMixin.java | 24 ++ .../vaadin/miki/markers/WithIconMixin.java | 24 ++ .../vaadin/miki/markers/WithTextMixin.java | 36 +++ .../miki/superfields/buttons/ButtonState.java | 86 +++++++ .../superfields/buttons/MultiClickButton.java | 173 +++++++++++++ .../buttons/SimpleButtonState.java | 228 ++++++++++++++++++ .../buttons/MultiClickButtonTest.java | 82 +++++++ 19 files changed, 915 insertions(+), 1 deletion(-) create mode 100644 superfields/src/main/java/org/vaadin/miki/events/click/ComponentClickEvent.java create mode 100644 superfields/src/main/java/org/vaadin/miki/events/click/ComponentClickListener.java create mode 100644 superfields/src/main/java/org/vaadin/miki/events/click/ComponentClickNotifier.java create mode 100644 superfields/src/main/java/org/vaadin/miki/events/state/StateChangeEvent.java create mode 100644 superfields/src/main/java/org/vaadin/miki/events/state/StateChangeListener.java create mode 100644 superfields/src/main/java/org/vaadin/miki/events/state/StateChangeNotifier.java create mode 100644 superfields/src/main/java/org/vaadin/miki/markers/Clickable.java create mode 100644 superfields/src/main/java/org/vaadin/miki/markers/HasComponentAsIcon.java create mode 100644 superfields/src/main/java/org/vaadin/miki/markers/HasIcon.java create mode 100644 superfields/src/main/java/org/vaadin/miki/markers/HasState.java create mode 100644 superfields/src/main/java/org/vaadin/miki/markers/WithComponentAsIconMixin.java create mode 100644 superfields/src/main/java/org/vaadin/miki/markers/WithIconMixin.java create mode 100644 superfields/src/main/java/org/vaadin/miki/markers/WithTextMixin.java create mode 100644 superfields/src/main/java/org/vaadin/miki/superfields/buttons/ButtonState.java create mode 100644 superfields/src/main/java/org/vaadin/miki/superfields/buttons/MultiClickButton.java create mode 100644 superfields/src/main/java/org/vaadin/miki/superfields/buttons/SimpleButtonState.java create mode 100644 superfields/src/test/java/org/vaadin/miki/superfields/buttons/MultiClickButtonTest.java diff --git a/demo-v14/frontend/styles/demo-styles.css b/demo-v14/frontend/styles/demo-styles.css index 4a6939ae..799e07ea 100644 --- a/demo-v14/frontend/styles/demo-styles.css +++ b/demo-v14/frontend/styles/demo-styles.css @@ -68,4 +68,4 @@ span.highlighted { .tab-icon { margin-right: 5px; -} \ No newline at end of file +} diff --git a/demo-v14/src/main/java/org/vaadin/miki/DemoComponentFactory.java b/demo-v14/src/main/java/org/vaadin/miki/DemoComponentFactory.java index 230438e7..417717fb 100644 --- a/demo-v14/src/main/java/org/vaadin/miki/DemoComponentFactory.java +++ b/demo-v14/src/main/java/org/vaadin/miki/DemoComponentFactory.java @@ -4,7 +4,9 @@ import com.vaadin.flow.component.Component; import com.vaadin.flow.component.FocusNotifier; import com.vaadin.flow.component.HasValue; +import com.vaadin.flow.component.UI; import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.checkbox.Checkbox; import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.html.Div; @@ -22,6 +24,7 @@ import com.vaadin.flow.function.SerializableBiConsumer; import com.vaadin.flow.function.SerializableConsumer; import org.slf4j.LoggerFactory; +import org.vaadin.miki.events.state.StateChangeNotifier; import org.vaadin.miki.events.text.TextSelectionNotifier; import org.vaadin.miki.markers.CanReceiveSelectionEventsFromClient; import org.vaadin.miki.markers.CanSelectText; @@ -30,6 +33,8 @@ import org.vaadin.miki.markers.WithNullValueOptionallyAllowed; import org.vaadin.miki.shared.dates.DatePattern; import org.vaadin.miki.shared.dates.DatePatterns; +import org.vaadin.miki.superfields.buttons.MultiClickButton; +import org.vaadin.miki.superfields.buttons.SimpleButtonState; import org.vaadin.miki.superfields.dates.SuperDatePicker; import org.vaadin.miki.superfields.dates.SuperDateTimePicker; import org.vaadin.miki.superfields.itemgrid.ItemGrid; @@ -115,6 +120,12 @@ private DemoComponentFactory() { ).withId("super-tabs") ); this.components.put(ObservedField.class, new ObservedField()); + this.components.put(MultiClickButton.class, new MultiClickButton( + event -> UI.getCurrent().navigate(""), + new SimpleButtonState("Click to navigate to Info Page").withThemeVariant(ButtonVariant.LUMO_PRIMARY), + new SimpleButtonState("Are you sure?", VaadinIcon.INFO_CIRCLE.create()), + new SimpleButtonState("Really navigate away?", VaadinIcon.INFO.create()).withThemeVariant(ButtonVariant.LUMO_ERROR) + ).withId("multi-click-button")); this.components.put(ComponentObserver.class, new ComponentObserver()); this.components.put(UnloadObserver.class, UnloadObserver.get().withoutQueryingOnUnload()); this.components.put(ItemGrid.class, new ItemGrid>( @@ -160,6 +171,7 @@ private DemoComponentFactory() { this.contentBuilders.put(UnloadObserver.class, this::buildUnloadObserver); this.contentBuilders.put(FocusNotifier.class, this::buildFocusNotifier); this.contentBuilders.put(BlurNotifier.class, this::buildBlurNotifier); + this.contentBuilders.put(StateChangeNotifier.class, this::buildStateChangeNotifier); this.afterLocaleChange.put(SuperIntegerField.class, o -> ((SuperIntegerField)o).setMaximumIntegerDigits(6)); this.afterLocaleChange.put(SuperLongField.class, o -> ((SuperLongField)o).setMaximumIntegerDigits(11)); @@ -209,6 +221,13 @@ private void buildBlurNotifier(Component component, Consumer callba callback.accept(new Component[]{new Span("Leave the demo component to see a notification.")}); } + private void buildStateChangeNotifier(Component component, Consumer callback) { + ((StateChangeNotifier)component).addStateChangeListener(event -> + Notification.show("Component "+component.getClass().getSimpleName()+" changed its state.", NOTIFICATION_TIME, Notification.Position.BOTTOM_END) + ); + callback.accept(new Component[]{new Span("Notifications will be shown when this component changes its state for any reason.")}); + } + private void buildHasLocale(Component component, Consumer callback) { final ComboBox locales = new ComboBox<>("Select locale:", new Locale("pl", "PL"), Locale.UK, Locale.FRANCE, Locale.GERMANY, Locale.CHINA); locales.setItemLabelGenerator(locale -> locale.getDisplayCountry() + " / "+locale.getDisplayLanguage()); diff --git a/superfields/src/main/java/org/vaadin/miki/events/click/ComponentClickEvent.java b/superfields/src/main/java/org/vaadin/miki/events/click/ComponentClickEvent.java new file mode 100644 index 00000000..930506d0 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/events/click/ComponentClickEvent.java @@ -0,0 +1,39 @@ +package org.vaadin.miki.events.click; + +import com.vaadin.flow.component.ClickEvent; +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.ComponentEvent; +import org.vaadin.miki.markers.Clickable; + +/** + * An event for button clicks. + * + * There already is {@link ClickEvent}, but that one is fired automatically by the framework. This event must be explicitly fired by the source component. + * + * @param Event source. + * @author miki + * @since 2020-07-08 + */ +public class ComponentClickEvent extends ComponentEvent { + + private final ClickEvent details; + + /** + * Creates a new event using the given source and indicator whether the + * event originated from the client side or the server side. + * @param source the source component + * @param originalEvent Original click event with even more details. Can be {@code null}. + */ + public ComponentClickEvent(C source, ClickEvent originalEvent) { + super(source, originalEvent.isFromClient()); + this.details = originalEvent; + } + + /** + * Returns the underlying {@link ClickEvent}. + * @return A {@link ClickEvent}. May be {@code null} if this event is not associated with any underlying event. + */ + public ClickEvent getDetails() { + return details; + } +} diff --git a/superfields/src/main/java/org/vaadin/miki/events/click/ComponentClickListener.java b/superfields/src/main/java/org/vaadin/miki/events/click/ComponentClickListener.java new file mode 100644 index 00000000..69de96fb --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/events/click/ComponentClickListener.java @@ -0,0 +1,15 @@ +package org.vaadin.miki.events.click; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.ComponentEventListener; +import org.vaadin.miki.markers.Clickable; + +/** + * Marker interface for objects that react to {@link ComponentClickEvent}s. + * @author miki + * @since 2020-07-08 + */ +@FunctionalInterface +public interface ComponentClickListener extends ComponentEventListener> { + +} diff --git a/superfields/src/main/java/org/vaadin/miki/events/click/ComponentClickNotifier.java b/superfields/src/main/java/org/vaadin/miki/events/click/ComponentClickNotifier.java new file mode 100644 index 00000000..c9cf046d --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/events/click/ComponentClickNotifier.java @@ -0,0 +1,21 @@ +package org.vaadin.miki.events.click; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.shared.Registration; +import org.vaadin.miki.markers.Clickable; + +/** + * Marker interface for objects that broadcast {@link ComponentClickEvent}s. + * @author miki + * @since 2020-07-08 + */ +public interface ComponentClickNotifier { + + /** + * Adds a listener. + * @param listener Listener to be notified when event is fired. + * @return A {@link Registration} that can be used to stop listening to the event. + */ + Registration addClickListener(ComponentClickListener listener); + +} diff --git a/superfields/src/main/java/org/vaadin/miki/events/state/StateChangeEvent.java b/superfields/src/main/java/org/vaadin/miki/events/state/StateChangeEvent.java new file mode 100644 index 00000000..3f3fd230 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/events/state/StateChangeEvent.java @@ -0,0 +1,38 @@ +package org.vaadin.miki.events.state; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.ComponentEvent; +import org.vaadin.miki.markers.HasState; + +import java.io.Serializable; + +/** + * Event associated with the change of component's state. + * Somewhat similar to value change. + * @param Source component. + * @param Information about the state. + */ +public class StateChangeEvent> extends ComponentEvent { + + private final S state; + + /** + * Creates a new event using the given source and indicator whether the + * event originated from the client side or the server side. + * @param source the source component + * @param fromClient true if the event originated from the client + * @param state Current state of the component. + */ + public StateChangeEvent(C source, boolean fromClient, S state) { + super(source, fromClient); + this.state = state; + } + + /** + * Returns current state of the source component. Modifying the returned object may affect the source component, but it is not required nor enforced. + * @return Component state. May never be {@code null}. + */ + public S getState() { + return state; + } +} diff --git a/superfields/src/main/java/org/vaadin/miki/events/state/StateChangeListener.java b/superfields/src/main/java/org/vaadin/miki/events/state/StateChangeListener.java new file mode 100644 index 00000000..09c8813c --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/events/state/StateChangeListener.java @@ -0,0 +1,16 @@ +package org.vaadin.miki.events.state; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.ComponentEventListener; +import org.vaadin.miki.markers.HasState; + +import java.io.Serializable; + +/** + * Marker interface for objects that listen to state changes. + * @param Information about the state. + * @param Source of the changes. + */ +@FunctionalInterface +public interface StateChangeListener> extends ComponentEventListener> { +} diff --git a/superfields/src/main/java/org/vaadin/miki/events/state/StateChangeNotifier.java b/superfields/src/main/java/org/vaadin/miki/events/state/StateChangeNotifier.java new file mode 100644 index 00000000..e0d71611 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/events/state/StateChangeNotifier.java @@ -0,0 +1,26 @@ +package org.vaadin.miki.events.state; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.shared.Registration; +import org.vaadin.miki.markers.HasState; + +import java.io.Serializable; + +/** + * Marker interface for objects that broadcast {@link StateChangeEvent}s. + * @param State type. + * @param Component type. + * @author miki + * @since 2020-07-08 + */ +@FunctionalInterface +public interface StateChangeNotifier> { + + /** + * Adds given {@link StateChangeListener}. + * @param listener Listener to be notified about {@link StateChangeEvent}s. + * @return A {@link Registration} that can be used to stop listening to the event. + */ + Registration addStateChangeListener(StateChangeListener listener); + +} diff --git a/superfields/src/main/java/org/vaadin/miki/markers/Clickable.java b/superfields/src/main/java/org/vaadin/miki/markers/Clickable.java new file mode 100644 index 00000000..bf5ad1f1 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/markers/Clickable.java @@ -0,0 +1,17 @@ +package org.vaadin.miki.markers; + +/** + * Marker interface for components that can be clicked. + * @author miki + * @since 2020-07-07 + */ +@FunctionalInterface +public interface Clickable { + + /** + * Clicks this object. + * What it means is left for implementations to figure out. + */ + void click(); + +} diff --git a/superfields/src/main/java/org/vaadin/miki/markers/HasComponentAsIcon.java b/superfields/src/main/java/org/vaadin/miki/markers/HasComponentAsIcon.java new file mode 100644 index 00000000..2c9f45d4 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/markers/HasComponentAsIcon.java @@ -0,0 +1,24 @@ +package org.vaadin.miki.markers; + +import com.vaadin.flow.component.Component; + +/** + * Marker interface for objects that accept a general {@link Component} as an icon. + * @author miki + * @since 2020-07-07 + */ +public interface HasComponentAsIcon { + + /** + * Sets given {@link Component} as an icon of this object. + * @param icon A {@link Component} to be used as an icon. Can be {@code null} to clear current icon. + */ + void setIcon(Component icon); + + /** + * Returns current icon. + * @return A {@link Component} that serves as an icon for this object. Can be {@code null}. + */ + Component getIcon(); + +} diff --git a/superfields/src/main/java/org/vaadin/miki/markers/HasIcon.java b/superfields/src/main/java/org/vaadin/miki/markers/HasIcon.java new file mode 100644 index 00000000..0bf8ae02 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/markers/HasIcon.java @@ -0,0 +1,24 @@ +package org.vaadin.miki.markers; + +import com.vaadin.flow.component.icon.Icon; + +/** + * Marker interface for objects that have an {@link Icon}. + * @author miki + * @since 2020-07-07 + */ +public interface HasIcon { + + /** + * Sets an icon associated with this object. + * @param icon Icon to set. Can be {@code null} to remove current icon. + */ + void setIcon(Icon icon); + + /** + * Returns current icon. + * @return Current {@link Icon}. Can be {@code null} if no icon has been associated. + */ + Icon getIcon(); + +} diff --git a/superfields/src/main/java/org/vaadin/miki/markers/HasState.java b/superfields/src/main/java/org/vaadin/miki/markers/HasState.java new file mode 100644 index 00000000..7ee682b9 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/markers/HasState.java @@ -0,0 +1,22 @@ +package org.vaadin.miki.markers; + +/** + * Marker interface for objects that have a state. + * State is read-only by default and other actions influence the state the component is in. + * + * @param Object that encapsulates current state. + * + * @author miki + * @since 2020-07-08 + */ +@FunctionalInterface +public interface HasState { + + /** + * Returns the current state of this object. + * The changes to the resulting object should not affect this object. + * @return Current state. May never be {@code null}. + */ + S getState(); + +} diff --git a/superfields/src/main/java/org/vaadin/miki/markers/WithComponentAsIconMixin.java b/superfields/src/main/java/org/vaadin/miki/markers/WithComponentAsIconMixin.java new file mode 100644 index 00000000..9667be78 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/markers/WithComponentAsIconMixin.java @@ -0,0 +1,24 @@ +package org.vaadin.miki.markers; + +import com.vaadin.flow.component.Component; + +/** + * Mixin interface for {@link HasComponentAsIcon}. + * @param Self type. + * @author miki + * @since 2020-07-07 + */ +public interface WithComponentAsIconMixin extends HasComponentAsIcon { + + /** + * Chains {@link #setIcon(Component)} and returns itself. + * @param icon Icon to set. Can be {@code null}. + * @return This. + */ + @SuppressWarnings("unchecked") + default SELF withIcon(Component icon) { + this.setIcon(icon); + return (SELF)this; + } + +} diff --git a/superfields/src/main/java/org/vaadin/miki/markers/WithIconMixin.java b/superfields/src/main/java/org/vaadin/miki/markers/WithIconMixin.java new file mode 100644 index 00000000..fe04a81c --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/markers/WithIconMixin.java @@ -0,0 +1,24 @@ +package org.vaadin.miki.markers; + +import com.vaadin.flow.component.icon.Icon; + +/** + * Mixin interface to allow chaining {@link #setIcon(Icon)}. + * @param Self type. + * @author miki + * @since 2020-07-07 + */ +public interface WithIconMixin extends HasIcon { + + /** + * Chains {@link #setIcon(Icon)} and returns itself. + * @param icon Icon to set. + * @return This. + */ + @SuppressWarnings("unchecked") + default SELF withIcon(Icon icon) { + this.setIcon(icon); + return (SELF)this; + } + +} diff --git a/superfields/src/main/java/org/vaadin/miki/markers/WithTextMixin.java b/superfields/src/main/java/org/vaadin/miki/markers/WithTextMixin.java new file mode 100644 index 00000000..00dbfc92 --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/markers/WithTextMixin.java @@ -0,0 +1,36 @@ +package org.vaadin.miki.markers; + +/** + * Marker interface for objects that have a String property named {@code text}. + * Does not extend nor depend on Vaadin's {@code HasText}, because that interface extends {@code HasElement}. + * @param Self type. + * + * @author miki + * @since 2020-07-07 + */ +public interface WithTextMixin> { + + /** + * Sets text of this object. + * @param text Text to set. + */ + void setText(String text); + + /** + * Returns current text of this object. + * @return Current text. + */ + String getText(); + + /** + * Chains {@link #setText(String)} and returns itself. + * @param text Text to set. + * @return This. + */ + @SuppressWarnings("unchecked") + default SELF withText(String text) { + this.setText(text); + return (SELF)this; + } + +} diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/buttons/ButtonState.java b/superfields/src/main/java/org/vaadin/miki/superfields/buttons/ButtonState.java new file mode 100644 index 00000000..25b888bd --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/superfields/buttons/ButtonState.java @@ -0,0 +1,86 @@ +package org.vaadin.miki.superfields.buttons; + +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.button.ButtonVariant; + +import java.io.Serializable; +import java.util.Collections; +import java.util.Set; + +/** + * Encapsulation of a state of a button (text, icon, style names, etc.). + * @author miki + * @since 2020-07-07 + */ +public interface ButtonState extends Serializable { + + /** + * Returns current text of the button. + * @return Text. + */ + String getText(); + + /** + * Returns current icon of the button. + * @return Icon. + */ + Component getIcon(); + + /** + * Returns current (ordered) set of style class names associated with this state. + * @return An ordered set of style class names. Changes to the returned object affect this object. + */ + Set getClassNames(); + + /** + * Returns current (ordered) set of theme names associated with this state. + * @return An ordered set of theme names. Changes to the returned object affect this object. + */ + Set getThemeNames(); + + /** + * Returns current (ordered) set of theme variants associated with this state. + * @return An ordered set of theme variants. Changes to the returned object affect this object. + */ + Set getThemeVariants(); + + /** + * Converts a {@link Button} into information about its state. + * @param button Button to get state from. + * @return A {@link ButtonState}. + */ + static ButtonState of(Button button) { + final String text = button.getText(); + final Component icon = button.getIcon(); + final Set classes = Collections.unmodifiableSet(button.getClassNames()); + final Set themes = Collections.unmodifiableSet(button.getThemeNames()); + return new ButtonState() { + @Override + public String getText() { + return text; + } + + @Override + public Component getIcon() { + return icon; + } + + @Override + public Set getClassNames() { + return classes; + } + + @Override + public Set getThemeNames() { + return themes; + } + + @Override + public Set getThemeVariants() { + return Collections.emptySet(); + } + }; + } + +} diff --git a/superfields/src/main/java/org/vaadin/miki/superfields/buttons/MultiClickButton.java b/superfields/src/main/java/org/vaadin/miki/superfields/buttons/MultiClickButton.java new file mode 100644 index 00000000..2481023f --- /dev/null +++ b/superfields/src/main/java/org/vaadin/miki/superfields/buttons/MultiClickButton.java @@ -0,0 +1,173 @@ +package org.vaadin.miki.superfields.buttons; + +import com.vaadin.flow.component.ClickEvent; +import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.Composite; +import com.vaadin.flow.component.HasEnabled; +import com.vaadin.flow.component.HasSize; +import com.vaadin.flow.component.HasStyle; +import com.vaadin.flow.component.Tag; +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.button.ButtonVariant; +import com.vaadin.flow.shared.Registration; +import org.vaadin.miki.events.click.ComponentClickEvent; +import org.vaadin.miki.events.click.ComponentClickListener; +import org.vaadin.miki.events.click.ComponentClickNotifier; +import org.vaadin.miki.events.state.StateChangeEvent; +import org.vaadin.miki.events.state.StateChangeListener; +import org.vaadin.miki.events.state.StateChangeNotifier; +import org.vaadin.miki.markers.Clickable; +import org.vaadin.miki.markers.HasState; +import org.vaadin.miki.markers.WithIdMixin; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * A button that needs multiple clicks before a regular click listener can be invoked. + * + * @author miki + * @since 2020-07-06 + */ +@Tag("multi-click-button") +public class MultiClickButton extends Composite