Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
12 роки тому
11 роки тому
Font icon support (#13152) Renamed Icon to ImageIcon Change-Id: I608815f17a3651b205fed81b5294385df0d68802 Extracted the abstract client-side Icon class Change-Id: Ic32e270595a5796d0bbd1dd31f34282b56672aa9 Created the FontIcon class Change-Id: Iad13871e7bf1807dee2c538c76306d4620191f5e Renamed AbstractComponentConnector.getIcon to getIconUri Change-Id: I6953ab79661993b561655d483c1bd013b66407f3 Added the AbstractComponentConnector.getIcon method Change-Id: I6fb91dc643fb09da3ba53666b1a8a289901702e3 Refactored getIcon Change-Id: Ibae39e66d0fb8449e20ac5209eb8c18b6ada4387 Made all existing uses of Icon compatible with FontIcons Change-Id: I8f28ec5254f2e5282a887519d3f44bc1e27aba72 Initial server-side support for font icons - does not include an actual icon set yet (#13152) Change-Id: Ie6c09b17dd577c726e0efc13567749f6f4d56d8d Changed server side FontIcon URI generation to match the correct scheme Change-Id: I3628b930b310b3f285bc58a3f471e31e641d307e Initial server-side icon font (FontAwesome) with scss - to be considered placeholder for testing (#13152) Change-Id: I361e62aba0d943a736471824e149d65c7eea9c76 Changed the FontIcon URI scheme Change-Id: I15c92f6bb3d0aa0a800f3f0bfa80419979453e17 Added FontIcon support to AbstractOrderedLayoutConnector Change-Id: I3b2b45b22d29622fd888dbe922aa0cc8a718104d Added FontIcon support to table items Change-Id: Id22ce94c96a892420aab1e39663688fc9f3bc282 Added FontIcon support to OptionGroup items Change-Id: Ie08bef688f6802182ef5f8b2bf82cf8b1f9096bb Switched to openly use FontAwesome (#13152) Change-Id: I18c3325ce93915b7fd6e338c8c293a89711277bc VaadinIcons are now FontAwesome (#13152) Change-Id: I0ab2a80735cbf08b6e33d358e3e8c6a205626fc4 VCaption does not longer set icon to 0x0px if it's a FontIcon (#13152) Change-Id: Ibcd96e0f79f0adf2e217a8580d17f1cc93705710 Fixed typo in @font-face, removed .otf (#13152) Change-Id: I698ca32c560e5f198c32a6c44f7884d3030ee610 Make font icons behave more like img (display:inline-block) (#13152) Change-Id: Ic79186c90f1fc566deae1f4d8d4ba2c21d89a42e
10 роки тому
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  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.client.ui.window;
  17. import java.util.logging.Logger;
  18. import com.google.gwt.core.client.Scheduler;
  19. import com.google.gwt.dom.client.Element;
  20. import com.google.gwt.dom.client.NativeEvent;
  21. import com.google.gwt.dom.client.Node;
  22. import com.google.gwt.dom.client.NodeList;
  23. import com.google.gwt.dom.client.Style;
  24. import com.google.gwt.dom.client.Style.Position;
  25. import com.google.gwt.dom.client.Style.Unit;
  26. import com.google.gwt.event.dom.client.ClickEvent;
  27. import com.google.gwt.event.dom.client.ClickHandler;
  28. import com.google.gwt.event.dom.client.DoubleClickEvent;
  29. import com.google.gwt.event.dom.client.DoubleClickHandler;
  30. import com.google.gwt.event.dom.client.KeyCodes;
  31. import com.google.gwt.event.dom.client.KeyUpEvent;
  32. import com.google.gwt.event.dom.client.KeyUpHandler;
  33. import com.google.gwt.user.client.DOM;
  34. import com.google.gwt.user.client.Window;
  35. import com.vaadin.client.ApplicationConnection;
  36. import com.vaadin.client.ComponentConnector;
  37. import com.vaadin.client.ConnectorHierarchyChangeEvent;
  38. import com.vaadin.client.LayoutManager;
  39. import com.vaadin.client.Paintable;
  40. import com.vaadin.client.UIDL;
  41. import com.vaadin.client.communication.StateChangeEvent;
  42. import com.vaadin.client.ui.AbstractSingleComponentContainerConnector;
  43. import com.vaadin.client.ui.ClickEventHandler;
  44. import com.vaadin.client.ui.PostLayoutListener;
  45. import com.vaadin.client.ui.ShortcutActionHandler;
  46. import com.vaadin.client.ui.SimpleManagedLayout;
  47. import com.vaadin.client.ui.VWindow;
  48. import com.vaadin.client.ui.layout.MayScrollChildren;
  49. import com.vaadin.shared.MouseEventDetails;
  50. import com.vaadin.shared.ui.Connect;
  51. import com.vaadin.shared.ui.window.WindowMode;
  52. import com.vaadin.shared.ui.window.WindowServerRpc;
  53. import com.vaadin.shared.ui.window.WindowState;
  54. @Connect(value = com.vaadin.ui.Window.class)
  55. public class WindowConnector extends AbstractSingleComponentContainerConnector
  56. implements Paintable, SimpleManagedLayout, PostLayoutListener,
  57. MayScrollChildren, WindowMoveHandler {
  58. private Node windowClone;
  59. private ClickEventHandler clickEventHandler = new ClickEventHandler(this) {
  60. @Override
  61. protected void fireClick(NativeEvent event,
  62. MouseEventDetails mouseDetails) {
  63. getRpcProxy(WindowServerRpc.class).click(mouseDetails);
  64. }
  65. };
  66. abstract class WindowEventHandler
  67. implements ClickHandler, DoubleClickHandler, KeyUpHandler {
  68. }
  69. private WindowEventHandler maximizeRestoreClickHandler = new WindowEventHandler() {
  70. @Override
  71. public void onClick(ClickEvent event) {
  72. final Element target = event.getNativeEvent().getEventTarget()
  73. .cast();
  74. if (target == getWidget().maximizeRestoreBox) {
  75. // Click on maximize/restore box
  76. onMaximizeRestore();
  77. }
  78. }
  79. @Override
  80. public void onDoubleClick(DoubleClickEvent event) {
  81. final Element target = event.getNativeEvent().getEventTarget()
  82. .cast();
  83. if (getWidget().header.isOrHasChild(target)) {
  84. // Double click on header
  85. onMaximizeRestore();
  86. }
  87. }
  88. @Override
  89. public void onKeyUp(KeyUpEvent event) {
  90. final int keyCode = event.getNativeKeyCode();
  91. final Element target = event.getNativeEvent().getEventTarget()
  92. .cast();
  93. // key ENTER or SPACE on maximize/restore box
  94. if (target == getWidget().maximizeRestoreBox
  95. && isKeyEnterOrSpace(keyCode)) {
  96. onMaximizeRestore();
  97. }
  98. }
  99. };
  100. @Override
  101. public boolean delegateCaptionHandling() {
  102. return false;
  103. }
  104. @Override
  105. protected void init() {
  106. super.init();
  107. VWindow window = getWidget();
  108. window.id = getConnectorId();
  109. window.client = getConnection();
  110. window.connector = this;
  111. getLayoutManager().registerDependency(this,
  112. window.contentPanel.getElement());
  113. getLayoutManager().registerDependency(this, window.header);
  114. getLayoutManager().registerDependency(this, window.footer);
  115. window.addHandler(maximizeRestoreClickHandler, ClickEvent.getType());
  116. window.addHandler(maximizeRestoreClickHandler,
  117. DoubleClickEvent.getType());
  118. window.addHandler(maximizeRestoreClickHandler, KeyUpEvent.getType());
  119. window.setOwner(getConnection().getUIConnector().getWidget());
  120. window.addMoveHandler(this);
  121. }
  122. @Override
  123. public void onUnregister() {
  124. LayoutManager lm = getLayoutManager();
  125. VWindow window = getWidget();
  126. lm.unregisterDependency(this, window.contentPanel.getElement());
  127. lm.unregisterDependency(this, window.header);
  128. lm.unregisterDependency(this, window.footer);
  129. }
  130. @Override
  131. public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
  132. VWindow window = getWidget();
  133. String connectorId = getConnectorId();
  134. // Workaround needed for Testing Tools (GWT generates window DOM
  135. // slightly different in different browsers).
  136. window.closeBox.setId(connectorId + "_window_close");
  137. window.maximizeRestoreBox
  138. .setId(connectorId + "_window_maximizerestore");
  139. window.visibilityChangesDisabled = true;
  140. if (!isRealUpdate(uidl)) {
  141. return;
  142. }
  143. window.visibilityChangesDisabled = false;
  144. // we may have actions
  145. for (int i = 0; i < uidl.getChildCount(); i++) {
  146. UIDL childUidl = uidl.getChildUIDL(i);
  147. if (childUidl.getTag().equals("actions")) {
  148. if (window.shortcutHandler == null) {
  149. window.shortcutHandler = new ShortcutActionHandler(
  150. connectorId, client);
  151. }
  152. window.shortcutHandler.updateActionMap(childUidl);
  153. }
  154. }
  155. if (uidl.hasAttribute("bringToFront")) {
  156. /*
  157. * Focus as a side-effect. Will be overridden by
  158. * ApplicationConnection if another component was focused by the
  159. * server side.
  160. */
  161. window.contentPanel.focus();
  162. window.bringToFrontSequence = uidl.getIntAttribute("bringToFront");
  163. VWindow.deferOrdering();
  164. }
  165. }
  166. @Override
  167. public void updateCaption(ComponentConnector component) {
  168. // NOP, window has own caption, layout caption not rendered
  169. }
  170. @Override
  171. public VWindow getWidget() {
  172. return (VWindow) super.getWidget();
  173. }
  174. @Override
  175. public void onConnectorHierarchyChange(
  176. ConnectorHierarchyChangeEvent event) {
  177. // We always have 1 child, unless the child is hidden
  178. getWidget().contentPanel.setWidget(getContentWidget());
  179. if (getParent() == null && windowClone != null) {
  180. // If the window is removed from the UI, add the copy of the
  181. // contents to the window (in case of an 'out-animation')
  182. getWidget().getElement().removeAllChildren();
  183. getWidget().getElement().appendChild(windowClone);
  184. // Clean reference
  185. windowClone = null;
  186. }
  187. }
  188. @Override
  189. public void layout() {
  190. LayoutManager lm = getLayoutManager();
  191. VWindow window = getWidget();
  192. // ensure window is not larger than browser window
  193. if (window.getOffsetWidth() > Window.getClientWidth()) {
  194. window.setWidth(Window.getClientWidth() + "px");
  195. lm.setNeedsMeasure(getContent());
  196. }
  197. if (window.getOffsetHeight() > Window.getClientHeight()) {
  198. window.setHeight(Window.getClientHeight() + "px");
  199. lm.setNeedsMeasure(getContent());
  200. }
  201. ComponentConnector content = getContent();
  202. boolean hasContent = content != null;
  203. Element contentElement = window.contentPanel.getElement();
  204. Style contentStyle = window.contents.getStyle();
  205. int headerHeight = lm.getOuterHeight(window.header);
  206. contentStyle.setPaddingTop(headerHeight, Unit.PX);
  207. contentStyle.setMarginTop(-headerHeight, Unit.PX);
  208. int footerHeight = lm.getOuterHeight(window.footer);
  209. contentStyle.setPaddingBottom(footerHeight, Unit.PX);
  210. contentStyle.setMarginBottom(-footerHeight, Unit.PX);
  211. int minWidth = lm.getOuterWidth(window.header)
  212. - lm.getInnerWidth(window.header);
  213. int minHeight = footerHeight + headerHeight;
  214. getWidget().getElement().getStyle().setPropertyPx("minWidth", minWidth);
  215. getWidget().getElement().getStyle().setPropertyPx("minHeight",
  216. minHeight);
  217. /*
  218. * Must set absolute position if the child has relative height and
  219. * there's a chance of horizontal scrolling as some browsers will
  220. * otherwise not take the scrollbar into account when calculating the
  221. * height.
  222. */
  223. if (hasContent) {
  224. Element layoutElement = content.getWidget().getElement();
  225. Style childStyle = layoutElement.getStyle();
  226. if (content.isRelativeHeight()) {
  227. childStyle.setPosition(Position.ABSOLUTE);
  228. Style wrapperStyle = contentElement.getStyle();
  229. if (window.getElement().getStyle().getWidth().isEmpty()
  230. && !content.isRelativeWidth()) {
  231. /*
  232. * Need to lock width to make undefined width work even with
  233. * absolute positioning
  234. */
  235. int contentWidth = lm.getOuterWidth(layoutElement);
  236. wrapperStyle.setWidth(contentWidth, Unit.PX);
  237. } else {
  238. wrapperStyle.clearWidth();
  239. }
  240. } else {
  241. childStyle.clearPosition();
  242. }
  243. }
  244. }
  245. @Override
  246. public void postLayout() {
  247. VWindow window = getWidget();
  248. if (!window.isAttached()) {
  249. Logger.getLogger(WindowConnector.class.getName())
  250. .warning("Called postLayout to detached Window.");
  251. return;
  252. }
  253. if (window.centered && getState().windowMode != WindowMode.MAXIMIZED) {
  254. window.center();
  255. }
  256. window.positionOrSizeUpdated();
  257. if (getParent() != null) {
  258. // Take a copy of the contents, since the server will detach all
  259. // children of this window when it's closed, and the window will be
  260. // emptied during the following hierarchy update (we need to keep
  261. // the contents visible for the duration of a possible
  262. // 'out-animation')
  263. // Fix for #14645 and #14785 - as soon as we clone audio and video
  264. // tags, they start fetching data, and playing immediately in
  265. // background, in case autoplay attribute is present. Therefore we
  266. // have to replace them with stubs in the clone. And we can't just
  267. // erase them, because there are corresponding player widgets to
  268. // animate
  269. windowClone = cloneNodeFilteringMedia(
  270. getWidget().getElement().getFirstChild());
  271. }
  272. }
  273. private Node cloneNodeFilteringMedia(Node node) {
  274. if (node instanceof Element) {
  275. Element old = (Element) node;
  276. if ("audio".equalsIgnoreCase(old.getTagName())
  277. || "video".equalsIgnoreCase(old.getTagName())) {
  278. if (!old.hasAttribute("controls")
  279. && "audio".equalsIgnoreCase(old.getTagName())) {
  280. // nothing to animate, so we won't add this to
  281. // the clone
  282. return null;
  283. }
  284. Element newEl = DOM.createElement(old.getTagName());
  285. if (old.hasAttribute("controls")) {
  286. newEl.setAttribute("controls",
  287. old.getAttribute("controls"));
  288. }
  289. if (old.hasAttribute("style")) {
  290. newEl.setAttribute("style", old.getAttribute("style"));
  291. }
  292. if (old.hasAttribute("class")) {
  293. newEl.setAttribute("class", old.getAttribute("class"));
  294. }
  295. return newEl;
  296. }
  297. if ("iframe".equalsIgnoreCase(old.getTagName())
  298. && old.hasAttribute("src")
  299. && old.getAttribute("src").contains("APP/connector")) {
  300. // an iframe reloads when reattached to the DOM, but
  301. // unfortunately, when newEl is reattached, server-side
  302. // resource (e.g. generated PDF) is already gone, so this will
  303. // end up with 404, which might be undesirable.
  304. // Instead of the resource that is not available anymore,
  305. // let's just use empty iframe.
  306. // See
  307. // https://github.com/vaadin/framework/issues/11369
  308. // for details of the issue this works around
  309. Element newEl = old.cloneNode(false).cast();
  310. newEl.setAttribute("src", "about:blank");
  311. return newEl;
  312. }
  313. }
  314. Node res = node.cloneNode(false);
  315. if (node.hasChildNodes()) {
  316. NodeList<Node> nl = node.getChildNodes();
  317. for (int i = 0; i < nl.getLength(); i++) {
  318. Node clone = cloneNodeFilteringMedia(nl.getItem(i));
  319. if (clone != null) {
  320. res.appendChild(clone);
  321. }
  322. }
  323. }
  324. return res;
  325. }
  326. @Override
  327. public WindowState getState() {
  328. return (WindowState) super.getState();
  329. }
  330. @Override
  331. public void onStateChanged(StateChangeEvent stateChangeEvent) {
  332. super.onStateChanged(stateChangeEvent);
  333. VWindow window = getWidget();
  334. WindowState state = getState();
  335. if (state.modal != window.vaadinModality) {
  336. window.setVaadinModality(!window.vaadinModality);
  337. }
  338. boolean resizeable = state.resizable
  339. && state.windowMode == WindowMode.NORMAL;
  340. window.setResizable(resizeable);
  341. window.resizeLazy = state.resizeLazy;
  342. window.setDraggable(
  343. state.draggable && state.windowMode == WindowMode.NORMAL);
  344. window.updateMaximizeRestoreClassName(state.resizable,
  345. state.windowMode);
  346. // Caption must be set before required header size is measured. If
  347. // the caption attribute is missing the caption should be cleared.
  348. String iconURL = null;
  349. if (getIconUri() != null) {
  350. iconURL = getIconUri();
  351. }
  352. window.setAssistivePrefix(state.assistivePrefix);
  353. window.setAssistivePostfix(state.assistivePostfix);
  354. window.setCaption(state.caption, iconURL, getState().captionAsHtml);
  355. window.setWaiAriaRole(getState().role);
  356. window.setAssistiveDescription(state.contentDescription);
  357. window.setTabStopEnabled(getState().assistiveTabStop);
  358. window.setTabStopTopAssistiveText(getState().assistiveTabStopTopText);
  359. window.setTabStopBottomAssistiveText(
  360. getState().assistiveTabStopBottomText);
  361. clickEventHandler.handleEventHandlerRegistration();
  362. window.setClosable(state.closable);
  363. // initialize position from state
  364. updateWindowPosition();
  365. // setting scrollposition must happen after children is rendered
  366. window.contentPanel.setScrollPosition(state.scrollTop);
  367. window.contentPanel.setHorizontalScrollPosition(state.scrollLeft);
  368. // Center this window on screen if requested
  369. // This had to be here because we might not know the content size before
  370. // everything is painted into the window
  371. // centered if this is unset on move/resize
  372. window.centered = state.centered;
  373. // Ensure centering before setting visible (#16486)
  374. if (window.centered && getState().windowMode != WindowMode.MAXIMIZED) {
  375. Scheduler.get().scheduleFinally(() -> {
  376. // the window may have got removed again before this is
  377. // triggered, and centering would re-display it
  378. if (getWidget().isShowing()) {
  379. getWidget().center();
  380. }
  381. });
  382. }
  383. window.setVisible(true);
  384. }
  385. // Need to override default because of window mode
  386. @Override
  387. protected void updateComponentSize() {
  388. if (getState().windowMode == WindowMode.NORMAL) {
  389. super.updateComponentSize();
  390. } else if (getState().windowMode == WindowMode.MAXIMIZED) {
  391. super.updateComponentSize("100%", "100%");
  392. }
  393. }
  394. protected void updateWindowPosition() {
  395. VWindow window = getWidget();
  396. WindowState state = getState();
  397. if (state.windowMode == WindowMode.NORMAL) {
  398. // if centered, position handled in postLayout()
  399. if (!state.centered
  400. && (state.positionX >= 0 || state.positionY >= 0)) {
  401. // If both positions are negative, then
  402. // setWindowOrderAndPosition has already taken care of
  403. // positioning the window so it stacks with other windows
  404. window.setPopupPosition(state.positionX, state.positionY);
  405. }
  406. } else if (state.windowMode == WindowMode.MAXIMIZED) {
  407. window.setPopupPositionNoUpdate(0, 0);
  408. }
  409. }
  410. protected void updateWindowMode() {
  411. VWindow window = getWidget();
  412. WindowState state = getState();
  413. // update draggable on widget
  414. window.setDraggable(
  415. state.draggable && state.windowMode == WindowMode.NORMAL);
  416. // update resizable on widget
  417. window.setResizable(
  418. state.resizable && state.windowMode == WindowMode.NORMAL);
  419. updateComponentSize();
  420. updateWindowPosition();
  421. window.updateMaximizeRestoreClassName(state.resizable,
  422. state.windowMode);
  423. window.updateContentsSize();
  424. }
  425. protected void onMaximizeRestore() {
  426. WindowState state = getState();
  427. if (state.resizable) {
  428. if (state.windowMode == WindowMode.MAXIMIZED) {
  429. state.windowMode = WindowMode.NORMAL;
  430. } else {
  431. state.windowMode = WindowMode.MAXIMIZED;
  432. }
  433. updateWindowMode();
  434. VWindow window = getWidget();
  435. window.bringToFront();
  436. getRpcProxy(WindowServerRpc.class)
  437. .windowModeChanged(state.windowMode);
  438. }
  439. }
  440. /**
  441. * Gives the WindowConnector an order number. As a side effect, moves the
  442. * window according to its order number so the windows are stacked. This
  443. * method should be called for each window in the order they should appear.
  444. */
  445. public void setWindowOrderAndPosition() {
  446. getWidget().setWindowOrderAndPosition();
  447. }
  448. @Override
  449. public boolean hasTooltip() {
  450. /*
  451. * Tooltip event handler always needed on the window widget to make sure
  452. * tooltips are properly hidden. (#11448)
  453. */
  454. return true;
  455. }
  456. @Override
  457. public void onWindowMove(WindowMoveEvent event) {
  458. getRpcProxy(WindowServerRpc.class).windowMoved(event.getNewX(),
  459. event.getNewY());
  460. }
  461. private boolean isKeyEnterOrSpace(int keyCode) {
  462. return keyCode == KeyCodes.KEY_ENTER || keyCode == KeyCodes.KEY_SPACE;
  463. }
  464. }