Browse Source

Support starting downloads and opening URLs from a menu item (#10478)

tags/8.4.0.alpha2
Artur 6 years ago
parent
commit
761bef8fb7
19 changed files with 558 additions and 43 deletions
  1. 1
    0
      all/src/main/templates/release-notes.html
  2. 73
    0
      client/src/main/java/com/vaadin/client/extensions/AbstractEventTriggerExtensionConnector.java
  3. 3
    15
      client/src/main/java/com/vaadin/client/extensions/BrowserWindowOpenerConnector.java
  4. 55
    0
      client/src/main/java/com/vaadin/client/extensions/EventTrigger.java
  5. 8
    14
      client/src/main/java/com/vaadin/client/extensions/FileDownloaderConnector.java
  6. 67
    8
      client/src/main/java/com/vaadin/client/ui/VMenuBar.java
  7. 1
    0
      client/src/main/java/com/vaadin/client/ui/menubar/MenuBarConnector.java
  8. 1
    1
      documentation/articles/LettingTheUserDownloadAFile.asciidoc
  9. 19
    0
      server/src/main/java/com/vaadin/server/BrowserWindowOpener.java
  10. 65
    0
      server/src/main/java/com/vaadin/server/EventTrigger.java
  11. 19
    0
      server/src/main/java/com/vaadin/server/FileDownloader.java
  12. 56
    1
      server/src/main/java/com/vaadin/ui/MenuBar.java
  13. 33
    0
      shared/src/main/java/com/vaadin/shared/extension/PartInformationState.java
  14. 2
    2
      shared/src/main/java/com/vaadin/shared/extension/filedownloader/FileDownloaderState.java
  15. 2
    2
      shared/src/main/java/com/vaadin/shared/ui/BrowserWindowOpenerState.java
  16. 73
    0
      uitest/src/main/java/com/vaadin/tests/components/MenuBarDownloadBrowserOpenerUI.java
  17. 23
    0
      uitest/src/main/java/com/vaadin/tests/extensions/EventTriggerExtension.java
  18. 13
    0
      uitest/src/main/java/com/vaadin/tests/widgetset/client/extension/EventTriggerExtensionConnector.java
  19. 44
    0
      uitest/src/test/java/com/vaadin/tests/components/MenuBarDownloadBrowserOpenerUITest.java

+ 1
- 0
all/src/main/templates/release-notes.html View File

@@ -103,6 +103,7 @@

<h2 id="incompatible">Incompatible or Behavior-altering Changes in @version-minor@</h2>

<li><tt>BrowserWindowOpenerConnector</tt> and <tt>FileDownloaderConnector</tt> now are subclasses of <tt>AbstractEventTriggerExtensionConnector</tt>
<li>Date range limits in <tt>AbstractDateFieldState</tt> are now <tt>String</tt>s instead of <tt>Date</tt>s, some client-side method signatures were changed</li>
<li><tt>BrowserResizeListener</tt> is only called once resizing ends.</li>
<li><tt>ItemClickEvent</tt> for <tt>Grid</tt> now takes and additional row index parameter.</li>

+ 73
- 0
client/src/main/java/com/vaadin/client/extensions/AbstractEventTriggerExtensionConnector.java View File

@@ -0,0 +1,73 @@
/*
* Copyright 2000-2018 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.client.extensions;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.HandlerRegistration;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ServerConnector;
import com.vaadin.shared.extension.PartInformationState;

/**
* An abstract extension connector with trigger support. Implementor's
* {@link #trigger} method call may be initiated by another {@code Component}
* without server round-trip. The class is used to overcome browser security
* limitations. For instance, window may not be open with the round-trip.
*
* @author Vaadin Ltd.
* @since
*/
public abstract class AbstractEventTriggerExtensionConnector
extends AbstractExtensionConnector {

private HandlerRegistration eventHandlerRegistration;

/**
* Called whenever a click occurs on the widget (if widget does not
* implement {@link EventTrigger}) or when the {@link EventTrigger} fires.
*
*/
protected abstract void trigger();

@Override
public PartInformationState getState() {
return (PartInformationState) super.getState();
}

@Override
protected void extend(ServerConnector target) {
Widget targetWidget = ((ComponentConnector) target).getWidget();
if (targetWidget instanceof EventTrigger) {
String partInformation = getState().partInformation;
eventHandlerRegistration = ((EventTrigger) targetWidget)
.addTrigger(this::trigger, partInformation);
} else {
eventHandlerRegistration = targetWidget
.addDomHandler(e -> trigger(), ClickEvent.getType());
}
}

@Override
public void onUnregister() {
super.onUnregister();

if (eventHandlerRegistration != null) {
eventHandlerRegistration.removeHandler();
eventHandlerRegistration = null;
}
}
}

+ 3
- 15
client/src/main/java/com/vaadin/client/extensions/BrowserWindowOpenerConnector.java View File

@@ -18,13 +18,8 @@ package com.vaadin.client.extensions;

import java.util.Map.Entry;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ServerConnector;
import com.vaadin.server.BrowserWindowOpener;
import com.vaadin.shared.ui.BrowserWindowOpenerState;
import com.vaadin.shared.ui.Connect;
@@ -37,15 +32,8 @@ import com.vaadin.shared.util.SharedUtil;
* @since 7.0.0
*/
@Connect(BrowserWindowOpener.class)
public class BrowserWindowOpenerConnector extends AbstractExtensionConnector
implements ClickHandler {

@Override
protected void extend(ServerConnector target) {
final Widget targetWidget = ((ComponentConnector) target).getWidget();

targetWidget.addDomHandler(this, ClickEvent.getType());
}
public class BrowserWindowOpenerConnector
extends AbstractEventTriggerExtensionConnector {

@Override
public BrowserWindowOpenerState getState() {
@@ -53,7 +41,7 @@ public class BrowserWindowOpenerConnector extends AbstractExtensionConnector
}

@Override
public void onClick(ClickEvent event) {
protected void trigger() {
String url = getResourceUrl(BrowserWindowOpenerState.locationResource);
url = addParametersAndFragment(url);
if (url != null) {

+ 55
- 0
client/src/main/java/com/vaadin/client/extensions/EventTrigger.java View File

@@ -0,0 +1,55 @@
/*
* Copyright 2000-2018 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.client.extensions;

import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.HandlerRegistration;

/**
* Provides support for triggering an event from a given parts of a component or
* using various events.
* <p>
* Used by features such as {@link FileDownloaderConnector} and
* {@link BrowserWindowOpenerConnector} to listen to a given event on a given
* element. The component is the one responsible for deciding the element and
* the event to listen to.
* <p>
* This is the client side interface.
* <p>
* If the component on the server side implements
* {@code com.vaadin.server.EventTrigger} then this interface should be
* implemented by the {@link Widget} used by the client side connector.
*
* @since
*/
public interface EventTrigger {

/**
* Adds an appropriate event handler on the correct element inside the
* widget and invokes the given file downloader when the event occurs.
*
* @param command
* The command to execute when the event occurs
* @param partInformation
* Information passed from the server, typically telling which
* element to attach the DOM handler to
* @return a registration handler which can be used to remove the handler
*/
public HandlerRegistration addTrigger(Command command,
String partInformation);

}

+ 8
- 14
client/src/main/java/com/vaadin/client/extensions/FileDownloaderConnector.java View File

@@ -21,33 +21,27 @@ import com.google.gwt.dom.client.IFrameElement;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.Style.Visibility;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ServerConnector;
import com.vaadin.server.FileDownloader;
import com.vaadin.shared.extension.filedownloader.FileDownloaderState;
import com.vaadin.shared.ui.Connect;

@Connect(FileDownloader.class)
public class FileDownloaderConnector extends AbstractExtensionConnector
implements ClickHandler {
public class FileDownloaderConnector
extends AbstractEventTriggerExtensionConnector {

private IFrameElement iframe;

/**
* Called when the download should start.
*
* @since
*/
@Override
protected void extend(ServerConnector target) {
final Widget downloadWidget = ((ComponentConnector) target).getWidget();

downloadWidget.addDomHandler(this, ClickEvent.getType());
}

@Override
public void onClick(ClickEvent event) {
protected void trigger() {
final String url = getResourceUrl("dl");
if (url != null && !url.isEmpty()) {
BrowserInfo browser = BrowserInfo.get();

+ 67
- 8
client/src/main/java/com/vaadin/client/ui/VMenuBar.java View File

@@ -16,8 +16,10 @@
package com.vaadin.client.ui;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

import com.google.gwt.core.client.GWT;
@@ -46,6 +48,7 @@ import com.google.gwt.user.client.ui.HasHTML;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.web.bindery.event.shared.HandlerRegistration;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.LayoutManager;
@@ -53,12 +56,13 @@ import com.vaadin.client.TooltipInfo;
import com.vaadin.client.UIDL;
import com.vaadin.client.Util;
import com.vaadin.client.WidgetUtil;
import com.vaadin.client.extensions.EventTrigger;
import com.vaadin.shared.ui.ContentMode;
import com.vaadin.shared.ui.menubar.MenuBarConstants;

public class VMenuBar extends FocusableFlowPanel
implements CloseHandler<PopupPanel>, KeyPressHandler, KeyDownHandler,
FocusHandler, SubPartAware, MouseOutHandler, MouseOverHandler {
implements CloseHandler<PopupPanel>, KeyPressHandler, KeyDownHandler,
FocusHandler, SubPartAware, MouseOutHandler, MouseOverHandler, EventTrigger {

// The hierarchy of VMenuBar is a bit weird as VMenuBar is the Paintable,
// used for the root menu but also used for the sub menus.
@@ -117,6 +121,8 @@ FocusHandler, SubPartAware, MouseOutHandler, MouseOverHandler {
/** For internal use only. May be removed or replaced in the future. */
public boolean htmlContentAllowed;

private Map<String, List<Command>> triggers = new HashMap<>();

public VMenuBar() {
// Create an empty horizontal menubar
this(false, null);
@@ -414,9 +420,12 @@ FocusHandler, SubPartAware, MouseOutHandler, MouseOverHandler {
* @param item
*/
public void itemClick(CustomMenuItem item) {
if (item.getCommand() != null) {
boolean triggered = triggerEventIfNeeded(item);
if (item.getCommand() != null || triggered) {
try {
item.getCommand().execute();
if (item.getCommand() != null) {
item.getCommand().execute();
}
} finally {
setSelected(null);
if (visibleChildMenu != null) {
@@ -808,6 +817,7 @@ FocusHandler, SubPartAware, MouseOutHandler, MouseOverHandler {
protected ContentMode descriptionContentMode = null;

private String styleName;
private String id;

/**
* Default menu item {@link Widget} constructor for GWT.create().
@@ -1166,6 +1176,14 @@ FocusHandler, SubPartAware, MouseOutHandler, MouseOverHandler {
return null;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

}

/**
@@ -1642,6 +1660,7 @@ FocusHandler, SubPartAware, MouseOutHandler, MouseOverHandler {
openMenuAndFocusFirstIfPossible(getSelected());
} else {
try {
triggerEventIfNeeded(getSelected());
final Command command = getSelected().getCommand();
if (command != null) {
command.execute();
@@ -1654,10 +1673,7 @@ FocusHandler, SubPartAware, MouseOutHandler, MouseOverHandler {
// not leave menu to visible ("hover open") mode
menuVisible = false;

VMenuBar root = this;
while (root.getParentMenu() != null) {
root = root.getParentMenu();
}
VMenuBar root = getRoot();
root.ignoreFocus = true;
root.getElement().focus();
root.ignoreFocus = false;
@@ -1669,6 +1685,17 @@ FocusHandler, SubPartAware, MouseOutHandler, MouseOverHandler {
return false;
}

private boolean triggerEventIfNeeded(CustomMenuItem item) {
List<Command> commands = getTriggers().get(item.getId());
if (commands != null) {
for (Command command : commands) {
command.execute();
}
return true;
}
return false;
}

private void selectFirstItem() {
for (int i = 0; i < items.size(); i++) {
CustomMenuItem item = items.get(i);
@@ -1877,4 +1904,36 @@ FocusHandler, SubPartAware, MouseOutHandler, MouseOverHandler {
public void onMouseOut(MouseOutEvent event) {
LazyCloser.schedule();
}

private VMenuBar getRoot() {
VMenuBar root = this;

while (root.getParentMenu() != null) {
root = root.getParentMenu();
}

return root;
}

@Override
public HandlerRegistration addTrigger(Command command,
String partInformation) {
if (partInformation == null || partInformation.isEmpty()) {
throw new IllegalArgumentException(
"The 'partInformation' parameter must contain the menu item id");
}

getTriggers().computeIfAbsent(partInformation, s-> new ArrayList<>()).add(command);
return () -> {
List<Command> commands = getTriggers().get(partInformation);
if (commands != null) {
commands.remove(command);
}
};
}

private Map<String, List<Command>> getTriggers() {
return getRoot().triggers;
}

}

+ 1
- 0
client/src/main/java/com/vaadin/client/ui/menubar/MenuBarConnector.java View File

@@ -129,6 +129,7 @@ public class MenuBarConnector extends AbstractComponentConnector
}

currentItem = currentMenu.addItem(itemHTML, cmd);
currentItem.setId("" + itemId);
currentItem.updateFromUIDL(item, client);

if (item.getChildCount() > 0) {

+ 1
- 1
documentation/articles/LettingTheUserDownloadAFile.asciidoc View File

@@ -56,7 +56,7 @@ public class LettingUserDownladFile extends UI {
....

To use `FileDownloader`, you just create an instance of the extension
and use it to extend the component that should start the download. You
and use it to extend the component or `MenuItem` that should start the download. You
should also note that `FileDownloader` works best with resources that
are served by Vaadin as it relies on sending some special HTTP headers
along with the file to ensure the browser doesn't try to open the file

+ 19
- 0
server/src/main/java/com/vaadin/server/BrowserWindowOpener.java View File

@@ -122,10 +122,29 @@ public class BrowserWindowOpener extends AbstractExtension {
setResource(BrowserWindowOpenerState.locationResource, resource);
}

/**
* Add this extension to the target component.
*
* @param target
* the component to attach this extension to
*/
public void extend(AbstractComponent target) {
super.extend(target);
}

/**
* Add this extension to the {@code EventTrigger}.
*
* @param eventTrigger
* the trigger to attach this extension to
*
* @since
*/
public void extend(EventTrigger eventTrigger) {
super.extend(eventTrigger.getConnector());
getState().partInformation = eventTrigger.getPartInformation();
}

/**
* Sets the provided URL {@code url} for this instance. The {@code url} will
* be opened in a new browser window/tab when the extended component is

+ 65
- 0
server/src/main/java/com/vaadin/server/EventTrigger.java View File

@@ -0,0 +1,65 @@
/*
* Copyright 2000-2018 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.server;

import java.io.Serializable;

import com.vaadin.ui.Component;
import com.vaadin.ui.MenuBar;

/**
* Provides support for triggering an event from a given parts of a component or
* using various events.
* <p>
* Used by features such as {@link FileDownloader} and
* {@link BrowserWindowOpener} to listen to a given event on a given element on
* the client side. The component is the one responsible for deciding the
* element and the event to listen to and can communicate this to the client
* using {@link #getPartInformation()}.
* <p>
* This is the server side interface.
* <p>
* If a {@link Component} implements this interface, then the corresponding
* connector on the client side must implement
* {@code com.vaadin.client.extensions.EventTrigger}.
*
* @since
*/
public interface EventTrigger extends Serializable {

/**
* Gets the connector who will be used to offer the file download. Typically
* a component containing a certain DOM element, which in turn triggers the
* download.
*
* @return the connector for the file download
*/
AbstractClientConnector getConnector();

/**
* Gets a free form string which identifies which part of the connector that
* should trigger the download. The string is passed to the connector
* (FileDownloaderHandler implementor) on the client side.
* <p>
* For example, {@link MenuBar} passes the id of a menu item through this
* method so that the client side can listen to events for that particular
* item only.
*
* @return a free form string which makes sense to the client side connector
*/
String getPartInformation();

}

+ 19
- 0
server/src/main/java/com/vaadin/server/FileDownloader.java View File

@@ -66,10 +66,29 @@ public class FileDownloader extends AbstractExtension {
setResource("dl", resource);
}

/**
* Add this extension to the target component.
*
* @param target
* the component to attach this extension to
*/
public void extend(AbstractComponent target) {
super.extend(target);
}

/**
* Add this extension to the {@code EventTrigger}.
*
* @param eventTrigger
* the trigger to attach this extension to
*
* @since
*/
public void extend(EventTrigger eventTrigger) {
super.extend(eventTrigger.getConnector());
getState().partInformation = eventTrigger.getPartInformation();
}

/**
* Gets the resource set for download.
*

+ 56
- 1
server/src/main/java/com/vaadin/ui/MenuBar.java View File

@@ -28,6 +28,8 @@ import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.parser.Tag;

import com.vaadin.server.AbstractClientConnector;
import com.vaadin.server.EventTrigger;
import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget;
import com.vaadin.server.Resource;
@@ -217,6 +219,23 @@ implements LegacyComponent, Focusable {
setMoreMenuItem(null);
}

/**
* Adds a new menu item to the menu bar
* <p>
* Clicking on this menu item has no effect. Use
* {@link #addItem(String, Command)} or {@link MenuItem#setCommand(Command)}
* to assign an action to the menu item.
*
* @param caption
* the text for the menu item
* @throws IllegalArgumentException
*
* @since
*/
public MenuBar.MenuItem addItem(String caption) {
return addItem(caption, null, null);
}

/**
* Add a new item to the menu bar. Command can be null, but a caption must
* be given.
@@ -453,7 +472,7 @@ implements LegacyComponent, Focusable {
* multiple MenuItems to a MenuItem and create a sub-menu.
*
*/
public class MenuItem implements Serializable {
public class MenuItem implements Serializable, EventTrigger {

/** Private members * */
private final int itsId;
@@ -522,6 +541,22 @@ implements LegacyComponent, Focusable {
return item;
}

/**
* Add a new menu item inside this menu item, creating a sub-menu.
* <p>
* Clicking on the new item has no effect. Use
* {@link #addItem(String, Command)} or {@link #setCommand(Command)} to
* assign an action to the menu item.
*
* @param caption
* the text for the menu item
*
* @since
*/
public MenuBar.MenuItem addItem(String caption) {
return addItem(caption, null, null);
}

/**
* Add a new item inside this item, thus creating a sub-menu. Command
* can be null, but a caption must be given.
@@ -992,6 +1027,26 @@ implements LegacyComponent, Focusable {
this.checked = checked;
markAsDirty();
}

/**
* Gets the menu bar this item is part of.
*
* @return the menu bar this item is attached to
* @since
*/
public MenuBar getMenuBar() {
return MenuBar.this;
}

@Override
public AbstractClientConnector getConnector() {
return getMenuBar();
}

@Override
public String getPartInformation() {
return String.valueOf(getId());
}
}

@Override

+ 33
- 0
shared/src/main/java/com/vaadin/shared/extension/PartInformationState.java View File

@@ -0,0 +1,33 @@
/*
* Copyright 2000-2018 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.shared.extension;

import com.vaadin.shared.communication.SharedState;

/**
* Shared state for {@code AbstractEventTriggerExtensionConnector} extension.
*
* @since
*/
public class PartInformationState extends SharedState {

/**
* Information passed to the widget on the client side, to allow it to
* attach to the correct DOM element.
*/
public String partInformation;

}

+ 2
- 2
shared/src/main/java/com/vaadin/shared/extension/filedownloader/FileDownloaderState.java View File

@@ -15,7 +15,7 @@
*/
package com.vaadin.shared.extension.filedownloader;

import com.vaadin.shared.communication.SharedState;
import com.vaadin.shared.extension.PartInformationState;

/**
* Shared state for FileDownloader.
@@ -24,6 +24,6 @@ import com.vaadin.shared.communication.SharedState;
*
* @since 8.0
*/
public class FileDownloaderState extends SharedState {
public class FileDownloaderState extends PartInformationState {

}

+ 2
- 2
shared/src/main/java/com/vaadin/shared/ui/BrowserWindowOpenerState.java View File

@@ -19,9 +19,9 @@ package com.vaadin.shared.ui;
import java.util.HashMap;
import java.util.Map;

import com.vaadin.shared.communication.SharedState;
import com.vaadin.shared.extension.PartInformationState;

public class BrowserWindowOpenerState extends SharedState {
public class BrowserWindowOpenerState extends PartInformationState {
public static final String locationResource = "url";

public String target = "_blank";

+ 73
- 0
uitest/src/main/java/com/vaadin/tests/components/MenuBarDownloadBrowserOpenerUI.java View File

@@ -0,0 +1,73 @@
package com.vaadin.tests.components;

import com.vaadin.annotations.Widgetset;
import com.vaadin.server.BrowserWindowOpener;
import com.vaadin.server.ClassResource;
import com.vaadin.server.ConnectorResource;
import com.vaadin.server.ExternalResource;
import com.vaadin.server.FileDownloader;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.embedded.EmbeddedPdf;
import com.vaadin.tests.extensions.EventTriggerExtension;
import com.vaadin.tests.widgetset.TestingWidgetSet;
import com.vaadin.ui.Button;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.MenuItem;

@Widgetset(TestingWidgetSet.NAME)
public class MenuBarDownloadBrowserOpenerUI extends AbstractTestUIWithLog {

@Override
protected void setup(VaadinRequest request) {

ConnectorResource downloadResource = new ClassResource(
EmbeddedPdf.class, "test.pdf");
ExternalResource openResource = new ExternalResource(
"https://vaadin.com");

MenuBar menuBar = new MenuBar();
MenuItem download = menuBar.addItem("Download");
MenuItem saveAsNoLog = download.addItem("Save as without logging...");
MenuItem saveAsLog = download.addItem("Save as with logging...",
item -> log("Download triggered"));
FileDownloader fd = new FileDownloader(downloadResource);
fd.extend(saveAsNoLog);
FileDownloader fd2 = new FileDownloader(downloadResource);
fd2.extend(saveAsLog);

MenuItem open = menuBar.addItem("Open");
MenuItem openNoLog = open.addItem("Open without logging...");
MenuItem openLog = open.addItem("Open with logging...", item -> log("Open triggered"));

BrowserWindowOpener bwo = new BrowserWindowOpener(openResource);
bwo.extend(openNoLog);
BrowserWindowOpener bwo2 = new BrowserWindowOpener(openResource);
bwo2.extend(openLog);

addComponent(menuBar);

addComponent(new Button("Remove downloaders and openers", event -> {
fd.remove();
fd2.remove();
bwo.remove();
bwo2.remove();
}));

setupTestExtension(menuBar);

}

private void setupTestExtension(MenuBar menuBar) {
EventTriggerExtension triggerable1 = new EventTriggerExtension();
EventTriggerExtension triggerable2 = new EventTriggerExtension();

MenuItem testExtension = menuBar.addItem("TestExtension");
MenuItem runMe = testExtension.addItem("RunMe");
triggerable1.extend(runMe);

testExtension.addItem("AddTrigger", c -> triggerable2.extend(runMe));
testExtension.addItem("RemoveTrigger", c -> triggerable2.remove());

}

}

+ 23
- 0
uitest/src/main/java/com/vaadin/tests/extensions/EventTriggerExtension.java View File

@@ -0,0 +1,23 @@
package com.vaadin.tests.extensions;

import com.vaadin.server.AbstractExtension;
import com.vaadin.server.EventTrigger;
import com.vaadin.shared.extension.PartInformationState;

public class EventTriggerExtension extends AbstractExtension {

@Override
protected PartInformationState getState() {
return (PartInformationState) super.getState();
}

@Override
protected PartInformationState getState(boolean markAsDirty) {
return (PartInformationState) super.getState(markAsDirty);
}

public void extend(EventTrigger eventTrigger) {
super.extend(eventTrigger.getConnector());
getState().partInformation = eventTrigger.getPartInformation();
}
}

+ 13
- 0
uitest/src/main/java/com/vaadin/tests/widgetset/client/extension/EventTriggerExtensionConnector.java View File

@@ -0,0 +1,13 @@
package com.vaadin.tests.widgetset.client.extension;

import com.vaadin.client.extensions.AbstractEventTriggerExtensionConnector;
import com.vaadin.shared.ui.Connect;
import com.vaadin.tests.extensions.EventTriggerExtension;

@Connect(EventTriggerExtension.class)
public class EventTriggerExtensionConnector extends AbstractEventTriggerExtensionConnector{
@Override
protected native void trigger() /*-{
alert("Trigger");
}-*/;
}

+ 44
- 0
uitest/src/test/java/com/vaadin/tests/components/MenuBarDownloadBrowserOpenerUITest.java View File

@@ -0,0 +1,44 @@
package com.vaadin.tests.components;

import java.util.List;

import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.Alert;
import org.openqa.selenium.remote.DesiredCapabilities;

import com.vaadin.testbench.elements.MenuBarElement;
import com.vaadin.testbench.parallel.Browser;
import com.vaadin.tests.tb3.MultiBrowserTest;

public class MenuBarDownloadBrowserOpenerUITest extends MultiBrowserTest {
@Override
public List<DesiredCapabilities> getBrowsersToTest() {
//alerts do not work properly on PhantomJS
return getBrowserCapabilities(Browser.CHROME);
}

@Test
public void testTriggerExtension() {
openTestURL();
MenuBarElement first = $(MenuBarElement.class).first();
first.clickItem("TestExtension", "RunMe");
checkAndCloseAlert();

first.clickItem("TestExtension", "AddTrigger");
first.clickItem("TestExtension", "RunMe");
checkAndCloseAlert();
checkAndCloseAlert();

first.clickItem("TestExtension", "RemoveTrigger");
first.clickItem("TestExtension", "RunMe");
checkAndCloseAlert();
}

private void checkAndCloseAlert() {
Alert alert = getDriver().switchTo().alert();
Assert.assertEquals("Trigger",alert.getText());
alert.dismiss();
}

}

Loading…
Cancel
Save