summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPekka Hyvönen <pekka@vaadin.com>2015-02-19 17:21:22 +0200
committerPekka Hyvönen <pekka@vaadin.com>2015-02-23 15:02:39 +0200
commitbff2a3f558ea0416ae48b5595b59057a3475d6b6 (patch)
tree978c92663379919221f55ed6bad4a88b4e1f20ff
parentad7bcdc7d22cedf30d76dd6d1ba7a1c9bcabdd53 (diff)
downloadvaadin-framework-bff2a3f558ea0416ae48b5595b59057a3475d6b6.tar.gz
vaadin-framework-bff2a3f558ea0416ae48b5595b59057a3475d6b6.zip
Theming and UX for Grid column reordering. (#16643)
- Show sorting and focus on the dragged header. - Keep the focused header/cell the same after drag. - Make the drop marker get the same color as the grid selection. - Make dragged header and the drag element theme customizable - Valo related theming: little opacity, proper positioning Change-Id: Ia1c6f72ef2c7b4333e64ac410e50ef3688461749
-rw-r--r--WebContent/VAADIN/themes/base/grid/grid.scss5
-rw-r--r--WebContent/VAADIN/themes/valo/components/_grid.scss9
-rw-r--r--client/src/com/vaadin/client/widgets/Grid.java45
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java44
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnReorderEventTest.java74
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnReorderTest.java233
-rw-r--r--uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnReorderTest.java32
7 files changed, 326 insertions, 116 deletions
diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss
index d0bae911db..35024e27c0 100644
--- a/WebContent/VAADIN/themes/base/grid/grid.scss
+++ b/WebContent/VAADIN/themes/base/grid/grid.scss
@@ -14,6 +14,7 @@ $v-grid-row-focused-background-color: null !default;
$v-grid-header-row-height: null !default;
$v-grid-header-font-size: $v-font-size !default;
$v-grid-header-background-color: $v-grid-row-background-color !default;
+$v-grid-header-drag-marked-color: $v-grid-row-selected-background-color !default;
$v-grid-footer-row-height: $v-grid-header-row-height !default;
$v-grid-footer-font-size: $v-grid-header-font-size !default;
@@ -61,12 +62,14 @@ $v-grid-editor-background-color: $v-grid-row-background-color !default;
> .#{$primaryStyleName}-cell {
border: $v-grid-border;
+ margin-top: -10px;
opacity: 0.9;
filter: alpha(opacity=90); // IE8
+ z-index: 30000;
}
> .#{$primaryStyleName}-drop-marker {
- background-color: #197de1;
+ background-color: $v-grid-header-drag-marked-color;
position: absolute;
width: 3px;
}
diff --git a/WebContent/VAADIN/themes/valo/components/_grid.scss b/WebContent/VAADIN/themes/valo/components/_grid.scss
index 4cac9c5e43..0d6d2ff0a6 100644
--- a/WebContent/VAADIN/themes/valo/components/_grid.scss
+++ b/WebContent/VAADIN/themes/valo/components/_grid.scss
@@ -40,6 +40,15 @@ $v-grid-animations-enabled: $v-animations-enabled !default;
text-shadow: valo-text-shadow($font-color: valo-font-color($v-grid-header-background-color), $background-color: $v-grid-header-background-color);
}
+ .#{$primary-stylename}-header .#{$primary-stylename}-cell.dragged {
+ @include opacity(0.5, false);
+ @include transition (opacity .3s ease-in-out);
+ }
+
+ .#{$primary-stylename}-header .#{$primary-stylename}-cell.dragged-column-header {
+ margin-top: round($v-grid-row-height/-2);
+ }
+
.#{$primary-stylename}-footer .#{$primary-stylename}-cell {
@include valo-gradient($v-grid-footer-background-color);
text-shadow: valo-text-shadow($font-color: valo-font-color($v-grid-footer-background-color), $background-color: $v-grid-footer-background-color);
diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java
index 643f223068..d54c023e3d 100644
--- a/client/src/com/vaadin/client/widgets/Grid.java
+++ b/client/src/com/vaadin/client/widgets/Grid.java
@@ -2932,10 +2932,6 @@ public class Grid<T> extends ResizeComposite implements
dropMarker.getStyle().setLeft(dropMarkerLeft, Unit.PX);
}
- private void resolveDragElementVerticalPosition() {
- dragElement.getStyle().setTop(-10, Unit.PX);
- }
-
private void resolveDragElementHorizontalPosition(final int clientX) {
int left = clientX - table.getAbsoluteLeft();
left = Math.max(0, Math.min(left, table.getClientWidth()));
@@ -2946,22 +2942,23 @@ public class Grid<T> extends ResizeComposite implements
@Override
public void showDragElement() {
initHeaderDragElementDOM();
- // TODO this clones also some unwanted style names, should confirm
- // with UX what we want to show (focus/sort indicator)
+ // needs to clone focus and sorting indicators too (UX)
dragElement = DOM.clone(eventCell.getElement(), true);
dragElement.getStyle().clearWidth();
dropMarker.getStyle().setProperty("height",
dragElement.getStyle().getHeight());
tableHeader.appendChild(dragElement);
- // might need to change this on fly once sorting with multiple
- // header rows is possible
- resolveDragElementVerticalPosition();
+ // mark the column being dragged for styling
+ eventCell.getElement().addClassName("dragged");
+ // mark the floating cell, for styling & testing
+ dragElement.addClassName("dragged-column-header");
}
@Override
public void removeDragElement() {
table.removeFromParent();
dragElement.removeFromParent();
+ eventCell.getElement().removeClassName("dragged");
}
@Override
@@ -2980,10 +2977,40 @@ public class Grid<T> extends ResizeComposite implements
@SuppressWarnings("unchecked")
Column<?, T>[] array = reordered.toArray(new Column[reordered
.size()]);
+ transferCellFocusOnDrop();
setColumnOrder(array);
} // else no reordering
}
+ private void transferCellFocusOnDrop() {
+ final Cell focusedCell = cellFocusHandler.getFocusedCell();
+ if (focusedCell != null) {
+ final int focusedCellColumnIndex = focusedCell.getColumn();
+ final int focusedRowIndex = focusedCell.getRow();
+ final int draggedColumnIndex = eventCell.getColumnIndex();
+ // transfer focus if it was effected by the new column order
+ // FIXME if the dragged column is partly outside of the view
+ // port and the focused cell is +-1 of the dragged column, the
+ // grid scrolls to the right end. maybe fixed when the automatic
+ // scroll handling is implemented?
+ final RowContainer rowContainer = escalator
+ .findRowContainer(focusedCell.getElement());
+ if (focusedCellColumnIndex == draggedColumnIndex) {
+ // move with the dragged column
+ cellFocusHandler.setCellFocus(focusedRowIndex,
+ latestColumnDropIndex, rowContainer);
+ } else if (latestColumnDropIndex <= focusedCellColumnIndex
+ && draggedColumnIndex > focusedCellColumnIndex) {
+ cellFocusHandler.setCellFocus(focusedRowIndex,
+ focusedCellColumnIndex + 1, rowContainer);
+ } else if (latestColumnDropIndex >= focusedCellColumnIndex
+ && draggedColumnIndex < focusedCellColumnIndex) {
+ cellFocusHandler.setCellFocus(focusedRowIndex,
+ focusedCellColumnIndex - 1, rowContainer);
+ }
+ }
+ }
+
@Override
public void onDragCancel() {
// cancel next click so that we may prevent column sorting if
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java
index 0e339ec0ae..e7fbc14d89 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeaturesTest.java
@@ -15,6 +15,9 @@
*/
package com.vaadin.tests.components.grid.basicfeatures;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
import java.util.ArrayList;
import java.util.List;
@@ -132,4 +135,45 @@ public abstract class GridBasicFeaturesTest extends MultiBrowserTest {
testUrl = testUrl.replace("?&", "?");
driver.get(testUrl);
}
+
+ protected void focusCell(int row, int column) {
+ getGridElement().getCell(row, column).click();
+ }
+
+ protected void assertColumnHeaderOrder(int... indices) {
+ List<TestBenchElement> headers = getGridHeaderRowCells();
+ for (int i = 0; i < indices.length; i++) {
+ assertColumnHeader("Column " + indices[i], headers.get(i));
+ }
+ }
+
+ protected void assertColumnHeader(String expectedHeaderCaption,
+ TestBenchElement testBenchElement) {
+ assertEquals(expectedHeaderCaption.toLowerCase(), testBenchElement
+ .getText().toLowerCase());
+ }
+
+ protected WebElement getDefaultColumnHeader(int index) {
+ List<TestBenchElement> headerRowCells = getGridHeaderRowCells();
+ return headerRowCells.get(index);
+ }
+
+ protected void dragDefaultColumnHeader(int draggedColumnHeaderIndex,
+ int onTopOfColumnHeaderIndex, int xOffsetFromColumnTopLeftCorner) {
+ new Actions(getDriver())
+ .clickAndHold(getDefaultColumnHeader(draggedColumnHeaderIndex))
+ .moveToElement(
+ getDefaultColumnHeader(onTopOfColumnHeaderIndex),
+ xOffsetFromColumnTopLeftCorner, 0).release().perform();
+ }
+
+ protected void assertColumnIsSorted(int index) {
+ WebElement columnHeader = getDefaultColumnHeader(index);
+ assertTrue(columnHeader.getAttribute("class").contains("sort"));
+ }
+
+ protected void assertFocusedCell(int row, int column) {
+ assertTrue(getGridElement().getCell(row, column).getAttribute("class")
+ .contains("focused"));
+ }
}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnReorderEventTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnReorderEventTest.java
deleted file mode 100644
index eda064284c..0000000000
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnReorderEventTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2000-2014 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.tests.components.grid.basicfeatures;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.openqa.selenium.By;
-import org.openqa.selenium.WebElement;
-
-import com.vaadin.testbench.elements.GridElement.GridCellElement;
-import com.vaadin.tests.annotations.TestCategory;
-
-/**
- *
- * @since
- * @author Vaadin Ltd
- */
-@TestCategory("grid")
-public class GridColumnReorderEventTest extends GridBasicClientFeaturesTest {
-
- @Before
- public void before() {
- openTestURL();
- }
-
- @Test
- public void columnReorderEventTriggered() {
- final int firstIndex = 3;
- final int secondIndex = 4;
- final String firstHeaderText = getGridElement().getHeaderCell(0,
- firstIndex).getText();
- final String secondHeaderText = getGridElement().getHeaderCell(0,
- secondIndex).getText();
- selectMenuPath("Component", "Internals", "Listeners",
- "Add ColumnReorder listener");
- selectMenuPath("Component", "Columns", "Column " + secondIndex,
- "Move column left");
- // columns 3 and 4 should have swapped to 4 and 3
- GridCellElement headerCell = getGridElement().getHeaderCell(0,
- firstIndex);
- assertEquals(secondHeaderText, headerCell.getText());
- headerCell = getGridElement().getHeaderCell(0, secondIndex);
- assertEquals(firstHeaderText, headerCell.getText());
-
- // the reorder event should have typed the order to this label
- WebElement columnReorderElement = findElement(By.id("columnreorder"));
- int eventIndex = Integer.parseInt(columnReorderElement
- .getAttribute("columns"));
- assertEquals(1, eventIndex);
-
- // trigger another event
- selectMenuPath("Component", "Columns", "Column " + secondIndex,
- "Move column left");
- columnReorderElement = findElement(By.id("columnreorder"));
- eventIndex = Integer.parseInt(columnReorderElement
- .getAttribute("columns"));
- assertEquals(2, eventIndex);
- }
-}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnReorderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnReorderTest.java
new file mode 100644
index 0000000000..9f43c39b1e
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnReorderTest.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2000-2014 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.grid.basicfeatures;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.testbench.elements.GridElement.GridCellElement;
+import com.vaadin.tests.annotations.TestCategory;
+
+/**
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+@TestCategory("grid")
+public class GridColumnReorderTest extends GridBasicClientFeaturesTest {
+
+ @Before
+ public void before() {
+ openTestURL();
+ }
+
+ @Test
+ public void columnReorderEventTriggered() {
+ final int firstIndex = 3;
+ final int secondIndex = 4;
+ final String firstHeaderText = getGridElement().getHeaderCell(0,
+ firstIndex).getText();
+ final String secondHeaderText = getGridElement().getHeaderCell(0,
+ secondIndex).getText();
+ selectMenuPath("Component", "Internals", "Listeners",
+ "Add ColumnReorder listener");
+ selectMenuPath("Component", "Columns", "Column " + secondIndex,
+ "Move column left");
+ // columns 3 and 4 should have swapped to 4 and 3
+ GridCellElement headerCell = getGridElement().getHeaderCell(0,
+ firstIndex);
+ assertEquals(secondHeaderText, headerCell.getText());
+ headerCell = getGridElement().getHeaderCell(0, secondIndex);
+ assertEquals(firstHeaderText, headerCell.getText());
+
+ // the reorder event should have typed the order to this label
+ WebElement columnReorderElement = findElement(By.id("columnreorder"));
+ int eventIndex = Integer.parseInt(columnReorderElement
+ .getAttribute("columns"));
+ assertEquals(1, eventIndex);
+
+ // trigger another event
+ selectMenuPath("Component", "Columns", "Column " + secondIndex,
+ "Move column left");
+ columnReorderElement = findElement(By.id("columnreorder"));
+ eventIndex = Integer.parseInt(columnReorderElement
+ .getAttribute("columns"));
+ assertEquals(2, eventIndex);
+ }
+
+ @Test
+ public void testColumnReorder_onReorder_columnReorderEventTriggered() {
+ final int firstIndex = 3;
+ final int secondIndex = 4;
+ final String firstHeaderText = getGridElement().getHeaderCell(0,
+ firstIndex).getText();
+ final String secondHeaderText = getGridElement().getHeaderCell(0,
+ secondIndex).getText();
+ selectMenuPath("Component", "Internals", "Listeners",
+ "Add ColumnReorder listener");
+ selectMenuPath("Component", "Columns", "Column " + secondIndex,
+ "Move column left");
+ // columns 3 and 4 should have swapped to 4 and 3
+ GridCellElement headerCell = getGridElement().getHeaderCell(0,
+ firstIndex);
+ assertEquals(secondHeaderText, headerCell.getText());
+ headerCell = getGridElement().getHeaderCell(0, secondIndex);
+ assertEquals(firstHeaderText, headerCell.getText());
+
+ // the reorder event should have typed the order to this label
+ WebElement columnReorderElement = findElement(By.id("columnreorder"));
+ int eventIndex = Integer.parseInt(columnReorderElement
+ .getAttribute("columns"));
+ assertEquals(1, eventIndex);
+
+ // trigger another event
+ selectMenuPath("Component", "Columns", "Column " + secondIndex,
+ "Move column left");
+ columnReorderElement = findElement(By.id("columnreorder"));
+ eventIndex = Integer.parseInt(columnReorderElement
+ .getAttribute("columns"));
+ assertEquals(2, eventIndex);
+ }
+
+ @Test
+ public void testColumnReorder_draggingSortedColumn_sortIndicatorShownOnDraggedElement() {
+ // given
+ toggleColumnReorder();
+ toggleSortableColumn(0);
+ sortColumn(0);
+
+ // when
+ startDragButDontDropOnDefaultColumnHeader(0);
+
+ // then
+ WebElement draggedElement = getDraggedHeaderElement();
+ assertTrue(draggedElement.getAttribute("class").contains("sort"));
+ }
+
+ @Test
+ public void testColumnReorder_draggingSortedColumn_sortStays() {
+ // given
+ toggleColumnReorder();
+ toggleSortableColumn(0);
+ sortColumn(0);
+
+ // when
+ dragDefaultColumnHeader(0, 2, 10);
+
+ // then
+ assertColumnIsSorted(1);
+ }
+
+ @Test
+ public void testColumnReorder_draggingFocusedHeader_focusShownOnDraggedElement() {
+ // given
+ toggleColumnReorder();
+ focusDefaultHeader(0);
+
+ // when
+ startDragButDontDropOnDefaultColumnHeader(0);
+
+ // then
+ WebElement draggedElement = getDraggedHeaderElement();
+ assertTrue(draggedElement.getAttribute("class").contains("focused"));
+ }
+
+ @Test
+ public void testColumnReorder_draggingFocusedHeader_focusIsKeptOnHeader() {
+ // given
+ toggleColumnReorder();
+ focusDefaultHeader(0);
+
+ // when
+ dragDefaultColumnHeader(0, 3, 10);
+
+ // then
+ WebElement defaultColumnHeader = getDefaultColumnHeader(2);
+ String attribute = defaultColumnHeader.getAttribute("class");
+ assertTrue(attribute.contains("focused"));
+ }
+
+ @Test
+ public void testColumnReorder_draggingFocusedCellColumn_focusIsKeptOnCell() {
+ // given
+ toggleColumnReorder();
+ focusCell(2, 2);
+
+ // when
+ dragDefaultColumnHeader(2, 0, 10);
+
+ // then
+ assertFocusedCell(2, 0);
+ }
+
+ @Test
+ public void testColumnReorder_dragColumnFromRightToLeftOfFocusedCellColumn_focusIsKept() {
+ // given
+ toggleColumnReorder();
+ focusCell(1, 3);
+
+ // when
+ dragDefaultColumnHeader(4, 1, 10);
+
+ // then
+ assertFocusedCell(1, 4);
+ }
+
+ @Test
+ public void testColumnReorder_dragColumnFromLeftToRightOfFocusedCellColumn_focusIsKept() {
+ // given
+ toggleColumnReorder();
+ focusCell(4, 2);
+
+ // when
+ dragDefaultColumnHeader(0, 4, 10);
+
+ // then
+ assertFocusedCell(4, 1);
+ }
+
+ private void toggleColumnReorder() {
+ selectMenuPath("Component", "State", "Column Reordering");
+ }
+
+ private void toggleSortableColumn(int index) {
+ selectMenuPath("Component", "Columns", "Column " + index, "Sortable");
+ }
+
+ private void startDragButDontDropOnDefaultColumnHeader(int index) {
+ new Actions(getDriver())
+ .clickAndHold(getGridHeaderRowCells().get(index))
+ .moveByOffset(100, 0).perform();
+ }
+
+ private void sortColumn(int index) {
+ getGridHeaderRowCells().get(index).click();
+ }
+
+ private void focusDefaultHeader(int index) {
+ getGridHeaderRowCells().get(index).click();
+ }
+
+ private WebElement getDraggedHeaderElement() {
+ return findElement(By.className("dragged-column-header"));
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnReorderTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnReorderTest.java
index 2f00071351..2cc8610209 100644
--- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnReorderTest.java
+++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnReorderTest.java
@@ -15,18 +15,12 @@
*/
package com.vaadin.tests.components.grid.basicfeatures.server;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import java.util.List;
-
import org.junit.Before;
import org.junit.Test;
-import org.openqa.selenium.WebElement;
-import org.openqa.selenium.interactions.Actions;
-import com.vaadin.testbench.TestBenchElement;
import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest;
/**
@@ -212,30 +206,4 @@ public class GridColumnReorderTest extends GridBasicFeaturesTest {
assertFalse(logRow.contains("Columns reordered"));
}
- private void assertColumnHeaderOrder(int... indices) {
- List<TestBenchElement> headers = getGridHeaderRowCells();
- for (int i = 0; i < indices.length; i++) {
- assertColumnHeader("Column " + indices[i], headers.get(i));
- }
- }
-
- private void assertColumnHeader(String expectedHeaderCaption,
- TestBenchElement testBenchElement) {
- assertEquals(expectedHeaderCaption.toLowerCase(), testBenchElement
- .getText().toLowerCase());
- }
-
- private WebElement getDefaultColumnHeader(int index) {
- List<TestBenchElement> headerRowCells = getGridHeaderRowCells();
- return headerRowCells.get(index);
- }
-
- private void dragDefaultColumnHeader(int draggedColumnHeaderIndex,
- int onTopOfColumnHeaderIndex, int xOffsetFromColumnTopLeftCorner) {
- new Actions(getDriver())
- .clickAndHold(getDefaultColumnHeader(draggedColumnHeaderIndex))
- .moveToElement(
- getDefaultColumnHeader(onTopOfColumnHeaderIndex),
- xOffsetFromColumnTopLeftCorner, 0).release().perform();
- }
}