|
15 | 15 | */
|
16 | 16 | package com.vaadin.flow.component.page;
|
17 | 17 |
|
18 |
| -import java.io.BufferedReader; |
19 |
| -import java.io.IOException; |
20 |
| -import java.io.InputStream; |
21 |
| -import java.io.InputStreamReader; |
22 | 18 | import java.io.Serializable;
|
23 | 19 | import java.net.MalformedURLException;
|
24 | 20 | import java.net.URI;
|
25 | 21 | import java.net.URL;
|
26 |
| -import java.nio.charset.StandardCharsets; |
| 22 | +import java.util.ArrayList; |
27 | 23 | import java.util.Arrays;
|
28 | 24 | import java.util.Objects;
|
29 | 25 | import java.util.function.Function;
|
30 | 26 |
|
31 |
| -import com.vaadin.flow.component.ClientCallable; |
32 |
| -import com.vaadin.flow.component.Component; |
33 |
| -import com.vaadin.flow.component.ComponentEvent; |
34 | 27 | import com.vaadin.flow.component.Direction;
|
35 |
| -import com.vaadin.flow.component.Tag; |
36 | 28 | import com.vaadin.flow.component.UI;
|
37 | 29 | import com.vaadin.flow.component.dependency.JavaScript;
|
38 | 30 | import com.vaadin.flow.component.dependency.JsModule;
|
39 | 31 | import com.vaadin.flow.component.dependency.StyleSheet;
|
40 |
| -import com.vaadin.flow.component.internal.AllowInert; |
41 | 32 | import com.vaadin.flow.component.internal.PendingJavaScriptInvocation;
|
42 | 33 | import com.vaadin.flow.component.internal.UIInternals.JavaScriptInvocation;
|
| 34 | +import com.vaadin.flow.dom.DomListenerRegistration; |
43 | 35 | import com.vaadin.flow.dom.Element;
|
44 | 36 | import com.vaadin.flow.function.SerializableConsumer;
|
45 | 37 | import com.vaadin.flow.internal.UrlUtil;
|
46 | 38 | import com.vaadin.flow.shared.Registration;
|
47 | 39 | import com.vaadin.flow.shared.ui.Dependency;
|
48 | 40 | import com.vaadin.flow.shared.ui.Dependency.Type;
|
49 | 41 | import com.vaadin.flow.shared.ui.LoadMode;
|
50 |
| - |
51 | 42 | import elemental.json.JsonObject;
|
52 | 43 | import elemental.json.JsonType;
|
53 | 44 | import elemental.json.JsonValue;
|
|
61 | 52 | */
|
62 | 53 | public class Page implements Serializable {
|
63 | 54 |
|
64 |
| - @Tag(Tag.DIV) |
65 |
| - private static class ResizeEventReceiver extends Component { |
66 |
| - |
67 |
| - private int windowResizeListenersSize; |
68 |
| - |
69 |
| - @ClientCallable |
70 |
| - @AllowInert |
71 |
| - private void windowResized(int width, int height) { |
72 |
| - if (windowResizeListenersSize != 0) { |
73 |
| - fireEvent(new ResizeEvent(this, width, height)); |
74 |
| - } |
75 |
| - } |
76 |
| - |
77 |
| - private Registration addListener(BrowserWindowResizeListener listener) { |
78 |
| - windowResizeListenersSize++; |
79 |
| - Registration registration = addListener(ResizeEvent.class, |
80 |
| - event -> listener |
81 |
| - .browserWindowResized(event.getApiEvent())); |
82 |
| - |
83 |
| - Registration combined = Registration |
84 |
| - .combine(this::listenerIsUnregistered, registration); |
85 |
| - return Registration.once(combined::remove); |
86 |
| - } |
87 |
| - |
88 |
| - private void listenerIsUnregistered() { |
89 |
| - windowResizeListenersSize--; |
90 |
| - if (windowResizeListenersSize == 0) { |
91 |
| - // remove JS listener |
92 |
| - getUI().get().getPage().executeJs("$0.resizeRemove()", this); |
93 |
| - } |
94 |
| - } |
95 |
| - } |
96 |
| - |
97 |
| - private static class ResizeEvent |
98 |
| - extends ComponentEvent<ResizeEventReceiver> { |
99 |
| - |
100 |
| - private final BrowserWindowResizeEvent apiEvent; |
101 |
| - |
102 |
| - private ResizeEvent(ResizeEventReceiver source, int width, int height) { |
103 |
| - super(source, true); |
104 |
| - apiEvent = new BrowserWindowResizeEvent( |
105 |
| - source.getUI().get().getPage(), width, height); |
106 |
| - |
107 |
| - } |
108 |
| - |
109 |
| - private BrowserWindowResizeEvent getApiEvent() { |
110 |
| - return apiEvent; |
111 |
| - } |
112 |
| - } |
113 |
| - |
114 |
| - private ResizeEventReceiver resizeReceiver; |
115 | 55 | private final UI ui;
|
116 | 56 | private final History history;
|
| 57 | + private DomListenerRegistration resizeReceiver; |
| 58 | + private ArrayList<BrowserWindowResizeListener> resizeListeners; |
117 | 59 |
|
118 | 60 | /**
|
119 | 61 | * Creates a page instance for the given UI.
|
@@ -373,17 +315,33 @@ public Registration addBrowserWindowResizeListener(
|
373 | 315 | BrowserWindowResizeListener resizeListener) {
|
374 | 316 | Objects.requireNonNull(resizeListener);
|
375 | 317 | if (resizeReceiver == null) {
|
376 |
| - // lazy creation which is done only one time since there is no way |
377 |
| - // to remove virtual children |
378 |
| - resizeReceiver = new ResizeEventReceiver(); |
379 |
| - ui.getElement().appendVirtualChild(resizeReceiver.getElement()); |
| 318 | + // "republish" on the UI element, so can be listened with core APIs |
| 319 | + ui.getElement().executeJs(""" |
| 320 | + const el = this; |
| 321 | + window.addEventListener('resize', evt => { |
| 322 | + const event = new Event("window-resize"); |
| 323 | + event.w = document.documentElement.clientWidth; |
| 324 | + event.h = document.documentElement.clientHeight; |
| 325 | + el.dispatchEvent(event); |
| 326 | + }); |
| 327 | + """); |
| 328 | + resizeReceiver = ui.getElement() |
| 329 | + .addEventListener("window-resize", e -> { |
| 330 | + var evt = new BrowserWindowResizeEvent(this, |
| 331 | + (int) e.getEventData().getNumber("event.w"), |
| 332 | + (int) e.getEventData().getNumber("event.h")); |
| 333 | + // Clone list to avoid issues if listener unregisters |
| 334 | + // itself |
| 335 | + new ArrayList<>(resizeListeners) |
| 336 | + .forEach(l -> l.browserWindowResized(evt)); |
| 337 | + }).addEventData("event.w").addEventData("event.h") |
| 338 | + .debounce(300).allowInert(); |
380 | 339 | }
|
381 |
| - if (resizeReceiver.windowResizeListenersSize == 0) { |
382 |
| - // JS resize listener may be completely disabled if there are not |
383 |
| - // listeners |
384 |
| - executeJs(LazyJsLoader.WINDOW_LISTENER_JS, resizeReceiver); |
| 340 | + if (resizeListeners == null) { |
| 341 | + resizeListeners = new ArrayList<>(1); |
385 | 342 | }
|
386 |
| - return resizeReceiver.addListener(resizeListener); |
| 343 | + resizeListeners.add(resizeListener); |
| 344 | + return () -> resizeListeners.remove(resizeListener); |
387 | 345 | }
|
388 | 346 |
|
389 | 347 | /**
|
@@ -467,30 +425,6 @@ private void addDependency(Dependency dependency) {
|
467 | 425 | ui.getInternals().getDependencyList().add(dependency);
|
468 | 426 | }
|
469 | 427 |
|
470 |
| - private static class LazyJsLoader implements Serializable { |
471 |
| - |
472 |
| - private static final String JS_FILE_NAME = "windowResizeListener.js"; |
473 |
| - |
474 |
| - private static final String WINDOW_LISTENER_JS = readJS(); |
475 |
| - |
476 |
| - private static String readJS() { |
477 |
| - try (InputStream stream = Page.class |
478 |
| - .getResourceAsStream(JS_FILE_NAME); |
479 |
| - BufferedReader bf = new BufferedReader( |
480 |
| - new InputStreamReader(stream, |
481 |
| - StandardCharsets.UTF_8))) { |
482 |
| - StringBuilder builder = new StringBuilder(); |
483 |
| - bf.lines().forEach(builder::append); |
484 |
| - return builder.toString(); |
485 |
| - } catch (IOException e) { |
486 |
| - throw new RuntimeException( |
487 |
| - "Couldn't read window resize listener JavaScript file " |
488 |
| - + JS_FILE_NAME + ". The package is broken", |
489 |
| - e); |
490 |
| - } |
491 |
| - } |
492 |
| - } |
493 |
| - |
494 | 428 | /**
|
495 | 429 | * Callback for receiving extended client-side details.
|
496 | 430 | */
|
|
0 commit comments