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.

VWindow.java 49KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482
  1. /*
  2. * Copyright 2000-2014 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.client.ui;
  17. import static com.vaadin.client.WidgetUtil.isFocusedElementEditable;
  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Collections;
  21. import java.util.Comparator;
  22. import java.util.List;
  23. import com.google.gwt.aria.client.Id;
  24. import com.google.gwt.aria.client.RelevantValue;
  25. import com.google.gwt.aria.client.Roles;
  26. import com.google.gwt.core.client.Scheduler;
  27. import com.google.gwt.core.client.Scheduler.ScheduledCommand;
  28. import com.google.gwt.dom.client.Document;
  29. import com.google.gwt.dom.client.Element;
  30. import com.google.gwt.dom.client.NativeEvent;
  31. import com.google.gwt.dom.client.Style;
  32. import com.google.gwt.dom.client.Style.Display;
  33. import com.google.gwt.dom.client.Style.Position;
  34. import com.google.gwt.dom.client.Style.Unit;
  35. import com.google.gwt.dom.client.Style.Visibility;
  36. import com.google.gwt.event.dom.client.BlurEvent;
  37. import com.google.gwt.event.dom.client.BlurHandler;
  38. import com.google.gwt.event.dom.client.FocusEvent;
  39. import com.google.gwt.event.dom.client.FocusHandler;
  40. import com.google.gwt.event.dom.client.KeyCodes;
  41. import com.google.gwt.event.dom.client.KeyDownEvent;
  42. import com.google.gwt.event.dom.client.KeyDownHandler;
  43. import com.google.gwt.event.dom.client.KeyUpEvent;
  44. import com.google.gwt.event.dom.client.KeyUpHandler;
  45. import com.google.gwt.event.dom.client.ScrollEvent;
  46. import com.google.gwt.event.dom.client.ScrollHandler;
  47. import com.google.gwt.event.shared.HandlerRegistration;
  48. import com.google.gwt.user.client.Command;
  49. import com.google.gwt.user.client.DOM;
  50. import com.google.gwt.user.client.Event;
  51. import com.google.gwt.user.client.Event.NativePreviewEvent;
  52. import com.google.gwt.user.client.Event.NativePreviewHandler;
  53. import com.google.gwt.user.client.Window;
  54. import com.google.gwt.user.client.ui.Widget;
  55. import com.vaadin.client.ApplicationConnection;
  56. import com.vaadin.client.BrowserInfo;
  57. import com.vaadin.client.ComponentConnector;
  58. import com.vaadin.client.ConnectorMap;
  59. import com.vaadin.client.Focusable;
  60. import com.vaadin.client.LayoutManager;
  61. import com.vaadin.client.WidgetUtil;
  62. import com.vaadin.client.debug.internal.VDebugWindow;
  63. import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
  64. import com.vaadin.client.ui.aria.AriaHelper;
  65. import com.vaadin.client.ui.window.WindowMoveEvent;
  66. import com.vaadin.client.ui.window.WindowMoveHandler;
  67. import com.vaadin.shared.Connector;
  68. import com.vaadin.shared.EventId;
  69. import com.vaadin.shared.ui.window.WindowMode;
  70. import com.vaadin.shared.ui.window.WindowRole;
  71. /**
  72. * "Sub window" component.
  73. *
  74. * @author Vaadin Ltd
  75. */
  76. public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
  77. ScrollHandler, KeyDownHandler, KeyUpHandler, FocusHandler, BlurHandler,
  78. Focusable {
  79. private static ArrayList<VWindow> windowOrder = new ArrayList<VWindow>();
  80. private static boolean orderingDefered;
  81. public static final String CLASSNAME = "v-window";
  82. private static final String MODAL_WINDOW_OPEN_CLASSNAME = "v-modal-window-open";
  83. private static final int STACKING_OFFSET_PIXELS = 15;
  84. public static final int Z_INDEX = 10000;
  85. /** For internal use only. May be removed or replaced in the future. */
  86. public Element contents;
  87. /** For internal use only. May be removed or replaced in the future. */
  88. public Element header;
  89. /** For internal use only. May be removed or replaced in the future. */
  90. public Element footer;
  91. private Element resizeBox;
  92. /** For internal use only. May be removed or replaced in the future. */
  93. public final FocusableScrollPanel contentPanel = new FocusableScrollPanel();
  94. private boolean dragging;
  95. private int startX;
  96. private int startY;
  97. private int origX;
  98. private int origY;
  99. private boolean resizing;
  100. private int origW;
  101. private int origH;
  102. /** For internal use only. May be removed or replaced in the future. */
  103. public Element closeBox;
  104. /** For internal use only. May be removed or replaced in the future. */
  105. public Element maximizeRestoreBox;
  106. /** For internal use only. May be removed or replaced in the future. */
  107. public ApplicationConnection client;
  108. /** For internal use only. May be removed or replaced in the future. */
  109. public String id;
  110. /** For internal use only. May be removed or replaced in the future. */
  111. public ShortcutActionHandler shortcutHandler;
  112. /** Last known positionx read from UIDL or updated to application connection */
  113. private int uidlPositionX = -1;
  114. /** Last known positiony read from UIDL or updated to application connection */
  115. private int uidlPositionY = -1;
  116. /** For internal use only. May be removed or replaced in the future. */
  117. public boolean vaadinModality = false;
  118. /** For internal use only. May be removed or replaced in the future. */
  119. public boolean resizable = true;
  120. private boolean draggable = true;
  121. /** For internal use only. May be removed or replaced in the future. */
  122. public boolean resizeLazy = false;
  123. private Element modalityCurtain;
  124. private Element draggingCurtain;
  125. private Element resizingCurtain;
  126. private Element headerText;
  127. private boolean closable = true;
  128. private Connector[] assistiveConnectors = new Connector[0];
  129. private String assistivePrefix;
  130. private String assistivePostfix;
  131. private Element topTabStop;
  132. private Element bottomTabStop;
  133. private NativePreviewHandler topEventBlocker;
  134. private NativePreviewHandler bottomEventBlocker;
  135. private HandlerRegistration topBlockerRegistration;
  136. private HandlerRegistration bottomBlockerRegistration;
  137. // Prevents leaving the window with the Tab key when true
  138. private boolean doTabStop;
  139. /**
  140. * If centered (via UIDL), the window should stay in the centered -mode
  141. * until a position is received from the server, or the user moves or
  142. * resizes the window.
  143. * <p>
  144. * For internal use only. May be removed or replaced in the future.
  145. */
  146. public boolean centered = false;
  147. /** For internal use only. May be removed or replaced in the future. */
  148. public boolean immediate;
  149. private Element wrapper;
  150. /** For internal use only. May be removed or replaced in the future. */
  151. public boolean visibilityChangesDisabled;
  152. /** For internal use only. May be removed or replaced in the future. */
  153. public int bringToFrontSequence = -1;
  154. private VLazyExecutor delayedContentsSizeUpdater = new VLazyExecutor(200,
  155. new ScheduledCommand() {
  156. @Override
  157. public void execute() {
  158. updateContentsSize();
  159. }
  160. });
  161. public VWindow() {
  162. super(false, false, true); // no autohide, not modal, shadow
  163. // Different style of shadow for windows
  164. setShadowStyle("window");
  165. Roles.getDialogRole().set(getElement());
  166. Roles.getDialogRole().setAriaRelevantProperty(getElement(),
  167. RelevantValue.ADDITIONS);
  168. constructDOM();
  169. contentPanel.addScrollHandler(this);
  170. contentPanel.addKeyDownHandler(this);
  171. contentPanel.addKeyUpHandler(this);
  172. contentPanel.addFocusHandler(this);
  173. contentPanel.addBlurHandler(this);
  174. }
  175. @Override
  176. protected void onAttach() {
  177. super.onAttach();
  178. /*
  179. * Stores the element that has focus in the application UI when the
  180. * window is opened, so it can be restored when the window closes.
  181. *
  182. * This is currently implemented for the case when one non-modal window
  183. * can be open at the same time, and the focus is not changed while the
  184. * window is open.
  185. */
  186. getApplicationConnection().getUIConnector().getWidget().storeFocus();
  187. /*
  188. * When this window gets reattached, set the tabstop to the previous
  189. * state.
  190. */
  191. setTabStopEnabled(doTabStop);
  192. // Fix for #14413. Any pseudo elements inside these elements are not
  193. // visible on initial render unless we shake the DOM.
  194. if (BrowserInfo.get().isIE8()) {
  195. closeBox.getStyle().setDisplay(Display.NONE);
  196. maximizeRestoreBox.getStyle().setDisplay(Display.NONE);
  197. Scheduler.get().scheduleFinally(new Command() {
  198. @Override
  199. public void execute() {
  200. closeBox.getStyle().clearDisplay();
  201. maximizeRestoreBox.getStyle().clearDisplay();
  202. }
  203. });
  204. }
  205. }
  206. @Override
  207. protected void onDetach() {
  208. super.onDetach();
  209. /*
  210. * Restores the previously stored focused element.
  211. *
  212. * When the focus was changed outside the window while the window was
  213. * open, the originally stored element is restored.
  214. */
  215. getApplicationConnection().getUIConnector().getWidget()
  216. .focusStoredElement();
  217. removeTabBlockHandlers();
  218. }
  219. private void addTabBlockHandlers() {
  220. if (topBlockerRegistration == null) {
  221. topBlockerRegistration = Event
  222. .addNativePreviewHandler(topEventBlocker);
  223. bottomBlockerRegistration = Event
  224. .addNativePreviewHandler(bottomEventBlocker);
  225. }
  226. }
  227. private void removeTabBlockHandlers() {
  228. if (topBlockerRegistration != null) {
  229. topBlockerRegistration.removeHandler();
  230. topBlockerRegistration = null;
  231. bottomBlockerRegistration.removeHandler();
  232. bottomBlockerRegistration = null;
  233. }
  234. }
  235. public void bringToFront() {
  236. int curIndex = windowOrder.indexOf(this);
  237. if (curIndex + 1 < windowOrder.size()) {
  238. windowOrder.remove(this);
  239. windowOrder.add(this);
  240. for (; curIndex < windowOrder.size(); curIndex++) {
  241. windowOrder.get(curIndex).setWindowOrder(curIndex);
  242. }
  243. }
  244. }
  245. /**
  246. * Returns true if this window is the topmost VWindow
  247. *
  248. * @return
  249. */
  250. private boolean isActive() {
  251. return equals(getTopmostWindow());
  252. }
  253. private static VWindow getTopmostWindow() {
  254. if (windowOrder.size() > 0) {
  255. return windowOrder.get(windowOrder.size() - 1);
  256. }
  257. return null;
  258. }
  259. /** For internal use only. May be removed or replaced in the future. */
  260. public void setWindowOrderAndPosition() {
  261. // This cannot be done in the constructor as the widgets are created in
  262. // a different order than on they should appear on screen
  263. if (windowOrder.contains(this)) {
  264. // Already set
  265. return;
  266. }
  267. final int order = windowOrder.size();
  268. setWindowOrder(order);
  269. windowOrder.add(this);
  270. setPopupPosition(order * STACKING_OFFSET_PIXELS, order
  271. * STACKING_OFFSET_PIXELS);
  272. }
  273. private void setWindowOrder(int order) {
  274. setZIndex(order + Z_INDEX);
  275. }
  276. @Override
  277. protected void setZIndex(int zIndex) {
  278. super.setZIndex(zIndex);
  279. if (vaadinModality) {
  280. getModalityCurtain().getStyle().setZIndex(zIndex);
  281. }
  282. }
  283. protected com.google.gwt.user.client.Element getModalityCurtain() {
  284. if (modalityCurtain == null) {
  285. modalityCurtain = DOM.createDiv();
  286. modalityCurtain.setClassName(CLASSNAME + "-modalitycurtain");
  287. }
  288. return DOM.asOld(modalityCurtain);
  289. }
  290. protected void constructDOM() {
  291. setStyleName(CLASSNAME);
  292. topTabStop = DOM.createDiv();
  293. DOM.setElementAttribute(topTabStop, "tabindex", "0");
  294. header = DOM.createDiv();
  295. DOM.setElementProperty(header, "className", CLASSNAME + "-outerheader");
  296. headerText = DOM.createDiv();
  297. DOM.setElementProperty(headerText, "className", CLASSNAME + "-header");
  298. contents = DOM.createDiv();
  299. DOM.setElementProperty(contents, "className", CLASSNAME + "-contents");
  300. footer = DOM.createDiv();
  301. DOM.setElementProperty(footer, "className", CLASSNAME + "-footer");
  302. resizeBox = DOM.createDiv();
  303. DOM.setElementProperty(resizeBox, "className", CLASSNAME + "-resizebox");
  304. closeBox = DOM.createDiv();
  305. maximizeRestoreBox = DOM.createDiv();
  306. DOM.setElementProperty(maximizeRestoreBox, "className", CLASSNAME
  307. + "-maximizebox");
  308. DOM.setElementAttribute(maximizeRestoreBox, "tabindex", "0");
  309. DOM.setElementProperty(closeBox, "className", CLASSNAME + "-closebox");
  310. DOM.setElementAttribute(closeBox, "tabindex", "0");
  311. DOM.appendChild(footer, resizeBox);
  312. bottomTabStop = DOM.createDiv();
  313. DOM.setElementAttribute(bottomTabStop, "tabindex", "0");
  314. wrapper = DOM.createDiv();
  315. DOM.setElementProperty(wrapper, "className", CLASSNAME + "-wrap");
  316. DOM.appendChild(wrapper, topTabStop);
  317. DOM.appendChild(wrapper, header);
  318. DOM.appendChild(wrapper, maximizeRestoreBox);
  319. DOM.appendChild(wrapper, closeBox);
  320. DOM.appendChild(header, headerText);
  321. DOM.appendChild(wrapper, contents);
  322. DOM.appendChild(wrapper, footer);
  323. DOM.appendChild(wrapper, bottomTabStop);
  324. DOM.appendChild(super.getContainerElement(), wrapper);
  325. sinkEvents(Event.ONDBLCLICK | Event.MOUSEEVENTS | Event.TOUCHEVENTS
  326. | Event.ONCLICK | Event.ONLOSECAPTURE);
  327. setWidget(contentPanel);
  328. // Make the closebox accessible for assistive devices
  329. Roles.getButtonRole().set(closeBox);
  330. Roles.getButtonRole().setAriaLabelProperty(closeBox, "close button");
  331. // Make the maximizebox accessible for assistive devices
  332. Roles.getButtonRole().set(maximizeRestoreBox);
  333. Roles.getButtonRole().setAriaLabelProperty(maximizeRestoreBox,
  334. "maximize button");
  335. // Provide the title to assistive devices
  336. AriaHelper.ensureHasId(headerText);
  337. Roles.getDialogRole().setAriaLabelledbyProperty(getElement(),
  338. Id.of(headerText));
  339. // Handlers to Prevent tab to leave the window
  340. // and backspace to cause browser navigation
  341. topEventBlocker = new NativePreviewHandler() {
  342. @Override
  343. public void onPreviewNativeEvent(NativePreviewEvent event) {
  344. NativeEvent nativeEvent = event.getNativeEvent();
  345. if (nativeEvent.getEventTarget().cast() == topTabStop
  346. && nativeEvent.getKeyCode() == KeyCodes.KEY_TAB
  347. && nativeEvent.getShiftKey()) {
  348. nativeEvent.preventDefault();
  349. }
  350. if (nativeEvent.getEventTarget().cast() == topTabStop
  351. && nativeEvent.getKeyCode() == KeyCodes.KEY_BACKSPACE) {
  352. nativeEvent.preventDefault();
  353. }
  354. }
  355. };
  356. bottomEventBlocker = new NativePreviewHandler() {
  357. @Override
  358. public void onPreviewNativeEvent(NativePreviewEvent event) {
  359. NativeEvent nativeEvent = event.getNativeEvent();
  360. if (nativeEvent.getEventTarget().cast() == bottomTabStop
  361. && nativeEvent.getKeyCode() == KeyCodes.KEY_TAB
  362. && !nativeEvent.getShiftKey()) {
  363. nativeEvent.preventDefault();
  364. }
  365. if (nativeEvent.getEventTarget().cast() == bottomTabStop
  366. && nativeEvent.getKeyCode() == KeyCodes.KEY_BACKSPACE) {
  367. nativeEvent.preventDefault();
  368. }
  369. }
  370. };
  371. }
  372. /**
  373. * Sets the message that is provided to users of assistive devices when the
  374. * user reaches the top of the window when leaving a window with the tab key
  375. * is prevented.
  376. * <p>
  377. * This message is not visible on the screen.
  378. *
  379. * @param topMessage
  380. * String provided when the user navigates with Shift-Tab keys to
  381. * the top of the window
  382. */
  383. public void setTabStopTopAssistiveText(String topMessage) {
  384. Roles.getNoteRole().setAriaLabelProperty(topTabStop, topMessage);
  385. }
  386. /**
  387. * Sets the message that is provided to users of assistive devices when the
  388. * user reaches the bottom of the window when leaving a window with the tab
  389. * key is prevented.
  390. * <p>
  391. * This message is not visible on the screen.
  392. *
  393. * @param bottomMessage
  394. * String provided when the user navigates with the Tab key to
  395. * the bottom of the window
  396. */
  397. public void setTabStopBottomAssistiveText(String bottomMessage) {
  398. Roles.getNoteRole().setAriaLabelProperty(bottomTabStop, bottomMessage);
  399. }
  400. /**
  401. * Gets the message that is provided to users of assistive devices when the
  402. * user reaches the top of the window when leaving a window with the tab key
  403. * is prevented.
  404. *
  405. * @return the top message
  406. */
  407. public String getTabStopTopAssistiveText() {
  408. return Roles.getNoteRole().getAriaLabelProperty(topTabStop);
  409. }
  410. /**
  411. * Gets the message that is provided to users of assistive devices when the
  412. * user reaches the bottom of the window when leaving a window with the tab
  413. * key is prevented.
  414. *
  415. * @return the bottom message
  416. */
  417. public String getTabStopBottomAssistiveText() {
  418. return Roles.getNoteRole().getAriaLabelProperty(bottomTabStop);
  419. }
  420. /**
  421. * Calling this method will defer ordering algorithm, to order windows based
  422. * on servers bringToFront and modality instructions. Non changed windows
  423. * will be left intact.
  424. * <p>
  425. * For internal use only. May be removed or replaced in the future.
  426. */
  427. public static void deferOrdering() {
  428. if (!orderingDefered) {
  429. orderingDefered = true;
  430. Scheduler.get().scheduleFinally(new Command() {
  431. @Override
  432. public void execute() {
  433. doServerSideOrdering();
  434. VNotification.bringNotificationsToFront();
  435. }
  436. });
  437. }
  438. }
  439. private static void doServerSideOrdering() {
  440. orderingDefered = false;
  441. VWindow[] array = windowOrder.toArray(new VWindow[windowOrder.size()]);
  442. Arrays.sort(array, new Comparator<VWindow>() {
  443. @Override
  444. public int compare(VWindow o1, VWindow o2) {
  445. /*
  446. * Order by modality, then by bringtofront sequence.
  447. */
  448. if (o1.vaadinModality && !o2.vaadinModality) {
  449. return 1;
  450. } else if (!o1.vaadinModality && o2.vaadinModality) {
  451. return -1;
  452. } else if (o1.bringToFrontSequence > o2.bringToFrontSequence) {
  453. return 1;
  454. } else if (o1.bringToFrontSequence < o2.bringToFrontSequence) {
  455. return -1;
  456. } else {
  457. return 0;
  458. }
  459. }
  460. });
  461. for (int i = 0; i < array.length; i++) {
  462. VWindow w = array[i];
  463. if (w.bringToFrontSequence != -1 || w.vaadinModality) {
  464. w.bringToFront();
  465. w.bringToFrontSequence = -1;
  466. }
  467. }
  468. }
  469. @Override
  470. public void setVisible(boolean visible) {
  471. /*
  472. * Visibility with VWindow works differently than with other Paintables
  473. * in Vaadin. Invisible VWindows are not attached to DOM at all. Flag is
  474. * used to avoid visibility call from
  475. * ApplicationConnection.updateComponent();
  476. */
  477. if (!visibilityChangesDisabled) {
  478. super.setVisible(visible);
  479. }
  480. if (visible
  481. && BrowserInfo.get().requiresPositionAbsoluteOverflowAutoFix()) {
  482. /*
  483. * Shake up the DOM a bit to make the window shed unnecessary
  484. * scrollbars and resize correctly afterwards. The version fixing
  485. * ticket #11994 which was changing the size to 110% was replaced
  486. * with this due to ticket #12943
  487. */
  488. WidgetUtil
  489. .runWebkitOverflowAutoFix(contents.getFirstChildElement());
  490. }
  491. }
  492. /** For internal use only. May be removed or replaced in the future. */
  493. public void setDraggable(boolean draggable) {
  494. if (this.draggable == draggable) {
  495. return;
  496. }
  497. this.draggable = draggable;
  498. setCursorProperties();
  499. }
  500. private void setCursorProperties() {
  501. if (!draggable) {
  502. header.getStyle().setProperty("cursor", "default");
  503. footer.getStyle().setProperty("cursor", "default");
  504. } else {
  505. header.getStyle().setProperty("cursor", "");
  506. footer.getStyle().setProperty("cursor", "");
  507. }
  508. }
  509. /**
  510. * Sets the closable state of the window. Additionally hides/shows the close
  511. * button according to the new state.
  512. *
  513. * @param closable
  514. * true if the window can be closed by the user
  515. */
  516. public void setClosable(boolean closable) {
  517. if (this.closable == closable) {
  518. return;
  519. }
  520. this.closable = closable;
  521. if (closable) {
  522. closeBox.getStyle().clearDisplay();
  523. } else {
  524. closeBox.getStyle().setDisplay(Display.NONE);
  525. }
  526. }
  527. /**
  528. * Returns the closable state of the sub window. If the sub window is
  529. * closable a decoration (typically an X) is shown to the user. By clicking
  530. * on the X the user can close the window.
  531. *
  532. * @return true if the sub window is closable
  533. */
  534. protected boolean isClosable() {
  535. return closable;
  536. }
  537. @Override
  538. public void show() {
  539. if (!windowOrder.contains(this)) {
  540. // This is needed if the window is hidden and then shown again.
  541. // Otherwise this VWindow is added to windowOrder in the
  542. // constructor.
  543. windowOrder.add(this);
  544. }
  545. if (vaadinModality) {
  546. showModalityCurtain();
  547. }
  548. super.show();
  549. }
  550. @Override
  551. public void hide() {
  552. /*
  553. * If the window has a RichTextArea and the RTA is focused at the time
  554. * of hiding in IE8 only the window will have some problems returning
  555. * the focus to the correct place. Curiously the focus will be returned
  556. * correctly if clicking on the "close" button in the window header but
  557. * closing the window from a button for example in the window will fail.
  558. * Symptom described in #10776
  559. *
  560. * The problematic part is that for the focus to be returned correctly
  561. * an input element needs to be focused in the root panel. Focusing some
  562. * other element apparently won't work.
  563. */
  564. if (BrowserInfo.get().isIE8()) {
  565. fixIE8FocusCaptureIssue();
  566. }
  567. if (vaadinModality) {
  568. hideModalityCurtain();
  569. }
  570. super.hide();
  571. int curIndex = windowOrder.indexOf(this);
  572. // Remove window from windowOrder to avoid references being left
  573. // hanging.
  574. windowOrder.remove(curIndex);
  575. // Update the z-indices of any remaining windows
  576. while (curIndex < windowOrder.size()) {
  577. windowOrder.get(curIndex).setWindowOrder(curIndex++);
  578. }
  579. }
  580. private void fixIE8FocusCaptureIssue() {
  581. Element e = DOM.createInputText();
  582. Style elemStyle = e.getStyle();
  583. elemStyle.setPosition(Position.ABSOLUTE);
  584. elemStyle.setTop(-10, Unit.PX);
  585. elemStyle.setWidth(0, Unit.PX);
  586. elemStyle.setHeight(0, Unit.PX);
  587. contentPanel.getElement().appendChild(e);
  588. e.focus();
  589. contentPanel.getElement().removeChild(e);
  590. }
  591. /** For internal use only. May be removed or replaced in the future. */
  592. public void setVaadinModality(boolean modality) {
  593. vaadinModality = modality;
  594. if (vaadinModality) {
  595. if (isAttached()) {
  596. showModalityCurtain();
  597. }
  598. addTabBlockHandlers();
  599. deferOrdering();
  600. } else {
  601. if (modalityCurtain != null) {
  602. if (isAttached()) {
  603. hideModalityCurtain();
  604. }
  605. modalityCurtain = null;
  606. }
  607. if (!doTabStop) {
  608. removeTabBlockHandlers();
  609. }
  610. }
  611. }
  612. private void showModalityCurtain() {
  613. getModalityCurtain().getStyle().setZIndex(
  614. windowOrder.indexOf(this) + Z_INDEX);
  615. if (isShowing()) {
  616. getOverlayContainer().insertBefore(getModalityCurtain(),
  617. getElement());
  618. } else {
  619. getOverlayContainer().appendChild(getModalityCurtain());
  620. }
  621. Document.get().getBody().addClassName(MODAL_WINDOW_OPEN_CLASSNAME);
  622. }
  623. private void hideModalityCurtain() {
  624. Document.get().getBody().removeClassName(MODAL_WINDOW_OPEN_CLASSNAME);
  625. modalityCurtain.removeFromParent();
  626. if (BrowserInfo.get().isIE()) {
  627. // IE leaks memory in certain cases unless we release the reference
  628. // (#9197)
  629. modalityCurtain = null;
  630. }
  631. }
  632. /*
  633. * Shows an empty div on top of all other content; used when moving, so that
  634. * iframes (etc) do not steal event.
  635. */
  636. private void showDraggingCurtain() {
  637. getElement().getParentElement().insertBefore(getDraggingCurtain(),
  638. getElement());
  639. }
  640. private void hideDraggingCurtain() {
  641. if (draggingCurtain != null) {
  642. draggingCurtain.removeFromParent();
  643. }
  644. }
  645. /*
  646. * Shows an empty div on top of all other content; used when resizing, so
  647. * that iframes (etc) do not steal event.
  648. */
  649. private void showResizingCurtain() {
  650. getElement().getParentElement().insertBefore(getResizingCurtain(),
  651. getElement());
  652. }
  653. private void hideResizingCurtain() {
  654. if (resizingCurtain != null) {
  655. resizingCurtain.removeFromParent();
  656. }
  657. }
  658. private Element getDraggingCurtain() {
  659. if (draggingCurtain == null) {
  660. draggingCurtain = createCurtain();
  661. draggingCurtain.setClassName(CLASSNAME + "-draggingCurtain");
  662. }
  663. return draggingCurtain;
  664. }
  665. private Element getResizingCurtain() {
  666. if (resizingCurtain == null) {
  667. resizingCurtain = createCurtain();
  668. resizingCurtain.setClassName(CLASSNAME + "-resizingCurtain");
  669. }
  670. return resizingCurtain;
  671. }
  672. private Element createCurtain() {
  673. Element curtain = DOM.createDiv();
  674. curtain.getStyle().setPosition(Position.ABSOLUTE);
  675. curtain.getStyle().setTop(0, Unit.PX);
  676. curtain.getStyle().setLeft(0, Unit.PX);
  677. curtain.getStyle().setWidth(100, Unit.PCT);
  678. curtain.getStyle().setHeight(100, Unit.PCT);
  679. curtain.getStyle().setZIndex(VOverlay.Z_INDEX);
  680. return curtain;
  681. }
  682. /** For internal use only. May be removed or replaced in the future. */
  683. public void setResizable(boolean resizability) {
  684. resizable = resizability;
  685. if (resizability) {
  686. DOM.setElementProperty(footer, "className", CLASSNAME + "-footer");
  687. DOM.setElementProperty(resizeBox, "className", CLASSNAME
  688. + "-resizebox");
  689. } else {
  690. DOM.setElementProperty(footer, "className", CLASSNAME + "-footer "
  691. + CLASSNAME + "-footer-noresize");
  692. DOM.setElementProperty(resizeBox, "className", CLASSNAME
  693. + "-resizebox " + CLASSNAME + "-resizebox-disabled");
  694. }
  695. }
  696. public void updateMaximizeRestoreClassName(boolean visible,
  697. WindowMode windowMode) {
  698. String className;
  699. if (windowMode == WindowMode.MAXIMIZED) {
  700. className = CLASSNAME + "-restorebox";
  701. } else {
  702. className = CLASSNAME + "-maximizebox";
  703. }
  704. if (!visible) {
  705. className = className + " " + className + "-disabled";
  706. }
  707. maximizeRestoreBox.setClassName(className);
  708. }
  709. // TODO this will eventually be removed, currently used to avoid updating to
  710. // server side.
  711. public void setPopupPositionNoUpdate(int left, int top) {
  712. if (top < 0) {
  713. // ensure window is not moved out of browser window from top of the
  714. // screen
  715. top = 0;
  716. }
  717. super.setPopupPosition(left, top);
  718. }
  719. @Override
  720. public void setPopupPosition(int left, int top) {
  721. if (top < 0) {
  722. // ensure window is not moved out of browser window from top of the
  723. // screen
  724. top = 0;
  725. }
  726. super.setPopupPosition(left, top);
  727. if (left != uidlPositionX && client != null) {
  728. client.updateVariable(id, "positionx", left, false);
  729. uidlPositionX = left;
  730. }
  731. if (top != uidlPositionY && client != null) {
  732. client.updateVariable(id, "positiony", top, false);
  733. uidlPositionY = top;
  734. }
  735. }
  736. public void setCaption(String c) {
  737. setCaption(c, null);
  738. }
  739. public void setCaption(String c, String iconURL) {
  740. setCaption(c, iconURL, false);
  741. }
  742. public void setCaption(String c, String iconURL, boolean asHtml) {
  743. String html = c;
  744. if (!asHtml) {
  745. c = WidgetUtil.escapeHTML(c);
  746. }
  747. // Provide information to assistive device users that a sub window was
  748. // opened
  749. String prefix = "<span class='"
  750. + AriaHelper.ASSISTIVE_DEVICE_ONLY_STYLE + "'>"
  751. + assistivePrefix + "</span>";
  752. String postfix = "<span class='"
  753. + AriaHelper.ASSISTIVE_DEVICE_ONLY_STYLE + "'>"
  754. + assistivePostfix + "</span>";
  755. html = prefix + html + postfix;
  756. headerText.setInnerHTML(html);
  757. if (iconURL != null) {
  758. Icon icon = client.getIcon(iconURL);
  759. DOM.insertChild(headerText, icon.getElement(), 0);
  760. }
  761. }
  762. /**
  763. * Setter for the text for assistive devices the window caption is prefixed
  764. * with.
  765. *
  766. * @param assistivePrefix
  767. * the assistivePrefix to set
  768. */
  769. public void setAssistivePrefix(String assistivePrefix) {
  770. this.assistivePrefix = assistivePrefix;
  771. }
  772. /**
  773. * Getter for the text for assistive devices the window caption is prefixed
  774. * with.
  775. *
  776. * @return the assistivePrefix
  777. */
  778. public String getAssistivePrefix() {
  779. return assistivePrefix;
  780. }
  781. /**
  782. * Setter for the text for assistive devices the window caption is postfixed
  783. * with.
  784. *
  785. * @param assistivePostfix
  786. * the assistivePostfix to set
  787. */
  788. public void setAssistivePostfix(String assistivePostfix) {
  789. this.assistivePostfix = assistivePostfix;
  790. }
  791. /**
  792. * Getter for the text for assistive devices the window caption is postfixed
  793. * with.
  794. *
  795. * @return the assistivePostfix
  796. */
  797. public String getAssistivePostfix() {
  798. return assistivePostfix;
  799. }
  800. @Override
  801. protected com.google.gwt.user.client.Element getContainerElement() {
  802. // in GWT 1.5 this method is used in PopupPanel constructor
  803. if (contents == null) {
  804. return super.getContainerElement();
  805. }
  806. return DOM.asOld(contents);
  807. }
  808. private Event headerDragPending;
  809. @Override
  810. public void onBrowserEvent(final Event event) {
  811. boolean bubble = true;
  812. final int type = event.getTypeInt();
  813. final Element target = DOM.eventGetTarget(event);
  814. if (resizing || resizeBox == target) {
  815. onResizeEvent(event);
  816. bubble = false;
  817. } else if (isClosable() && target == closeBox) {
  818. if (type == Event.ONCLICK) {
  819. onCloseClick();
  820. }
  821. bubble = false;
  822. } else if (target == maximizeRestoreBox) {
  823. // handled in connector
  824. if (type != Event.ONCLICK) {
  825. bubble = false;
  826. }
  827. } else if (header.isOrHasChild(target) && !dragging) {
  828. // dblclick handled in connector
  829. if (type != Event.ONDBLCLICK && draggable) {
  830. if (type == Event.ONMOUSEDOWN) {
  831. /**
  832. * Prevents accidental selection of window caption or
  833. * content. (#12726)
  834. */
  835. event.preventDefault();
  836. headerDragPending = event;
  837. } else if (type == Event.ONMOUSEMOVE
  838. && headerDragPending != null) {
  839. // ie won't work unless this is set here
  840. dragging = true;
  841. onDragEvent(headerDragPending);
  842. onDragEvent(event);
  843. headerDragPending = null;
  844. } else {
  845. headerDragPending = null;
  846. }
  847. bubble = false;
  848. }
  849. if (type == Event.ONCLICK) {
  850. activateOnClick();
  851. }
  852. } else if (dragging || !contents.isOrHasChild(target)) {
  853. onDragEvent(event);
  854. bubble = false;
  855. } else if (type == Event.ONCLICK) {
  856. activateOnClick();
  857. }
  858. /*
  859. * If clicking on other than the content, move focus to the window.
  860. * After that this windows e.g. gets all keyboard shortcuts.
  861. */
  862. if (type == Event.ONMOUSEDOWN
  863. && !contentPanel.getElement().isOrHasChild(target)
  864. && target != closeBox && target != maximizeRestoreBox) {
  865. contentPanel.focus();
  866. }
  867. if (!bubble) {
  868. event.stopPropagation();
  869. } else {
  870. // Super.onBrowserEvent takes care of Handlers added by the
  871. // ClickEventHandler
  872. super.onBrowserEvent(event);
  873. }
  874. }
  875. private void activateOnClick() {
  876. // clicked inside window or inside header, ensure to be on top
  877. if (!isActive()) {
  878. bringToFront();
  879. }
  880. }
  881. private void onCloseClick() {
  882. // Send the close event to the server
  883. client.updateVariable(id, "close", true, true);
  884. }
  885. private void onResizeEvent(Event event) {
  886. if (resizable && WidgetUtil.isTouchEventOrLeftMouseButton(event)) {
  887. switch (event.getTypeInt()) {
  888. case Event.ONMOUSEDOWN:
  889. case Event.ONTOUCHSTART:
  890. if (!isActive()) {
  891. bringToFront();
  892. }
  893. showResizingCurtain();
  894. if (BrowserInfo.get().isIE()) {
  895. resizeBox.getStyle().setVisibility(Visibility.HIDDEN);
  896. }
  897. resizing = true;
  898. startX = WidgetUtil.getTouchOrMouseClientX(event);
  899. startY = WidgetUtil.getTouchOrMouseClientY(event);
  900. origW = getElement().getOffsetWidth();
  901. origH = getElement().getOffsetHeight();
  902. DOM.setCapture(getElement());
  903. event.preventDefault();
  904. break;
  905. case Event.ONMOUSEUP:
  906. case Event.ONTOUCHEND:
  907. setSize(event, true);
  908. case Event.ONTOUCHCANCEL:
  909. DOM.releaseCapture(getElement());
  910. case Event.ONLOSECAPTURE:
  911. hideResizingCurtain();
  912. if (BrowserInfo.get().isIE()) {
  913. resizeBox.getStyle().clearVisibility();
  914. }
  915. resizing = false;
  916. break;
  917. case Event.ONMOUSEMOVE:
  918. case Event.ONTOUCHMOVE:
  919. if (resizing) {
  920. centered = false;
  921. setSize(event, false);
  922. event.preventDefault();
  923. }
  924. break;
  925. default:
  926. event.preventDefault();
  927. break;
  928. }
  929. }
  930. }
  931. /**
  932. * TODO check if we need to support this with touch based devices.
  933. *
  934. * Checks if the cursor was inside the browser content area when the event
  935. * happened.
  936. *
  937. * @param event
  938. * The event to be checked
  939. * @return true, if the cursor is inside the browser content area
  940. *
  941. * false, otherwise
  942. */
  943. private boolean cursorInsideBrowserContentArea(Event event) {
  944. if (event.getClientX() < 0 || event.getClientY() < 0) {
  945. // Outside to the left or above
  946. return false;
  947. }
  948. if (event.getClientX() > Window.getClientWidth()
  949. || event.getClientY() > Window.getClientHeight()) {
  950. // Outside to the right or below
  951. return false;
  952. }
  953. return true;
  954. }
  955. private void setSize(Event event, boolean updateVariables) {
  956. if (!cursorInsideBrowserContentArea(event)) {
  957. // Only drag while cursor is inside the browser client area
  958. return;
  959. }
  960. int w = WidgetUtil.getTouchOrMouseClientX(event) - startX + origW;
  961. int h = WidgetUtil.getTouchOrMouseClientY(event) - startY + origH;
  962. w = Math.max(w, getMinWidth());
  963. h = Math.max(h, getMinHeight());
  964. setWidth(w + "px");
  965. setHeight(h + "px");
  966. if (updateVariables) {
  967. // sending width back always as pixels, no need for unit
  968. client.updateVariable(id, "width", w, false);
  969. client.updateVariable(id, "height", h, immediate);
  970. }
  971. if (updateVariables || !resizeLazy) {
  972. // Resize has finished or is not lazy
  973. updateContentsSize();
  974. } else {
  975. // Lazy resize - wait for a while before re-rendering contents
  976. delayedContentsSizeUpdater.trigger();
  977. }
  978. }
  979. private int getMinHeight() {
  980. return getPixelValue(getElement().getStyle().getProperty("minHeight"));
  981. }
  982. private int getMinWidth() {
  983. return getPixelValue(getElement().getStyle().getProperty("minWidth"));
  984. }
  985. private static int getPixelValue(String size) {
  986. if (size == null || !size.endsWith("px")) {
  987. return -1;
  988. } else {
  989. return Integer.parseInt(size.substring(0, size.length() - 2));
  990. }
  991. }
  992. public void updateContentsSize() {
  993. LayoutManager layoutManager = getLayoutManager();
  994. layoutManager.setNeedsMeasure(ConnectorMap.get(client).getConnector(
  995. this));
  996. layoutManager.layoutNow();
  997. }
  998. @Override
  999. public void setWidth(String width) {
  1000. // Override PopupPanel which sets the width to the contents
  1001. getElement().getStyle().setProperty("width", width);
  1002. // Update v-has-width in case undefined window is resized
  1003. setStyleName("v-has-width", width != null && width.length() > 0);
  1004. }
  1005. @Override
  1006. public void setHeight(String height) {
  1007. // Override PopupPanel which sets the height to the contents
  1008. getElement().getStyle().setProperty("height", height);
  1009. // Update v-has-height in case undefined window is resized
  1010. setStyleName("v-has-height", height != null && height.length() > 0);
  1011. }
  1012. private void onDragEvent(Event event) {
  1013. if (!WidgetUtil.isTouchEventOrLeftMouseButton(event)) {
  1014. return;
  1015. }
  1016. switch (DOM.eventGetType(event)) {
  1017. case Event.ONTOUCHSTART:
  1018. if (event.getTouches().length() > 1) {
  1019. return;
  1020. }
  1021. case Event.ONMOUSEDOWN:
  1022. if (!isActive()) {
  1023. bringToFront();
  1024. }
  1025. beginMovingWindow(event);
  1026. break;
  1027. case Event.ONMOUSEUP:
  1028. case Event.ONTOUCHEND:
  1029. case Event.ONTOUCHCANCEL:
  1030. case Event.ONLOSECAPTURE:
  1031. stopMovingWindow();
  1032. break;
  1033. case Event.ONMOUSEMOVE:
  1034. case Event.ONTOUCHMOVE:
  1035. moveWindow(event);
  1036. break;
  1037. default:
  1038. break;
  1039. }
  1040. }
  1041. private void moveWindow(Event event) {
  1042. if (dragging) {
  1043. centered = false;
  1044. if (cursorInsideBrowserContentArea(event)) {
  1045. // Only drag while cursor is inside the browser client area
  1046. final int x = WidgetUtil.getTouchOrMouseClientX(event) - startX
  1047. + origX;
  1048. final int y = WidgetUtil.getTouchOrMouseClientY(event) - startY
  1049. + origY;
  1050. setPopupPosition(x, y);
  1051. }
  1052. DOM.eventPreventDefault(event);
  1053. }
  1054. }
  1055. private void beginMovingWindow(Event event) {
  1056. if (draggable) {
  1057. showDraggingCurtain();
  1058. dragging = true;
  1059. startX = WidgetUtil.getTouchOrMouseClientX(event);
  1060. startY = WidgetUtil.getTouchOrMouseClientY(event);
  1061. origX = DOM.getAbsoluteLeft(getElement());
  1062. origY = DOM.getAbsoluteTop(getElement());
  1063. DOM.setCapture(getElement());
  1064. DOM.eventPreventDefault(event);
  1065. }
  1066. }
  1067. private void stopMovingWindow() {
  1068. dragging = false;
  1069. hideDraggingCurtain();
  1070. DOM.releaseCapture(getElement());
  1071. // fire move event
  1072. fireEvent(new WindowMoveEvent(uidlPositionX, uidlPositionY));
  1073. }
  1074. @Override
  1075. public boolean onEventPreview(Event event) {
  1076. if (dragging) {
  1077. onDragEvent(event);
  1078. return false;
  1079. } else if (resizing) {
  1080. onResizeEvent(event);
  1081. return false;
  1082. }
  1083. // TODO This is probably completely unnecessary as the modality curtain
  1084. // prevents events from reaching other windows and any security check
  1085. // must be done on the server side and not here.
  1086. // The code here is also run many times as each VWindow has an event
  1087. // preview but we cannot check only the current VWindow here (e.g.
  1088. // if(isTopMost) {...}) because PopupPanel will cause all events that
  1089. // are not cancelled here and target this window to be consume():d
  1090. // meaning the event won't be sent to the rest of the preview handlers.
  1091. if (getTopmostWindow() != null && getTopmostWindow().vaadinModality) {
  1092. // Topmost window is modal. Cancel the event if it targets something
  1093. // outside that window (except debug console...)
  1094. if (DOM.getCaptureElement() != null) {
  1095. // Allow events when capture is set
  1096. return true;
  1097. }
  1098. final Element target = event.getEventTarget().cast();
  1099. if (!DOM.isOrHasChild(getTopmostWindow().getElement(), target)) {
  1100. // not within the modal window, but let's see if it's in the
  1101. // debug window
  1102. Widget w = WidgetUtil.findWidget(target, null);
  1103. while (w != null) {
  1104. if (w instanceof VDebugWindow) {
  1105. return true; // allow debug-window clicks
  1106. } else if (ConnectorMap.get(client).isConnector(w)) {
  1107. return false;
  1108. }
  1109. w = w.getParent();
  1110. }
  1111. return false;
  1112. }
  1113. }
  1114. return true;
  1115. }
  1116. @Override
  1117. public void addStyleDependentName(String styleSuffix) {
  1118. // VWindow's getStyleElement() does not return the same element as
  1119. // getElement(), so we need to override this.
  1120. setStyleName(getElement(), getStylePrimaryName() + "-" + styleSuffix,
  1121. true);
  1122. }
  1123. @Override
  1124. public ShortcutActionHandler getShortcutActionHandler() {
  1125. return shortcutHandler;
  1126. }
  1127. @Override
  1128. public void onScroll(ScrollEvent event) {
  1129. client.updateVariable(id, "scrollTop",
  1130. contentPanel.getScrollPosition(), false);
  1131. client.updateVariable(id, "scrollLeft",
  1132. contentPanel.getHorizontalScrollPosition(), false);
  1133. }
  1134. @Override
  1135. public void onKeyDown(KeyDownEvent event) {
  1136. if (vaadinModality
  1137. && event.getNativeKeyCode() == KeyCodes.KEY_BACKSPACE
  1138. && !isFocusedElementEditable()) {
  1139. event.preventDefault();
  1140. }
  1141. if (shortcutHandler != null) {
  1142. shortcutHandler
  1143. .handleKeyboardEvent(Event.as(event.getNativeEvent()));
  1144. return;
  1145. }
  1146. }
  1147. @Override
  1148. public void onKeyUp(KeyUpEvent event) {
  1149. if (isClosable() && event.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
  1150. onCloseClick();
  1151. }
  1152. }
  1153. @Override
  1154. public void onBlur(BlurEvent event) {
  1155. if (client.hasEventListeners(this, EventId.BLUR)) {
  1156. client.updateVariable(id, EventId.BLUR, "", true);
  1157. }
  1158. }
  1159. @Override
  1160. public void onFocus(FocusEvent event) {
  1161. if (client.hasEventListeners(this, EventId.FOCUS)) {
  1162. client.updateVariable(id, EventId.FOCUS, "", true);
  1163. }
  1164. }
  1165. @Override
  1166. public void focus() {
  1167. contentPanel.focus();
  1168. }
  1169. private int getDecorationHeight() {
  1170. LayoutManager lm = getLayoutManager();
  1171. int headerHeight = lm.getOuterHeight(header);
  1172. int footerHeight = lm.getOuterHeight(footer);
  1173. return headerHeight + footerHeight;
  1174. }
  1175. private LayoutManager getLayoutManager() {
  1176. return LayoutManager.get(client);
  1177. }
  1178. private int getDecorationWidth() {
  1179. LayoutManager layoutManager = getLayoutManager();
  1180. return layoutManager.getOuterWidth(getElement())
  1181. - contentPanel.getElement().getOffsetWidth();
  1182. }
  1183. /**
  1184. * Allows to specify which connectors contain the description for the
  1185. * window. Text contained in the widgets of the connectors will be read by
  1186. * assistive devices when it is opened.
  1187. * <p>
  1188. * When the provided array is empty, an existing description is removed.
  1189. *
  1190. * @param connectors
  1191. * with the connectors of the widgets to use as description
  1192. */
  1193. public void setAssistiveDescription(Connector[] connectors) {
  1194. if (connectors != null) {
  1195. assistiveConnectors = connectors;
  1196. if (connectors.length == 0) {
  1197. Roles.getDialogRole().removeAriaDescribedbyProperty(
  1198. getElement());
  1199. } else {
  1200. Id[] ids = new Id[connectors.length];
  1201. for (int index = 0; index < connectors.length; index++) {
  1202. if (connectors[index] == null) {
  1203. throw new IllegalArgumentException(
  1204. "All values in parameter description need to be non-null");
  1205. }
  1206. Element element = ((ComponentConnector) connectors[index])
  1207. .getWidget().getElement();
  1208. AriaHelper.ensureHasId(element);
  1209. ids[index] = Id.of(element);
  1210. }
  1211. Roles.getDialogRole().setAriaDescribedbyProperty(getElement(),
  1212. ids);
  1213. }
  1214. } else {
  1215. throw new IllegalArgumentException(
  1216. "Parameter description must be non-null");
  1217. }
  1218. }
  1219. /**
  1220. * Gets the connectors that are used as assistive description. Text
  1221. * contained in these connectors will be read by assistive devices when the
  1222. * window is opened.
  1223. *
  1224. * @return list of previously set connectors
  1225. */
  1226. public List<Connector> getAssistiveDescription() {
  1227. return Collections.unmodifiableList(Arrays.asList(assistiveConnectors));
  1228. }
  1229. /**
  1230. * Sets the WAI-ARIA role the window.
  1231. *
  1232. * This role defines how an assistive device handles a window. Available
  1233. * roles are alertdialog and dialog (@see <a
  1234. * href="http://www.w3.org/TR/2011/CR-wai-aria-20110118/roles">Roles
  1235. * Model</a>).
  1236. *
  1237. * The default role is dialog.
  1238. *
  1239. * @param role
  1240. * WAI-ARIA role to set for the window
  1241. */
  1242. public void setWaiAriaRole(WindowRole role) {
  1243. if (role == WindowRole.ALERTDIALOG) {
  1244. Roles.getAlertdialogRole().set(getElement());
  1245. } else {
  1246. Roles.getDialogRole().set(getElement());
  1247. }
  1248. }
  1249. /**
  1250. * Registers the handlers that prevent to leave the window using the
  1251. * Tab-key.
  1252. * <p>
  1253. * The value of the parameter doTabStop is stored and used for non-modal
  1254. * windows. For modal windows, the handlers are always registered, while
  1255. * preserving the stored value.
  1256. *
  1257. * @param doTabStop
  1258. * true to prevent leaving the window, false to allow leaving the
  1259. * window for non modal windows
  1260. */
  1261. public void setTabStopEnabled(boolean doTabStop) {
  1262. this.doTabStop = doTabStop;
  1263. if (doTabStop || vaadinModality) {
  1264. addTabBlockHandlers();
  1265. } else {
  1266. removeTabBlockHandlers();
  1267. }
  1268. }
  1269. /**
  1270. * Adds a Handler for when user moves the window.
  1271. *
  1272. * @since 7.1.9
  1273. *
  1274. * @return {@link HandlerRegistration} used to remove the handler
  1275. */
  1276. public HandlerRegistration addMoveHandler(WindowMoveHandler handler) {
  1277. return addHandler(handler, WindowMoveEvent.getType());
  1278. }
  1279. }