You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BrowserWindowOpener.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. * Copyright 2000-2018 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.server;
  17. import java.util.Collections;
  18. import java.util.Set;
  19. import com.vaadin.shared.ApplicationConstants;
  20. import com.vaadin.shared.ui.BrowserWindowOpenerState;
  21. import com.vaadin.ui.AbstractComponent;
  22. import com.vaadin.ui.UI;
  23. /**
  24. * Component extension that opens a browser popup window when the extended
  25. * component is clicked.
  26. *
  27. * @author Vaadin Ltd
  28. * @since 7.0.0
  29. */
  30. public class BrowserWindowOpener extends AbstractExtension {
  31. private static class BrowserWindowOpenerUIProvider extends UIProvider {
  32. private final String path;
  33. private final Class<? extends UI> uiClass;
  34. public BrowserWindowOpenerUIProvider(Class<? extends UI> uiClass,
  35. String path) {
  36. this.path = ensureInitialSlash(path);
  37. this.uiClass = uiClass;
  38. }
  39. private static String ensureInitialSlash(String path) {
  40. if (path == null) {
  41. return null;
  42. } else if (!path.startsWith("/")) {
  43. return '/' + path;
  44. } else {
  45. return path;
  46. }
  47. }
  48. @Override
  49. public Class<? extends UI> getUIClass(UIClassSelectionEvent event) {
  50. String requestPathInfo = event.getRequest().getPathInfo();
  51. if (path.equals(requestPathInfo)) {
  52. return uiClass;
  53. } else {
  54. return null;
  55. }
  56. }
  57. }
  58. private final BrowserWindowOpenerUIProvider uiProvider;
  59. /**
  60. * Creates a window opener that will open windows containing the provided UI
  61. * class.
  62. * <p>
  63. * Note: The new UI instance will not work with dependency injection (CDI
  64. * and Spring). Use {@link BrowserWindowOpener(String)} instead.
  65. * {@code VaadinServlet.getCurrent().getServletContext().getContextPath()}
  66. * gives the current context path.
  67. *
  68. * @param uiClass
  69. * the UI class that should be opened when the extended component
  70. * is clicked
  71. */
  72. public BrowserWindowOpener(Class<? extends UI> uiClass) {
  73. this(uiClass, generateUIClassUrl(uiClass));
  74. }
  75. /**
  76. * Creates a window opener that will open windows containing the provided UI
  77. * using the provided path.
  78. * <p>
  79. * Note: The new UI instance will not work with dependency injection (CDI
  80. * and Spring). Use {@link BrowserWindowOpener(String)} instead.
  81. * {@code VaadinServlet.getCurrent().getServletContext().getContextPath()}
  82. * gives the current context path.
  83. *
  84. * @param uiClass
  85. * the UI class that should be opened when the extended component
  86. * is clicked
  87. * @param path
  88. * the path that the UI should be bound to
  89. */
  90. public BrowserWindowOpener(Class<? extends UI> uiClass, String path) {
  91. // Create a Resource with a translated URL going to the VaadinService
  92. this(new ExternalResource(
  93. ApplicationConstants.APP_PROTOCOL_PREFIX + path),
  94. new BrowserWindowOpenerUIProvider(uiClass, path));
  95. }
  96. /**
  97. * Creates a window opener that will open windows to the provided URL.
  98. *
  99. * @param url
  100. * the URL to open in the window
  101. */
  102. public BrowserWindowOpener(String url) {
  103. this(new ExternalResource(url));
  104. }
  105. /**
  106. * Creates a window opener that will open window to the provided resource.
  107. *
  108. * @param resource
  109. * the resource to open in the window
  110. */
  111. public BrowserWindowOpener(Resource resource) {
  112. this(resource, null);
  113. }
  114. private BrowserWindowOpener(Resource resource,
  115. BrowserWindowOpenerUIProvider uiProvider) {
  116. this.uiProvider = uiProvider;
  117. setResource(BrowserWindowOpenerState.locationResource, resource);
  118. }
  119. /**
  120. * Add this extension to the target component.
  121. *
  122. * @param target
  123. * the component to attach this extension to
  124. */
  125. public void extend(AbstractComponent target) {
  126. super.extend(target);
  127. }
  128. /**
  129. * Add this extension to the {@code EventTrigger}.
  130. *
  131. * @param eventTrigger
  132. * the trigger to attach this extension to
  133. *
  134. * @since 8.4
  135. */
  136. public void extend(EventTrigger eventTrigger) {
  137. super.extend(eventTrigger.getConnector());
  138. getState().partInformation = eventTrigger.getPartInformation();
  139. }
  140. /**
  141. * Sets the provided URL {@code url} for this instance. The {@code url} will
  142. * be opened in a new browser window/tab when the extended component is
  143. * clicked.
  144. *
  145. * @since 7.4
  146. *
  147. * @param url
  148. * URL to open
  149. */
  150. public void setUrl(String url) {
  151. setResource(new ExternalResource(url));
  152. }
  153. /**
  154. * Sets the provided {@code resource} for this instance. The
  155. * {@code resource} will be opened in a new browser window/tab when the
  156. * extended component is clicked.
  157. *
  158. * @since 7.4
  159. *
  160. * @param resource
  161. * resource to open
  162. */
  163. public void setResource(Resource resource) {
  164. setResource(BrowserWindowOpenerState.locationResource, resource);
  165. }
  166. /**
  167. * Returns the resource for this instance.
  168. *
  169. * @since 7.4
  170. *
  171. * @return resource to open browser window
  172. */
  173. public Resource getResource() {
  174. return getResource(BrowserWindowOpenerState.locationResource);
  175. }
  176. /**
  177. * Returns the URL for this BrowserWindowOpener instance. Returns
  178. * {@code null} if this instance is not URL resource based (a non URL based
  179. * resource has been set for it).
  180. *
  181. * @since 7.4
  182. *
  183. * @return URL to open in the new browser window/tab when the extended
  184. * component is clicked
  185. */
  186. public String getUrl() {
  187. Resource resource = getResource();
  188. if (resource instanceof ExternalResource) {
  189. return ((ExternalResource) resource).getURL();
  190. }
  191. return null;
  192. }
  193. /**
  194. * Sets the target window name that will be used. If a window has already
  195. * been opened with the same name, the contents of that window will be
  196. * replaced instead of opening a new window. If the name is
  197. * <code>null</code> or <code>"_blank"</code>, a new window will always be
  198. * opened.
  199. *
  200. * @param windowName
  201. * the target name for the window
  202. */
  203. public void setWindowName(String windowName) {
  204. getState().target = windowName;
  205. }
  206. /**
  207. * Gets the target window name.
  208. *
  209. * @see #setWindowName(String)
  210. *
  211. * @return the window target string
  212. */
  213. public String getWindowName() {
  214. return getState(false).target;
  215. }
  216. // Avoid breaking url to multiple lines
  217. // @formatter:off
  218. /**
  219. * Sets the features for opening the window. See e.g.
  220. * {@link https://developer.mozilla.org/en-US/docs/DOM/window.open#Position_and_size_features}
  221. * for a description of the commonly supported features.
  222. *
  223. * @param features a string with window features, or <code>null</code> to use the default features.
  224. */
  225. // @formatter:on
  226. public void setFeatures(String features) {
  227. getState().features = features;
  228. }
  229. /**
  230. * Gets the window features.
  231. *
  232. * @see #setFeatures(String)
  233. * @return
  234. */
  235. public String getFeatures() {
  236. return getState(false).features;
  237. }
  238. @Override
  239. protected BrowserWindowOpenerState getState() {
  240. return (BrowserWindowOpenerState) super.getState();
  241. }
  242. @Override
  243. protected BrowserWindowOpenerState getState(boolean markAsDirty) {
  244. return (BrowserWindowOpenerState) super.getState(markAsDirty);
  245. }
  246. @Override
  247. public void attach() {
  248. super.attach();
  249. if (uiProvider != null
  250. && !getSession().getUIProviders().contains(uiProvider)) {
  251. getSession().addUIProvider(uiProvider);
  252. }
  253. }
  254. @Override
  255. public void detach() {
  256. if (uiProvider != null) {
  257. getSession().removeUIProvider(uiProvider);
  258. }
  259. super.detach();
  260. }
  261. private static String generateUIClassUrl(Class<? extends UI> uiClass) {
  262. return "popup/" + uiClass.getSimpleName();
  263. }
  264. /**
  265. * Sets a URI fragment that will be added to the URI opened in the window.
  266. * If the window is opened to contain a Vaadin UI, the fragment will be
  267. * available using {@link Page#getUriFragment()} on the Page instance of the
  268. * new UI.
  269. * <p>
  270. * The default value is <code>null</code>.
  271. *
  272. * @param uriFragment
  273. * the URI fragment string that should be included in the opened
  274. * URI, or <code>null</code> to preserve the original fragment of
  275. * the URI.
  276. */
  277. public void setUriFragment(String uriFragment) {
  278. getState().uriFragment = uriFragment;
  279. }
  280. /**
  281. * Gets that URI fragment configured for opened windows.
  282. *
  283. * @return the URI fragment string, or <code>null</code> if no fragment is
  284. * configured.
  285. *
  286. * @see #setUriFragment(String)
  287. */
  288. public String getUriFragment() {
  289. return getState(false).uriFragment;
  290. }
  291. /**
  292. * Sets a parameter that will be added to the query string of the opened
  293. * URI. If the window is opened to contain a Vaadin UI, the parameter will
  294. * be available using {@link VaadinRequest#getParameter(String)} e.g. using
  295. * the request instance passed to {@link UI#init(VaadinRequest)}.
  296. * <p>
  297. * Setting a parameter with the same name as a previously set parameter will
  298. * replace the previous value.
  299. *
  300. * @param name
  301. * the name of the parameter to add, not <code>null</code>
  302. * @param value
  303. * the value of the parameter to add, not <code>null</code>
  304. *
  305. * @see #removeParameter(String)
  306. * @see #getParameterNames()
  307. * @see #getParameter(String)
  308. */
  309. public void setParameter(String name, String value) {
  310. if (name == null || value == null) {
  311. throw new IllegalArgumentException("Null not allowed");
  312. }
  313. getState().parameters.put(name, value);
  314. }
  315. /**
  316. * Removes a parameter that has been set using
  317. * {@link #setParameter(String, String)}. Removing a parameter that has not
  318. * been set has no effect.
  319. *
  320. * @param name
  321. * the name of the parameter to remove, not <code>null</code>
  322. *
  323. * @see #setParameter(String, String)
  324. */
  325. public void removeParameter(String name) {
  326. if (name == null) {
  327. throw new IllegalArgumentException("Null not allowed");
  328. }
  329. getState().parameters.remove(name);
  330. }
  331. /**
  332. * Gets the names of all parameters set using
  333. * {@link #setParameter(String, String)}.
  334. *
  335. * @return an unmodifiable set of parameter names
  336. *
  337. * @see #setParameter(String, String)
  338. * @see #getParameter(String)
  339. */
  340. public Set<String> getParameterNames() {
  341. return Collections.unmodifiableSet(getState().parameters.keySet());
  342. }
  343. /**
  344. * Gets the value of a parameter set using
  345. * {@link #setParameter(String, String)}. If there is no parameter with the
  346. * given name, <code>null</code> is returned.
  347. *
  348. * @param name
  349. * the name of the parameter to get, not <code>null</code>
  350. * @return the value of the parameter, or <code>null</code> there is no
  351. * parameter
  352. *
  353. * @see #setParameter(String, String)
  354. * @see #getParameter(String)
  355. */
  356. public String getParameter(String name) {
  357. if (name == null) {
  358. throw new IllegalArgumentException("Null not allowed");
  359. }
  360. return getState(false).parameters.get(name);
  361. }
  362. }