/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * 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 org.uberfire.ext.layout.editor.client.components.columns; import javax.enterprise.context.Dependent; import javax.enterprise.event.Observes; import javax.inject.Inject; import com.google.gwt.core.client.Scheduler; import org.jboss.errai.common.client.dom.Button; import org.jboss.errai.common.client.dom.Div; import org.jboss.errai.common.client.dom.Document; import org.jboss.errai.common.client.dom.HTMLElement; import org.jboss.errai.common.client.dom.MouseEvent; import org.jboss.errai.common.client.ui.ElementWrapperWidget; import org.jboss.errai.ui.client.local.api.IsElement; import org.jboss.errai.ui.shared.api.annotations.DataField; import org.jboss.errai.ui.shared.api.annotations.Templated; import org.uberfire.client.mvp.UberElement; import org.uberfire.client.workbench.docks.UberfireDocksInteractionEvent; import org.uberfire.ext.layout.editor.api.editor.LayoutComponent; import org.uberfire.ext.layout.editor.client.infra.ColumnDrop; import org.uberfire.ext.layout.editor.client.infra.ContainerResizeEvent; import org.uberfire.ext.layout.editor.client.infra.DragComponentEndEvent; import org.uberfire.ext.layout.editor.client.infra.DragHelperComponentColumn; import org.uberfire.ext.layout.editor.client.widgets.KebabWidget; import org.uberfire.mvp.Command; import static org.jboss.errai.common.client.dom.DOMUtil.addCSSClass; import static org.jboss.errai.common.client.dom.DOMUtil.hasCSSClass; import static org.jboss.errai.common.client.dom.DOMUtil.removeAllChildren; import static org.jboss.errai.common.client.dom.DOMUtil.removeCSSClass; import static org.uberfire.ext.layout.editor.client.infra.HTML5DnDHelper.extractDndData; @Dependent @Templated public class ComponentColumnView implements UberElement<ComponentColumn>, ComponentColumn.View, IsElement { public static final String COL_CSS_CLASS = "col-md-"; private final int originalLeftRightWidth = 15; String cssSize = ""; private ComponentColumn presenter; @Inject @DataField private Div col; @Inject @DataField private Div colUp; @Inject @DataField private Div row; @Inject @DataField private Div colDown; @Inject @DataField private Div left; @Inject @DataField("resize-left") private Button resizeLeft; @Inject @DataField private Div right; @Inject @DataField("resize-right") private Button resizeRight; @Inject @DataField private Div content; @Inject private KebabWidget kebabWidget; @Inject private Document document; private ColumnDrop.Orientation contentDropOrientation; @Inject private DragHelperComponentColumn helper; @Override public void init(ComponentColumn presenter) { this.presenter = presenter; } @Override public void setupWidget() { setupEvents(); setupKebabWidget(); setupResize(); setupOnResize(); } private void setupOnResize() { document.getBody().setOnresize(event -> calculateSize()); } @Override public void setupResize() { resizeLeft.getStyle().setProperty("display", "none"); resizeRight.getStyle().setProperty("display", "none"); } public void dockSelectEvent(@Observes UberfireDocksInteractionEvent event) { calculateSize(); } private void setupKebabWidget() { kebabWidget.init(() -> presenter.remove(), () -> presenter.edit()); } private void setupEvents() { setupLeftEvents(); setupRightEvents(); setupColUpEvents(); setupColDownEvents(); setupContentEvents(); setupColEvents(); setupRowEvents(); setupResizeEvents(); } private void setupRowEvents() { row.setOnmouseout(event -> { removeCSSClass(colUp, "componentDropInColumnPreview"); removeCSSClass(colDown, "componentDropInColumnPreview"); }); } private void setupResizeEvents() { resizeLeft.setOnclick(event -> presenter.resizeLeft()); resizeRight.setOnclick(event -> presenter.resizeRight()); } private void setupColEvents() { col.setOnmouseup(e -> { e.preventDefault(); if (hasCSSClass(col, "rowDndPreview")) { removeCSSClass(col, "rowDndPreview"); } }); col.setOnmouseover(e -> { e.preventDefault(); }); col.setOnmouseout(event -> { removeCSSClass(colUp, "componentDropInColumnPreview"); removeCSSClass(colDown, "componentDropInColumnPreview"); }); } private void setupColUpEvents() { colUp.setOndragleave(event -> { removeCSSClass(colUp, "componentDropInColumnPreview"); }); colUp.setOndragexit(event -> { removeCSSClass(colUp, "componentDropInColumnPreview"); }); colUp.setOndragover(event -> { event.preventDefault(); if (presenter.shouldPreviewDrop()) { contentDropOrientation = ColumnDrop.Orientation.UP; addCSSClass(colUp, "componentDropInColumnPreview"); } }); colUp.setOndrop(e -> { if (contentDropOrientation != null) { presenter.onDrop(contentDropOrientation, extractDndData(e)); } removeCSSClass(colUp, "componentDropInColumnPreview"); removeCSSClass(colDown, "componentDropInColumnPreview"); }); colUp.setOnmouseout(event -> { removeCSSClass(colUp, "componentDropInColumnPreview"); }); } private void setupColDownEvents() { colDown.setOndrop(e -> { if (contentDropOrientation != null) { presenter.onDrop(contentDropOrientation, extractDndData(e)); } removeCSSClass(colUp, "componentDropInColumnPreview"); removeCSSClass(colDown, "componentDropInColumnPreview"); }); } private void setupRightEvents() { right.setOndragenter(e -> { e.preventDefault(); if (presenter.shouldPreviewDrop() && presenter.enableSideDnD()) { addCSSClass(right, "columnDropPreview"); addCSSClass(right, "dropPreview"); addCSSClass(content, "centerPreview"); removeCSSClass(colUp, "componentDropInColumnPreview"); } }); right.setOndragleave(e -> { e.preventDefault(); removeCSSClass(right, "columnDropPreview"); removeCSSClass(right, "dropPreview"); removeCSSClass(content, "centerPreview"); }); right.setOndragover(event -> event.preventDefault()); right.setOndrop(e -> { e.preventDefault(); if (presenter.enableSideDnD() && presenter.shouldPreviewDrop()) { removeCSSClass(right, "columnDropPreview"); removeCSSClass(right, "dropPreview"); removeCSSClass(content, "centerPreview"); presenter.onDrop(ColumnDrop.Orientation.RIGHT, extractDndData(e)); } }); right.setOnmouseover(e -> { e.preventDefault(); if (presenter.canResizeRight()) { resizeRight.getStyle().setProperty("display", "block"); } }); right.setOnmouseout(e -> { e.preventDefault(); if (presenter.canResizeRight()) { resizeRight.getStyle().setProperty("display", "none"); } }); } private void setupContentEvents() { content.setOndragover(e -> { e.preventDefault(); if (presenter.shouldPreviewDrop()) { if (dragOverUp(content, (MouseEvent) e)) { addCSSClass(colUp, "componentDropInColumnPreview"); removeCSSClass(colDown, "componentDropInColumnPreview"); contentDropOrientation = ColumnDrop.Orientation.UP; } else { addCSSClass(colDown, "componentDropInColumnPreview"); removeCSSClass(colUp, "componentDropInColumnPreview"); contentDropOrientation = ColumnDrop.Orientation.DOWN; } } }); content.setOndragleave(e -> { e.preventDefault(); removeCSSClass(colDown, "componentDropInColumnPreview"); contentDropOrientation = null; }); content.setOndrop(e -> { e.preventDefault(); if (contentDropOrientation != null) { presenter.onDrop(contentDropOrientation, extractDndData(e)); } removeCSSClass(colUp, "componentDropInColumnPreview"); removeCSSClass(colDown, "componentDropInColumnPreview"); }); content.setOnmouseout(e -> { removeCSSClass(content, "componentMovePreview"); }); content.setOnmouseover(e -> { e.preventDefault(); addCSSClass(content, "componentMovePreview"); }); content.setOndragend(e -> { e.stopPropagation(); removeCSSClass(row, "rowDndPreview"); presenter.dragEndComponent(); }); content.setOndragstart(e -> { e.stopPropagation(); e.getDataTransfer().setData("text/plain", "this-is-a-requirement-to-firefox-html5dnd"); addCSSClass(row, "rowDndPreview"); presenter.dragStartComponent(); }); } private void setupLeftEvents() { left.setOndragleave(e -> { e.preventDefault(); removeCSSClass(left, "columnDropPreview"); removeCSSClass(left, "dropPreview"); removeCSSClass(content, "centerPreview"); }); left.setOndrop(e -> { e.preventDefault(); if (presenter.enableSideDnD() && presenter.shouldPreviewDrop()) { removeCSSClass(left, "columnDropPreview"); removeCSSClass(left, "dropPreview"); removeCSSClass(content, "centerPreview"); presenter.onDrop(ColumnDrop.Orientation.LEFT, extractDndData(e)); } }); left.setOndragover(event -> { if (presenter.enableSideDnD() && presenter.shouldPreviewDrop()) { event.preventDefault(); } }); left.setOndragexit(event -> { event.preventDefault(); removeCSSClass(left, "columnDropPreview"); removeCSSClass(left, "dropPreview"); removeCSSClass(content, "centerPreview"); }); left.setOndragenter(e -> { e.preventDefault(); if (presenter.enableSideDnD() && presenter.shouldPreviewDrop()) { addCSSClass(left, "columnDropPreview"); addCSSClass(left, "dropPreview"); addCSSClass(content, "centerPreview"); removeCSSClass(colUp, "componentDropInColumnPreview"); } }); left.setOnmouseover(e -> { e.preventDefault(); if (presenter.canResizeLeft()) { resizeLeft.getStyle().setProperty("display", "block"); } }); left.setOnmouseout(e -> { e.preventDefault(); if (presenter.canResizeLeft()) { resizeLeft.getStyle().setProperty("display", "none"); } }); } public void resizeEventObserver(@Observes ContainerResizeEvent event) { calculateSize(); } @Override public void calculateSize() { Scheduler.get().scheduleDeferred(() -> { controlPadding(); calculateLeftRightWidth(); calculateContentWidth(); addCSSClass(col, "container"); }); } private void controlPadding() { if (!presenter.isInnerColumn()) { addCSSClass(col, "no-padding"); } else { if (hasCSSClass(col, "no-padding")) { removeCSSClass(col, "no-padding"); } } } private void calculateLeftRightWidth() { if (originalLeftRightWidth >= 0) { left.getStyle().setProperty("width", originalLeftRightWidth + "px"); right.getStyle().setProperty("width", originalLeftRightWidth + "px"); } } private void calculateContentWidth() { int smallSpace = 2; final int colWidth = col.getBoundingClientRect().getWidth().intValue(); final int contentWidth = colWidth - (originalLeftRightWidth * 2) - smallSpace; if (contentWidth >= 0) { content.getStyle().setProperty("width", contentWidth + "px"); colDown.getStyle().setProperty("width", "100%"); colUp.getStyle().setProperty("width", "100%"); } } @Override public void setSize(String size) { if (!col.getClassName().isEmpty()) { removeCSSClass(col, cssSize); } cssSize = COL_CSS_CLASS + size; addCSSClass(col, cssSize); } @Override public void clearContent() { removeAllChildren(content); } @Override public void setContent() { Scheduler.get().scheduleDeferred(() -> { removeAllChildren(content); HTMLElement previewWidget = getPreviewElement(); content.appendChild(kebabWidget.getElement()); content.appendChild(previewWidget); }); } @Override public void showConfigComponentModal(Command configurationFinish, Command configurationCanceled) { helper.showConfigModal(configurationFinish, configurationCanceled); } @Override public boolean hasModalConfiguration() { return helper.hasModalConfiguration(); } @Override public void setup(LayoutComponent layoutComponent) { helper.setLayoutComponent(layoutComponent); } private HTMLElement getPreviewElement() { HTMLElement previewElement = helper.getPreviewElement(ElementWrapperWidget.getWidget(content)); previewElement.getStyle().setProperty("cursor", "default"); previewElement.setClassName("le-widget"); return previewElement; } private boolean hasColPreview(HTMLElement element) { return hasCSSClass(element, "componentDropInColumnPreview"); } private boolean dragOverUp(Div div, MouseEvent e) { final int top = div.getBoundingClientRect().getTop().intValue(); final int bottom = div.getBoundingClientRect().getBottom().intValue(); int dragOverY = e.getClientY(); return (dragOverY - top) < (bottom - dragOverY); } public void cleanUp(@Observes DragComponentEndEvent dragComponentEndEvent) { removeCSSClass(colUp, "componentDropInColumnPreview"); } }