/* * Copyright 2000-2016 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.util.Collections; import java.util.Set; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.ui.BrowserWindowOpenerState; import com.vaadin.ui.AbstractComponent; import com.vaadin.ui.UI; /** * Component extension that opens a browser popup window when the extended * component is clicked. * * @author Vaadin Ltd * @since 7.0.0 */ public class BrowserWindowOpener extends AbstractExtension { private static class BrowserWindowOpenerUIProvider extends UIProvider { private final String path; private final Class<? extends UI> uiClass; public BrowserWindowOpenerUIProvider(Class<? extends UI> uiClass, String path) { this.path = ensureInitialSlash(path); this.uiClass = uiClass; } private static String ensureInitialSlash(String path) { if (path == null) { return null; } else if (!path.startsWith("/")) { return '/' + path; } else { return path; } } @Override public Class<? extends UI> getUIClass(UIClassSelectionEvent event) { String requestPathInfo = event.getRequest().getPathInfo(); if (path.equals(requestPathInfo)) { return uiClass; } else { return null; } } } private final BrowserWindowOpenerUIProvider uiProvider; /** * Creates a window opener that will open windows containing the provided UI * class * * @param uiClass * the UI class that should be opened when the extended component * is clicked */ public BrowserWindowOpener(Class<? extends UI> uiClass) { this(uiClass, generateUIClassUrl(uiClass)); } /** * Creates a window opener that will open windows containing the provided UI * using the provided path * * @param uiClass * the UI class that should be opened when the extended component * is clicked * @param path * the path that the UI should be bound to */ public BrowserWindowOpener(Class<? extends UI> uiClass, String path) { // Create a Resource with a translated URL going to the VaadinService this(new ExternalResource( ApplicationConstants.APP_PROTOCOL_PREFIX + path), new BrowserWindowOpenerUIProvider(uiClass, path)); } /** * Creates a window opener that will open windows to the provided URL * * @param url * the URL to open in the window */ public BrowserWindowOpener(String url) { this(new ExternalResource(url)); } /** * Creates a window opener that will open window to the provided resource * * @param resource * the resource to open in the window */ public BrowserWindowOpener(Resource resource) { this(resource, null); } private BrowserWindowOpener(Resource resource, BrowserWindowOpenerUIProvider uiProvider) { this.uiProvider = uiProvider; setResource(BrowserWindowOpenerState.locationResource, resource); } public void extend(AbstractComponent target) { super.extend(target); } /** * 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 * clicked. * * @since 7.4 * * @param url * URL to open */ public void setUrl(String url) { setResource(new ExternalResource(url)); } /** * Sets the provided {@code resource} for this instance. The * {@code resource} will be opened in a new browser window/tab when the * extended component is clicked. * * @since 7.4 * * @param resource * resource to open */ public void setResource(Resource resource) { setResource(BrowserWindowOpenerState.locationResource, resource); } /** * Returns the resource for this instance. * * @since 7.4 * * @return resource to open browser window */ public Resource getResource() { return getResource(BrowserWindowOpenerState.locationResource); } /** * Returns the URL for this BrowserWindowOpener instance. Returns * {@code null} if this instance is not URL resource based (a non URL based * resource has been set for it). * * @since 7.4 * * @return URL to open in the new browser window/tab when the extended * component is clicked */ public String getUrl() { Resource resource = getResource(); if (resource instanceof ExternalResource) { return ((ExternalResource) resource).getURL(); } return null; } /** * Sets the target window name that will be used. If a window has already * been opened with the same name, the contents of that window will be * replaced instead of opening a new window. If the name is * <code>null</code> or <code>"_blank"</code>, a new window will always be * opened. * * @param windowName * the target name for the window */ public void setWindowName(String windowName) { getState().target = windowName; } /** * Gets the target window name. * * @see #setWindowName(String) * * @return the window target string */ public String getWindowName() { return getState(false).target; } // Avoid breaking url to multiple lines // @formatter:off /** * Sets the features for opening the window. See e.g. * {@link https://developer.mozilla.org/en-US/docs/DOM/window.open#Position_and_size_features} * for a description of the commonly supported features. * * @param features a string with window features, or <code>null</code> to use the default features. */ // @formatter:on public void setFeatures(String features) { getState().features = features; } /** * Gets the window features. * * @see #setFeatures(String) * @return */ public String getFeatures() { return getState(false).features; } @Override protected BrowserWindowOpenerState getState() { return (BrowserWindowOpenerState) super.getState(); } @Override protected BrowserWindowOpenerState getState(boolean markAsDirty) { return (BrowserWindowOpenerState) super.getState(markAsDirty); } @Override public void attach() { super.attach(); if (uiProvider != null && !getSession().getUIProviders().contains(uiProvider)) { getSession().addUIProvider(uiProvider); } } @Override public void detach() { if (uiProvider != null) { getSession().removeUIProvider(uiProvider); } super.detach(); } private static String generateUIClassUrl(Class<? extends UI> uiClass) { return "popup/" + uiClass.getSimpleName(); } /** * Sets a URI fragment that will be added to the URI opened in the window. * If the window is opened to contain a Vaadin UI, the fragment will be * available using {@link Page#getUriFragment()} on the Page instance of the * new UI. * <p> * The default value is <code>null</code>. * * @param uriFragment * the URI fragment string that should be included in the opened * URI, or <code>null</code> to preserve the original fragment of * the URI. */ public void setUriFragment(String uriFragment) { getState().uriFragment = uriFragment; } /** * Gets that URI fragment configured for opened windows. * * @return the URI fragment string, or <code>null</code> if no fragment is * configured. * * @see #setUriFragment(String) */ public String getUriFragment() { return getState(false).uriFragment; } /** * Sets a parameter that will be added to the query string of the opened * URI. If the window is opened to contain a Vaadin UI, the parameter will * be available using {@link VaadinRequest#getParameter(String)} e.g. using * the request instance passed to {@link UI#init(VaadinRequest)}. * <p> * Setting a parameter with the same name as a previously set parameter will * replace the previous value. * * @param name * the name of the parameter to add, not <code>null</code> * @param value * the value of the parameter to add, not <code>null</code> * * @see #removeParameter(String) * @see #getParameterNames() * @see #getParameter(String) */ public void setParameter(String name, String value) { if (name == null || value == null) { throw new IllegalArgumentException("Null not allowed"); } getState().parameters.put(name, value); } /** * Removes a parameter that has been set using * {@link #setParameter(String, String)}. Removing a parameter that has not * been set has no effect. * * @param name * the name of the parameter to remove, not <code>null</code> * * @see #setParameter(String, String) */ public void removeParameter(String name) { if (name == null) { throw new IllegalArgumentException("Null not allowed"); } getState().parameters.remove(name); } /** * Gets the names of all parameters set using * {@link #setParameter(String, String)}. * * @return an unmodifiable set of parameter names * * @see #setParameter(String, String) * @see #getParameter(String) */ public Set<String> getParameterNames() { return Collections.unmodifiableSet(getState().parameters.keySet()); } /** * Gets the value of a parameter set using * {@link #setParameter(String, String)}. If there is no parameter with the * given name, <code>null</code> is returned. * * @param name * the name of the parameter to get, not <code>null</code> * @return the value of the parameter, or <code>null</code> there is no * parameter * * @see #setParameter(String, String) * @see #getParameter(String) */ public String getParameter(String name) { if (name == null) { throw new IllegalArgumentException("Null not allowed"); } return getState(false).parameters.get(name); } }