// Rows
- .#{$primaryStyleName}-row > td {
+ .#{$primaryStyleName}-row > td,
+ .#{$primaryStyleName}-editor-cells > div {
border-left: $v-grid-cell-vertical-border;
border-bottom: $v-grid-cell-horizontal-border;
// Editor
.#{$primaryStyleName}-editor {
- // TODO should be fixed in offset calculations
- margin-top: -1px;
position: absolute;
- overflow-y: visible;
- background: $v-grid-editor-background-color;
- @include box-shadow(0 0 10px 1px rgba(0,0,0,.3));
+ z-index: 20;
+ overflow: hidden;
+ left: 0;
+ right: 0;
+ border: $v-grid-border;
+ margin-top: nth($v-grid-border, 1) * -1;
+ @include box-shadow(0 0 9px rgba(0,0,0,.2));
+ }
+
+ .#{$primaryStyleName}-editor-cells {
+ position: relative;
+ white-space: nowrap;
> div {
- position: absolute;
+ display: inline-block;
@include box-sizing(border-box);
- border-left: $v-grid-cell-vertical-border;
+ vertical-align: middle;
+ background: $v-grid-editor-background-color;
&:first-child {
border-left: none;
}
+ > * {
+ vertical-align: middle;
+ display: inline-block;
+ }
+
.v-textfield,
.v-datefield,
.v-filterselect {
max-width: 100%;
min-height: 100%;
max-height: 100%;
- border: none;
- border-radius: 0;
}
- .v-textfield-focus,
- .v-filterselect-focus input {
- position: relative;
- z-index: 1;
+ .v-select,
+ .v-select-select {
+ min-width: 100%;
+ max-width: 100%;
}
}
}
- .#{$primaryStyleName}-editor-save,
- .#{$primaryStyleName}-editor-cancel {
- position: absolute;
- // TODO remove the inline size from the widgets
- width: auto !important;
- height: auto !important;
+ .#{$primaryStyleName}-editor-footer {
+ display: table;
+ height: $v-grid-row-height;
+ border-top: $v-grid-cell-horizontal-border;
+ margin-top: nth($v-grid-cell-horizontal-border, 1) * -1;
+ background: $v-grid-row-background-color;
+ padding: 0 5px;
+
+ + .#{$primaryStyleName}-editor-cells > div {
+ border-bottom: none;
+ border-top: $v-grid-cell-horizontal-border;
+ }
+
+ &:first-child {
+ border-top: none;
+ margin-top: 0;
+ border-bottom: $v-grid-cell-horizontal-border;
+ margin-bottom: nth($v-grid-cell-horizontal-border, 1) * -1;
+ }
+ }
+
+ .#{$primaryStyleName}-editor-message,
+ .#{$primaryStyleName}-editor-buttons {
+ display: table-cell;
+ white-space: nowrap;
+ vertical-align: middle;
+ }
+
+ .#{$primaryStyleName}-editor-message {
+ width: 100%;
+ position: relative;
+
+ > div {
+ position: absolute;
+ width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ line-height: $v-grid-row-height;
+ top: 0;
+ }
+ }
+
+ .#{$primaryStyleName}-editor-save {
+ margin-right: 4px;
}
// Renderers
$v-grid-row-background-color: valo-table-background-color() !default;
$v-grid-row-stripe-background-color: scale-color($v-grid-row-background-color, $lightness: if(color-luminance($v-grid-row-background-color) < 10, 4%, -4%)) !default;
-$v-grid-border: valo-border($color: $v-grid-row-background-color, $strength: 0.8) !default;
+$v-grid-border: flatten-list(valo-border($color: $v-grid-row-background-color, $strength: 0.8)) !default;
$v-grid-cell-focused-border: max(2px, first-number($v-border)) solid $v-selection-color !default;
$v-grid-row-height: $v-table-row-height !default;
$v-grid-cell-padding-horizontal: $v-table-cell-padding-horizontal !default;
+$v-grid-animations-enabled: $v-animations-enabled !default;
+
@import "../../base/grid/grid";
}
}
+ .#{$primary-stylename}-editor {
+ @include valo-focus-style;
+ border-color: $v-focus-color;
+ }
+
+ .#{$primary-stylename}-editor-footer {
+ font-size: $v-font-size--small;
+ padding: 0 round($v-layout-spacing-horizontal / 2);
+ background: $v-app-background-color;
+ @if $v-grid-animations-enabled {
+ @include animation(valo-grid-editor-footer-animate-in 200ms 120ms backwards);
+ }
+ }
+
+ @if $v-grid-animations-enabled {
+ .#{$primary-stylename}-editor-footer:first-child {
+ @include animation(valo-grid-editor-footer-animate-in-alt 200ms 120ms backwards);
+ }
+ }
+
+ .#{$primary-stylename}-editor-cells {
+ z-index: 1;
+ }
+
+ .#{$primary-stylename}-editor-cells > div {
+ // Vertical centering for widgets
+ &:before {
+ content: "";
+ display: inline-block;
+ height: 100%;
+ vertical-align: middle;
+ }
+
+ .v-textfield,
+ .v-textfield-focus,
+ .v-datefield,
+ .v-datefield .v-textfield-focus,
+ .v-filterselect-input,
+ .v-filterselect-input:focus {
+ border: none;
+ border-radius: 0;
+ background: transparent;
+
+ @if $v-textfield-bevel {
+ @include box-shadow(valo-bevel-and-shadow($bevel: $v-textfield-bevel));
+ } @else {
+ @include box-shadow(none);
+ }
+ }
+
+ .v-textfield-focus,
+ .v-datefield .v-textfield-focus,
+ .v-filterselect-input:focus {
+ position: relative;
+ }
+
+ .v-select {
+ padding-left: round($v-grid-cell-padding-horizontal / 2);
+ padding-right: round($v-grid-cell-padding-horizontal / 2);
+ }
+
+ .v-checkbox {
+ margin: 0 round($v-grid-cell-padding-horizontal / 2);
+
+ label {
+ white-space: nowrap;
+ }
+ }
+ }
+
+ .#{$primary-stylename}-editor-message > div:before {
+ display: inline-block;
+ @include valo-error-indicator-style($is-pseudo-element: true);
+ }
+
.#{$primary-stylename}-editor-save,
.#{$primary-stylename}-editor-cancel {
- @include valo-button-static-style;
- @include valo-button-style($unit-size: $v-unit-size--small, $font-size: $v-font-size--small);
+ @include valo-link-style;
+ font-weight: $v-font-weight + 100;
+ text-decoration: none;
+ border: none;
+ background: transparent;
+ padding: round($v-layout-spacing-vertical / 2) round($v-layout-spacing-horizontal / 2);
+ margin: 0;
+ outline: none;
}
// Customize scrollbars
}
}
+
+
+@include keyframes(valo-grid-editor-footer-animate-in) {
+ 0% {
+ margin-top: -$v-grid-row-height;
+ }
+}
+
+@include keyframes(valo-grid-editor-footer-animate-in-alt) {
+ 0% {
+ margin-bottom: -$v-grid-row-height - first-number($v-grid-cell-horizontal-border);
+ }
+ 100% {
+ margin-bottom: first-number($v-grid-cell-horizontal-border) * -1;
+ }
+}
*/
protected static class Editor<T> {
- private static final double BUTTON_HEIGHT = 25;
- private static final double BUTTON_WIDTH = 50;
- private static final double BUTTON_MARGIN = 5;
- private static final double SAVE_BUTTON_LEFT_MARGIN_PX = 0;
- private static final double CANCEL_BUTTON_LEFT_MARGIN_PX = SAVE_BUTTON_LEFT_MARGIN_PX
- + BUTTON_WIDTH + BUTTON_MARGIN;
-
public static final int KEYCODE_SHOW = KeyCodes.KEY_ENTER;
public static final int KEYCODE_HIDE = KeyCodes.KEY_ESCAPE;
private EditorHandler<T> handler;
private DivElement editorOverlay = DivElement.as(DOM.createDiv());
+ private DivElement cellWrapper = DivElement.as(DOM.createDiv());
+ private DivElement messageAndButtonsWrapper = DivElement.as(DOM
+ .createDiv());
+
+ private DivElement messageWrapper = DivElement.as(DOM.createDiv());
+ private DivElement buttonsWrapper = DivElement.as(DOM.createDiv());
+
+ // Element which contains the error message for the editor
+ // Should only be added to the DOM when there's a message to show
+ private DivElement message = DivElement.as(DOM.createDiv());
private Map<Column<?, T>, Widget> columnToWidget = new HashMap<Column<?, T>, Widget>();
public Editor() {
saveButton = new Button();
saveButton.setText(GridConstants.DEFAULT_SAVE_CAPTION);
- saveButton.setStylePrimaryName("v-nativebutton");
saveButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
cancelButton = new Button();
cancelButton.setText(GridConstants.DEFAULT_CANCEL_CAPTION);
- cancelButton.setStylePrimaryName("v-nativebutton");
cancelButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
*/
protected void showOverlay(TableRowElement tr) {
- DivElement tableWrapper = DivElement.as(tr.getParentElement()
- .getParentElement().getParentElement());
-
- AbstractRowContainer body = (AbstractRowContainer) grid
- .getEscalator().getBody();
-
- double rowTop = body.getRowTop(tr);
- int bodyTop = body.getElement().getAbsoluteTop();
- int wrapperTop = tableWrapper.getAbsoluteTop();
-
- double width = WidgetUtil
- .getRequiredWidthBoundingClientRectDouble(tr);
- double height = WidgetUtil
- .getRequiredHeightBoundingClientRectDouble(tr);
- double overlayTop = rowTop + bodyTop - wrapperTop;
- setBounds(editorOverlay, tr.getOffsetLeft(), overlayTop, width,
- height);
+ DivElement gridElement = DivElement.as(grid.getElement());
scrollHandler = grid.addScrollHandler(new ScrollHandler() {
@Override
}
});
- tableWrapper.appendChild(editorOverlay);
+ gridElement.appendChild(editorOverlay);
+ editorOverlay.appendChild(cellWrapper);
+ editorOverlay.appendChild(messageAndButtonsWrapper);
for (int i = 0; i < tr.getCells().getLength(); i++) {
Element cell = createCell(tr.getCells().getItem(i));
- editorOverlay.appendChild(cell);
+ cellWrapper.appendChild(cell);
Column<?, T> column = grid.getColumn(i);
if (column.isEditable()) {
}
}
- attachWidget(saveButton, editorOverlay);
- attachWidget(cancelButton, editorOverlay);
+ // Only add these elements once
+ if (!messageAndButtonsWrapper.isOrHasChild(messageWrapper)) {
+ messageAndButtonsWrapper.appendChild(messageWrapper);
+ messageAndButtonsWrapper.appendChild(buttonsWrapper);
+ }
- /*
- * We can't use BUTTON_HEIGHT here, becuase it's ignored by at least
- * Chrome and Firefox. So we measure it.
- */
- double buttonTop = getButtonTop(tr, saveButton.getOffsetHeight());
- setBounds(saveButton.getElement(), SAVE_BUTTON_LEFT_MARGIN_PX,
- buttonTop, BUTTON_WIDTH, BUTTON_HEIGHT);
- setBounds(cancelButton.getElement(), CANCEL_BUTTON_LEFT_MARGIN_PX,
- buttonTop, BUTTON_WIDTH, BUTTON_HEIGHT);
+ attachWidget(saveButton, buttonsWrapper);
+ attachWidget(cancelButton, buttonsWrapper);
updateHorizontalScrollPosition();
- }
- private double getButtonTop(TableRowElement tr, int buttonHeight) {
- boolean buttonsShouldBeRenderedBelow = buttonsShouldBeRenderedBelow(
- tr, buttonHeight);
- final double buttonTop;
- if (buttonsShouldBeRenderedBelow) {
- buttonTop = tr.getOffsetHeight() + BUTTON_MARGIN;
+ AbstractRowContainer body = (AbstractRowContainer) grid
+ .getEscalator().getBody();
+ double rowTop = body.getRowTop(tr);
+
+ int bodyTop = body.getElement().getAbsoluteTop();
+ int gridTop = gridElement.getAbsoluteTop();
+ double overlayTop = rowTop + bodyTop - gridTop;
+
+ if (buttonsShouldBeRenderedBelow(tr)) {
+ // Default case, editor buttons are below the edited row
+ editorOverlay.getStyle().setTop(overlayTop, Unit.PX);
+ editorOverlay.getStyle().clearBottom();
} else {
- buttonTop = -(buttonHeight + BUTTON_MARGIN);
+ // Move message and buttons wrapper on top of cell wrapper if
+ // there is not enough space visible space under and fix the
+ // overlay from the bottom
+ editorOverlay.appendChild(cellWrapper);
+ int gridHeight = grid.getElement().getOffsetHeight();
+ editorOverlay.getStyle()
+ .setBottom(
+ gridHeight - overlayTop - tr.getOffsetHeight(),
+ Unit.PX);
+ editorOverlay.getStyle().clearTop();
+ }
+
+ // Do not render over the vertical scrollbar
+ int nativeScrollbarSize = WidgetUtil.getNativeScrollbarSize();
+ if (nativeScrollbarSize > 0) {
+ editorOverlay.getStyle().setRight(nativeScrollbarSize, Unit.PX);
}
- return buttonTop;
}
- private boolean buttonsShouldBeRenderedBelow(TableRowElement tr,
- int buttonHeight) {
+ private boolean buttonsShouldBeRenderedBelow(TableRowElement tr) {
TableSectionElement tfoot = grid.escalator.getFooter().getElement();
double tfootPageTop = WidgetUtil.getBoundingClientRect(tfoot)
.getTop();
double trPageBottom = WidgetUtil.getBoundingClientRect(tr)
.getBottom();
- double bottomOfButtons = trPageBottom + buttonHeight
- + BUTTON_MARGIN;
+ int messageAndButtonsHeight = messageAndButtonsWrapper
+ .getOffsetHeight();
+ double bottomOfButtons = trPageBottom + messageAndButtonsHeight;
return bottomOfButtons < tfootPageTop;
}
detachWidget(cancelButton);
editorOverlay.removeAllChildren();
+ cellWrapper.removeAllChildren();
editorOverlay.removeFromParent();
scrollHandler.removeHandler();
protected void setStylePrimaryName(String primaryName) {
if (styleName != null) {
editorOverlay.removeClassName(styleName);
+
+ cellWrapper.removeClassName(styleName + "-cells");
+ messageAndButtonsWrapper.removeClassName(styleName + "-footer");
+
+ messageWrapper.removeClassName(styleName + "-message");
+ buttonsWrapper.removeClassName(styleName + "-buttons");
+
saveButton.removeStyleName(styleName + "-save");
cancelButton.removeStyleName(styleName + "-cancel");
}
styleName = primaryName + "-editor";
- editorOverlay.addClassName(styleName);
+ editorOverlay.setClassName(styleName);
- saveButton.addStyleName(styleName + "-save");
- cancelButton.addStyleName(styleName + "-cancel");
+ cellWrapper.setClassName(styleName + "-cells");
+ messageAndButtonsWrapper.setClassName(styleName + "-footer");
+
+ messageWrapper.setClassName(styleName + "-message");
+ buttonsWrapper.setClassName(styleName + "-buttons");
+
+ saveButton.setStyleName(styleName + "-save");
+ cancelButton.setStyleName(styleName + "-cancel");
}
/**
private void updateHorizontalScrollPosition() {
double scrollLeft = grid.getScrollLeft();
-
- editorOverlay.getStyle().setLeft(-scrollLeft, Unit.PX);
-
- double saveLeftPx = scrollLeft + SAVE_BUTTON_LEFT_MARGIN_PX;
- double cancelLeftPx = scrollLeft + CANCEL_BUTTON_LEFT_MARGIN_PX;
- saveButton.getElement().getStyle().setLeft(saveLeftPx, Unit.PX);
- cancelButton.getElement().getStyle().setLeft(cancelLeftPx, Unit.PX);
+ cellWrapper.getStyle().setLeft(-scrollLeft, Unit.PX);
}
protected void setGridEnabled(boolean enabled) {