@@ -175,7 +175,6 @@ import com.vaadin.client.widget.grid.sort.SortOrder; | |||
import com.vaadin.client.widgets.Escalator.AbstractRowContainer; | |||
import com.vaadin.client.widgets.Escalator.SubPartArguments; | |||
import com.vaadin.client.widgets.Grid.Editor.State; | |||
import com.vaadin.client.widgets.Grid.StaticSection.StaticCell; | |||
import com.vaadin.client.widgets.Grid.StaticSection.StaticRow; | |||
import com.vaadin.shared.Range; | |||
import com.vaadin.shared.Registration; | |||
@@ -5123,8 +5122,11 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, | |||
@Override | |||
public void onDrop() { | |||
final int draggedColumnIndex = eventCell.getColumnIndex(); | |||
final int colspan = header.getRow(eventCell.getRowIndex()) | |||
.getCell(eventCell.getColumn()).getColspan(); | |||
final StaticRow<?> draggedCellRow = header | |||
.getRow(eventCell.getRowIndex()); | |||
int colspan = draggedCellRow | |||
.getSizeOfCellGroup(getColumn(draggedColumnIndex)); | |||
colspan = colspan == 0 ? 1 : colspan; | |||
if (latestColumnDropIndex != draggedColumnIndex | |||
&& latestColumnDropIndex != draggedColumnIndex + colspan) { | |||
List<Column<?, T>> columns = getColumns(); | |||
@@ -5261,13 +5263,12 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, | |||
} | |||
final boolean isDraggedCellRow = row.equals(draggedCellRow); | |||
for (int cellColumnIndex = frozenColumns; cellColumnIndex < getColumnCount(); cellColumnIndex++) { | |||
StaticCell cell = row.getCell(getColumn(cellColumnIndex)); | |||
int colspan = cell.getColspan(); | |||
int colspan = row | |||
.getSizeOfCellGroup(getColumn(cellColumnIndex)); | |||
if (colspan <= 1) { | |||
continue; | |||
} | |||
final int cellColumnRightIndex = cellColumnIndex + row | |||
.getSizeOfCellGroup(getColumn(cellColumnIndex)); | |||
final int cellColumnRightIndex = cellColumnIndex + colspan; | |||
final Range cellRange = Range.between(cellColumnIndex, | |||
cellColumnRightIndex); | |||
final boolean intersects = draggedCellRange |
@@ -4485,8 +4485,11 @@ public class Grid<T> extends ResizeComposite implements HasSelectionHandlers<T>, | |||
@Override | |||
public void onDrop() { | |||
final int draggedColumnIndex = eventCell.getColumnIndex(); | |||
final int colspan = header.getRow(eventCell.getRowIndex()) | |||
.getCell(eventCell.getColumn()).getColspan(); | |||
final StaticRow<?> draggedCellRow = header | |||
.getRow(eventCell.getRowIndex()); | |||
Set<Column<?, ?>> cellGroup = draggedCellRow | |||
.getCellGroupForColumn(getColumn(draggedColumnIndex)); | |||
final int colspan = cellGroup == null ? 1 : cellGroup.size(); | |||
if (latestColumnDropIndex != draggedColumnIndex | |||
&& latestColumnDropIndex != draggedColumnIndex + colspan) { | |||
List<Column<?, T>> columns = getColumns(); |
@@ -31,7 +31,7 @@ | |||
<!-- Used in OSGi manifests --> | |||
<javax.validation.version>2.0.1.Final</javax.validation.version> | |||
<jsoup.version>1.14.2</jsoup.version> | |||
<jsoup.version>1.14.3</jsoup.version> | |||
<javax.portlet.version>2.0</javax.portlet.version> | |||
<vaadin.sass.version>0.9.13</vaadin.sass.version> | |||
<!-- Note that this should be kept in sync with the class Constants --> |
@@ -47,7 +47,9 @@ def getTestStatusHtml(): | |||
return createTableRow(traffic_light.format(color="black"), "Test status: unable to retrieve status of tests") | |||
else: | |||
test_failures_json = test_failures_request.json() | |||
if test_failures_json["count"] == 0: | |||
# nowadays the responds doesn't contain count keyword when the build is successful | |||
# while count word can be found when build fails | |||
if "count" not in test_failures_json: | |||
return createTableRow(traffic_light.format(color="green"), "Test status: all tests passing") | |||
else: | |||
return createTableRow(traffic_light.format(color="red"), "Test status: there are " + str(test_failures_json["count"]) + " failing tests, <a href={}>check the build report</a>".format(buildResultUrl)) |
@@ -33,7 +33,7 @@ def checkArchetypeMetaData(archetypeMetadataUrl, version): | |||
if archetype_metadata_request.status_code != 200: | |||
return createTableRow(traffic_light.format(color="black"), "Check archetype metadata: <a href='{url}'>unable to retrieve metadata from {url}</a>".format(url=archetypeMetadataUrl)) | |||
else: | |||
if "version=\"{version}\"".format(version=version) in archetype_metadata_request.content: | |||
if "version=\"{version}\"".format(version=version) in archetype_metadata_request.text: | |||
return createTableRow(traffic_light.format(color="green"), "Check archetype metadata: <a href='{url}'>metadata is correct for {url}</a>".format(url=archetypeMetadataUrl)) | |||
else: | |||
return createTableRow(traffic_light.format(color="red"), "Check archetype metadata: <a href='{url}'>metadata seems to be incorrect for {url}</a>".format(url=archetypeMetadataUrl)) | |||
@@ -66,5 +66,5 @@ content += createTableRow("", "<a href=\"https://github.com/vaadin/framework/rel | |||
content += "</table></body></html>" | |||
with open("result/report.html", "wb") as f: | |||
with open("result/report.html", "w") as f: | |||
f.write(content) |
@@ -4,7 +4,7 @@ Bundle-Version: ${osgi.bundle.version} | |||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8 | |||
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0 | |||
Import-Package: com.vaadin.sass.*;resolution:=optional,\ | |||
com.liferay.portal.kernel.util;resolution:=optional;version='[7.0.0,13.0.0)',\ | |||
com.liferay.portal.kernel.util;resolution:=optional;version='[7.0.0,17.0.0)',\ | |||
javax.portlet*;resolution:=optional,\ | |||
javax.validation*;resolution:=optional;version='${javax.validation.version}',\ | |||
org.atmosphere*;resolution:=optional;version='${atmosphere.runtime.version}',\ |
@@ -1239,8 +1239,7 @@ public class Binder<BEAN> implements Serializable { | |||
/** | |||
* Sets the field value by invoking the getter function on the given | |||
* bean. The default listener attached to the field will be removed for | |||
* the duration of this update. | |||
* bean. | |||
* | |||
* @param bean | |||
* the bean to fetch the property value from | |||
@@ -1252,13 +1251,12 @@ public class Binder<BEAN> implements Serializable { | |||
*/ | |||
private void initFieldValue(BEAN bean, boolean writeBackChangedValues) { | |||
assert bean != null; | |||
assert onValueChange != null; | |||
valueInit = true; | |||
try { | |||
TARGET originalValue = getter.apply(bean); | |||
convertAndSetFieldValue(originalValue); | |||
if (writeBackChangedValues && setter != null) { | |||
if (writeBackChangedValues && setter != null && !readOnly) { | |||
doConversion().ifOk(convertedValue -> { | |||
if (!Objects.equals(originalValue, convertedValue)) { | |||
setter.accept(bean, convertedValue); | |||
@@ -1891,7 +1889,6 @@ public class Binder<BEAN> implements Serializable { | |||
if (bean == null) { | |||
clearFields(); | |||
} else { | |||
changedBindings.clear(); | |||
getBindings().forEach(binding -> { | |||
// Some bindings may have been removed from binder | |||
// during readBean. We should skip those bindings to | |||
@@ -1902,6 +1899,7 @@ public class Binder<BEAN> implements Serializable { | |||
binding.initFieldValue(bean, false); | |||
} | |||
}); | |||
changedBindings.clear(); | |||
getValidationStatusHandler().statusChange( | |||
BinderValidationStatus.createUnresolvedStatus(this)); | |||
fireStatusChangeEvent(false); | |||
@@ -2001,7 +1999,7 @@ public class Binder<BEAN> implements Serializable { | |||
* updated, {@code false} otherwise | |||
*/ | |||
public boolean writeBeanIfValid(BEAN bean) { | |||
return doWriteIfValid(bean, new ArrayList<>(bindings)).isOk(); | |||
return doWriteIfValid(bean, bindings).isOk(); | |||
} | |||
/** | |||
@@ -2024,19 +2022,26 @@ public class Binder<BEAN> implements Serializable { | |||
Objects.requireNonNull(bean, "bean cannot be null"); | |||
List<ValidationResult> binderResults = Collections.emptyList(); | |||
// make a copy of the incoming bindings to avoid their modifications | |||
// during validation | |||
Collection<Binding<BEAN, ?>> currentBindings = new ArrayList<>( | |||
bindings); | |||
// First run fields level validation, if no validation errors then | |||
// update bean | |||
List<BindingValidationStatus<?>> bindingResults = bindings.stream() | |||
.map(b -> b.validate(false)).collect(Collectors.toList()); | |||
List<BindingValidationStatus<?>> bindingResults = currentBindings | |||
.stream().map(b -> b.validate(false)) | |||
.collect(Collectors.toList()); | |||
if (bindingResults.stream() | |||
.noneMatch(BindingValidationStatus::isError)) { | |||
// Store old bean values so we can restore them if validators fail | |||
Map<Binding<BEAN, ?>, Object> oldValues = getBeanState(bean, | |||
bindings); | |||
currentBindings); | |||
bindings.forEach(binding -> ((BindingImpl<BEAN, ?, ?>) binding) | |||
.writeFieldValue(bean)); | |||
currentBindings | |||
.forEach(binding -> ((BindingImpl<BEAN, ?, ?>) binding) | |||
.writeFieldValue(bean)); | |||
// Now run bean level validation against the updated bean | |||
binderResults = validateBean(bean); | |||
if (binderResults.stream().anyMatch(ValidationResult::isError)) { | |||
@@ -2047,7 +2052,7 @@ public class Binder<BEAN> implements Serializable { | |||
* Changes have been successfully saved. The set is only cleared | |||
* when the changes are stored in the currently set bean. | |||
*/ | |||
bindings.clear(); | |||
changedBindings.clear(); | |||
} else if (getBean() == null) { | |||
/* | |||
* When using readBean and writeBean there is no knowledge of |
@@ -60,7 +60,7 @@ import elemental.json.JsonObject; | |||
public class DataCommunicator<T> extends AbstractExtension { | |||
private Registration dataProviderUpdateRegistration; | |||
private static final int MAXIMUM_ALLOWED_ROWS = 500; | |||
private int maximumAllowedRows = 500; | |||
/** | |||
* Simple implementation of collection data provider communication. All data | |||
@@ -316,14 +316,24 @@ public class DataCommunicator<T> extends AbstractExtension { | |||
} | |||
/** | |||
* Set the maximum allowed rows to be fetched in one query. | |||
* Get the maximum allowed rows to be fetched in one query. | |||
* | |||
* @return Maximum allowed rows for one query. | |||
* @since 8.14.1 | |||
*/ | |||
protected int getMaximumAllowedRows() { | |||
return MAXIMUM_ALLOWED_ROWS; | |||
} | |||
return maximumAllowedRows; | |||
} | |||
/** | |||
* Set the maximum allowed rows to be fetched in one query. | |||
* | |||
* @param maximumAllowedRows Maximum allowed rows for one query. | |||
* @since | |||
*/ | |||
public void setMaximumAllowedRows(int maximumAllowedRows) { | |||
this.maximumAllowedRows = maximumAllowedRows; | |||
} | |||
/** | |||
* Triggered when rows have been dropped from the client side cache. |
@@ -422,6 +422,23 @@ public class Page implements Serializable { | |||
target.addText(css); | |||
target.endTag("css-string"); | |||
} | |||
@Override | |||
public boolean equals(Object obj) { | |||
if (obj == this) { | |||
return true; | |||
} else if (obj instanceof InjectedStyleString) { | |||
InjectedStyleString that = (InjectedStyleString) obj; | |||
return css.equals(that.css); | |||
} else { | |||
return false; | |||
} | |||
} | |||
@Override | |||
public int hashCode() { | |||
return css.hashCode(); | |||
} | |||
} | |||
private static class InjectedStyleResource implements InjectedStyle { | |||
@@ -466,9 +483,11 @@ public class Page implements Serializable { | |||
*/ | |||
public static class Styles implements Serializable { | |||
private LinkedHashSet<InjectedStyle> injectedStyles = new LinkedHashSet<>(); | |||
// For internal use only, visibility is package for enabling testing | |||
LinkedHashSet<InjectedStyle> injectedStyles = new LinkedHashSet<>(); | |||
private LinkedHashSet<InjectedStyle> pendingInjections = new LinkedHashSet<>(); | |||
// For internal use only, visibility is package for enabling testing | |||
LinkedHashSet<InjectedStyle> pendingInjections = new LinkedHashSet<>(); | |||
private final UI ui; | |||
@@ -488,8 +507,12 @@ public class Page implements Serializable { | |||
"Cannot inject null CSS string"); | |||
} | |||
pendingInjections.add(new InjectedStyleString(css)); | |||
ui.markAsDirty(); | |||
InjectedStyleString injectedStyleString = new InjectedStyleString( | |||
css); | |||
if (!injectedStyles.contains(injectedStyleString) | |||
&& pendingInjections.add(injectedStyleString)) { | |||
ui.markAsDirty(); | |||
} | |||
} | |||
/** | |||
@@ -1345,8 +1368,8 @@ public class Page implements Serializable { | |||
* Sets the page title. The page title is displayed by the browser e.g. as | |||
* the title of the browser window or as the title of the tab. | |||
* <p> | |||
* If the title is set to null, it will not left as-is. Set to empty string | |||
* to clear the title. | |||
* If this value is set to null, the previously set page title will be left | |||
* as-is. Set to empty string to clear the title. | |||
* | |||
* @param title | |||
* the page title to set |
@@ -10,6 +10,7 @@ import static org.junit.Assert.assertSame; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
import java.io.Serializable; | |||
import java.math.BigDecimal; | |||
import java.text.DecimalFormat; | |||
import java.text.NumberFormat; | |||
@@ -1518,6 +1519,121 @@ public class BinderTest extends BinderTestBase<Binder<Person>, Person> { | |||
assertEquals(new Double(2000), item.getSalaryDouble()); | |||
} | |||
// See: https://github.com/vaadin/framework/issues/9581 | |||
@Test | |||
public void withConverter_hasChangesFalse() { | |||
TextField nameField = new TextField(); | |||
nameField.setValue(""); | |||
TextField rentField = new TextField(); | |||
rentField.setValue(""); | |||
rentField.addValueChangeListener(event -> { | |||
nameField.setValue("Name"); | |||
}); | |||
item.setRent(BigDecimal.valueOf(10)); | |||
binder.forField(nameField).bind(Person::getFirstName, Person::setFirstName); | |||
binder.forField(rentField).withConverter(new EuroConverter("")) | |||
.withNullRepresentation(BigDecimal.valueOf(0d)) | |||
.bind(Person::getRent, Person::setRent); | |||
binder.readBean(item); | |||
assertFalse(binder.hasChanges()); | |||
assertEquals("€ 10.00", rentField.getValue()); | |||
assertEquals("Name", nameField.getValue()); | |||
} | |||
@Test | |||
public void invalidUsage_modifyFieldsInsideValidator_binderDoesNotThrow() { | |||
TextField field = new TextField(); | |||
AtomicBoolean validatorIsExecuted = new AtomicBoolean(); | |||
binder.forField(field).asRequired().withValidator((val, context) -> { | |||
nameField.setValue("foo"); | |||
ageField.setValue("bar"); | |||
validatorIsExecuted.set(true); | |||
return ValidationResult.ok(); | |||
}).bind(Person::getEmail, Person::setEmail); | |||
binder.forField(nameField).bind(Person::getFirstName, | |||
Person::setFirstName); | |||
binder.forField(ageField).bind(Person::getLastName, | |||
Person::setLastName); | |||
binder.setBean(new Person()); | |||
field.setValue("baz"); | |||
// mostly self control, the main check is: not exception is thrown | |||
assertTrue(validatorIsExecuted.get()); | |||
} | |||
public void setBean_readOnlyBinding_propertyBinding_valueIsNotUpdated() { | |||
Binder<ExampleBean> binder = new Binder<>(ExampleBean.class); | |||
binder.forField(nameField).withNullRepresentation("") | |||
.withConverter(new TestConverter()).bind("vals") | |||
.setReadOnly(true); | |||
ExampleBean bean = new ExampleBean(); | |||
SubPropClass val = new SubPropClass(); | |||
bean.setVals(val); | |||
binder.setBean(bean); | |||
assertSame(val, bean.getVals()); | |||
} | |||
@Test | |||
public void setBean_readOnlyBinding_accessorsBiding_valueIsNotUpdated() { | |||
Binder<ExampleBean> binder = new Binder<>(ExampleBean.class); | |||
binder.forField(nameField).withNullRepresentation("") | |||
.withConverter(new TestConverter()) | |||
.bind(ExampleBean::getVals, ExampleBean::setVals) | |||
.setReadOnly(true); | |||
ExampleBean bean = new ExampleBean(); | |||
SubPropClass val = new SubPropClass(); | |||
bean.setVals(val); | |||
binder.setBean(bean); | |||
assertSame(val, bean.getVals()); | |||
} | |||
public static class ExampleBean implements Serializable { | |||
private SubPropClass vals; | |||
public SubPropClass getVals() { | |||
return vals; | |||
} | |||
public void setVals(SubPropClass vals) { | |||
this.vals = vals; | |||
} | |||
} | |||
public static class SubPropClass implements Serializable { | |||
private String val1 = "Val1"; | |||
@Override | |||
public String toString() { | |||
return val1; | |||
} | |||
} | |||
public static class TestConverter | |||
implements Converter<String, SubPropClass> { | |||
@Override | |||
public Result<SubPropClass> convertToModel(String value, | |||
ValueContext context) { | |||
return Result.ok(null); | |||
} | |||
@Override | |||
public String convertToPresentation(SubPropClass value, | |||
ValueContext context) { | |||
return value != null ? value.toString() : null; | |||
} | |||
}; | |||
private TextField createNullAnd42RejectingFieldWithEmptyValue( | |||
String emptyValue) { | |||
return new TextField() { |
@@ -322,4 +322,12 @@ public class DataCommunicatorTest { | |||
communicator.onRequestRows(0, communicator.getMaximumAllowedRows() + 10, | |||
0, 0); | |||
} | |||
@Test | |||
public void requestTooMuchRowsOverride() { | |||
TestDataCommunicator communicator = new TestDataCommunicator(); | |||
int maxRows = communicator.getMaximumAllowedRows(); | |||
communicator.setMaximumAllowedRows(maxRows + 100); | |||
communicator.onRequestRows(0, maxRows + 10, 0, 0); | |||
} | |||
} |
@@ -1,7 +1,10 @@ | |||
package com.vaadin.server; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import java.io.Writer; | |||
import org.easymock.EasyMock; | |||
import org.junit.Test; | |||
@@ -45,6 +48,27 @@ public class PageTest { | |||
page.getState(false).hasResizeListeners); | |||
} | |||
@Test | |||
public void cssStringInjectedTwice() throws PaintException { | |||
TestPage page = new TestPage(EasyMock.createMock(UI.class), | |||
EasyMock.createMock(PageState.class)); | |||
JsonPaintTarget paintTarget = new JsonPaintTarget( | |||
EasyMock.createMock(LegacyCommunicationManager.class), | |||
EasyMock.createMock(Writer.class), true); | |||
page.getStyles().add(".my-style { color: red; }"); | |||
assertEquals(page.getStyles().pendingInjections.size(), 1); | |||
page.paintContent(paintTarget); | |||
assertEquals(page.getStyles().pendingInjections.size(), 0); | |||
assertEquals(page.getStyles().injectedStyles.size(), 1); | |||
page.getStyles().add(".my-style { color: red; }"); | |||
assertEquals(page.getStyles().pendingInjections.size(), 0); | |||
page.paintContent(paintTarget); | |||
assertEquals(page.getStyles().pendingInjections.size(), 0); | |||
assertEquals(page.getStyles().injectedStyles.size(), 1); | |||
} | |||
private static class TestPage extends Page { | |||
public TestPage(UI uI, PageState state) { |
@@ -12,7 +12,7 @@ | |||
<packaging>war</packaging> | |||
<properties> | |||
<jetty.skip>false</jetty.skip> | |||
<jetty.version>9.3.21.v20170918</jetty.version> | |||
<jetty.version>9.4.38.v20210224</jetty.version> | |||
<server.name>jetty9</server.name> | |||
</properties> | |||
@@ -2,13 +2,14 @@ | |||
* | |||
* @group table | |||
*/ | |||
$v-table-row-height: $v-unit-size !default; | |||
$v-table-border-width: first-number($v-border) !default; | |||
/** | |||
* | |||
* @group table | |||
*/ | |||
$v-table-border-width: first-number($v-border) !default; | |||
$v-table-row-height: $v-unit-size !default; | |||
$v-table-body-row-height: round($v-table-row-height + $v-table-border-width) !default; | |||
/** | |||
* | |||
@@ -229,7 +230,7 @@ $v-table-background-color: null !default; | |||
.#{$primary-stylename}-cell-content { | |||
border-left: $v-table-border-width solid $border-color; | |||
overflow: hidden; | |||
height: $v-table-row-height; | |||
height: $v-table-body-row-height; | |||
vertical-align: middle; | |||
&:first-child { | |||
@@ -279,9 +280,11 @@ $v-table-background-color: null !default; | |||
.#{$primary-stylename}-table td { | |||
border-top: $v-table-border-width solid $border-color; | |||
box-sizing: border-box; | |||
} | |||
.#{$primary-stylename}-table tr:first-child > td { | |||
height: $v-table-row-height; | |||
border-top: none; | |||
} | |||
@@ -522,7 +525,7 @@ $v-table-background-color: null !default; | |||
.#{$primary-stylename}-row-drag-bottom td.#{$primary-stylename}-cell-content { | |||
border-bottom: 2px solid $v-focus-color; | |||
height: $v-table-row-height - 2px; | |||
height: $v-table-body-row-height - 2px; | |||
} | |||
.#{$primary-stylename}-row-drag-bottom .#{$primary-stylename}-cell-wrapper { | |||
@@ -531,7 +534,7 @@ $v-table-background-color: null !default; | |||
.#{$primary-stylename}-row-drag-top td.#{$primary-stylename}-cell-content { | |||
border-top: 2px solid $v-focus-color; | |||
height: $v-table-row-height - 2px + $v-table-border-width; | |||
height: $v-table-body-row-height - 2px + $v-table-border-width; | |||
} | |||
.#{$primary-stylename}-row-drag-top .#{$primary-stylename}-cell-wrapper { | |||
@@ -679,7 +682,7 @@ $v-table-background-color: null !default; | |||
.#{$primary-stylename}-row-drag-top .#{$primary-stylename}-cell-content, | |||
.#{$primary-stylename}-row-drag-bottom .#{$primary-stylename}-cell-content { | |||
height: $v-table-row-height - 1px; | |||
height: $v-table-body-row-height - 1px; | |||
} | |||
} | |||