• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SAP / ui5-webcomponents-react / 12299560009

12 Dec 2024 03:28PM CUT coverage: 87.137%. Remained the same
12299560009

Pull #6741

github

web-flow
Merge 59c89b302 into 243ba13a6
Pull Request #6741: docs(Toolbar): outline how to open popovers

2921 of 3885 branches covered (75.19%)

5108 of 5862 relevant lines covered (87.14%)

51344.4 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

59.57
/packages/base/src/Device/index.ts
1
import { supportsTouch } from '@ui5/webcomponents-base/dist/Device.js';
2
import type { IOrientation, IWindowSize } from './EventProvider.js';
3
import { OrientationEventProvider, ResizeEventProvider } from './EventProvider.js';
4

5
const isSSR = () => typeof window === 'undefined';
445✔
6

7
const getActualWindowSize = (): [width: number, height: number] => {
427✔
8
  if (isSSR()) {
445!
9
    return [0, 0];
×
10
  }
11
  return [window.innerWidth, window.innerHeight];
445✔
12
};
13

14
let iResizeTimeout;
15
let bOrientationChange = false;
427✔
16
let bResize = false;
427✔
17
let iOrientationTimeout;
18
let iClearFlagTimeout;
19
let [iWindowWidthOld, iWindowHeightOld] = getActualWindowSize();
427✔
20
const rInputTagRegex = /INPUT|TEXTAREA|SELECT/;
427✔
21

22
const internalWindowSize: IWindowSize = {
427✔
23
  height: 0,
24
  width: 0
25
};
26

27
const internalOrientation: IOrientation = {
427✔
28
  landscape: false,
29
  portrait: false
30
};
31

32
// PRIVATE API
33

34
const isLandscape = () => {
427✔
35
  return !!window.matchMedia('(orientation: landscape)').matches;
23✔
36
};
37

38
const setResizeInfo = () => {
427✔
39
  internalWindowSize.width = getActualWindowSize()[0];
9✔
40
  internalWindowSize.height = getActualWindowSize()[1];
9✔
41
};
42

43
const setOrientationInfo = () => {
427✔
44
  internalOrientation.landscape = isLandscape();
11✔
45
  internalOrientation.portrait = !internalOrientation.landscape;
11✔
46
};
47

48
const clearFlags = () => {
427✔
49
  bOrientationChange = false;
×
50
  bResize = false;
×
51
  iClearFlagTimeout = null;
×
52
};
53

54
let eventListenersInitialized = false;
427✔
55
const initEventListeners = () => {
427✔
56
  // Add handler for orientationchange and resize after initialization of Device API
57
  if (supportsTouch()) {
3!
58
    // logic for mobile devices which support orientationchange (like ios, android)
59
    window.addEventListener('resize', handleMobileOrientationResizeChange, false);
×
60
    window.addEventListener('orientationchange', handleMobileOrientationResizeChange, false);
×
61
  } else {
62
    // desktop browsers and windows phone/tablet which not support orientationchange
63
    window.addEventListener('resize', handleResizeEvent, false);
3✔
64
  }
65
  setResizeInfo();
3✔
66
  setOrientationInfo();
3✔
67
  eventListenersInitialized = true;
3✔
68
};
69

70
// orientation change
71
const handleOrientationChange = () => {
427✔
72
  setOrientationInfo();
8✔
73
  OrientationEventProvider.fireEvent('orientation', {
8✔
74
    landscape: internalOrientation.landscape,
75
    portrait: internalOrientation.portrait
76
  });
77
};
78

79
const handleMobileTimeout = () => {
427✔
80
  // with ios split view, the browser fires only resize event and no orientationchange
81
  // when changing the size of a split view
82
  // therefore the following if needs to be adapted with additional check of iPad with version greater or equal 9
83
  // (splitview was introduced with iOS 9)
84
  if (bResize && bOrientationChange) {
×
85
    handleOrientationChange();
×
86
    handleResizeChange();
×
87
    bOrientationChange = false;
×
88
    bResize = false;
×
89
    if (iClearFlagTimeout) {
×
90
      window.clearTimeout(iClearFlagTimeout);
×
91
      iClearFlagTimeout = null;
×
92
    }
93
  }
94
  iOrientationTimeout = null;
×
95
};
96

97
const handleMobileOrientationResizeChange = (evt) => {
427✔
98
  if (evt.type === 'resize') {
×
99
    // @ts-expect-error: undefined is fine here
100
    if (rInputTagRegex.test(document.activeElement?.tagName) && !bOrientationChange) {
×
101
      return;
×
102
    }
103

104
    const [iWindowWidthNew, iWindowHeightNew] = getActualWindowSize();
×
105
    // skip multiple resize events by only one orientationchange
106
    if (iWindowHeightNew === iWindowHeightOld && iWindowWidthNew === iWindowWidthOld) {
×
107
      return;
×
108
    }
109
    bResize = true;
×
110
    // on mobile devices opening the keyboard on some devices leads to a resize event
111
    // in this case only the height changes, not the width
112
    if (iWindowHeightOld !== iWindowHeightNew && iWindowWidthOld === iWindowWidthNew) {
×
113
      handleResizeChange();
×
114
    } else {
115
      iWindowWidthOld = iWindowWidthNew;
×
116
    }
117
    iWindowHeightOld = iWindowHeightNew;
×
118

119
    if (iClearFlagTimeout) {
×
120
      window.clearTimeout(iClearFlagTimeout);
×
121
      iClearFlagTimeout = null;
×
122
    }
123
    // Some Android build-in browser fires a resize event after the viewport is applied.
124
    // This resize event has to be dismissed otherwise when the next orientationchange event happens,
125
    // a UI5 resize event will be fired with the wrong window size.
126
    iClearFlagTimeout = window.setTimeout(clearFlags, 1200);
×
127
  } else if (evt.type === 'orientationchange') {
×
128
    bOrientationChange = true;
×
129
  }
130

131
  if (iOrientationTimeout) {
×
132
    clearTimeout(iOrientationTimeout);
×
133
    iOrientationTimeout = null;
×
134
  }
135
  iOrientationTimeout = window.setTimeout(handleMobileTimeout, 50);
×
136
};
137

138
// RESIZE ONLY WITHOUT ORIENTATION CHANGE
139
const handleResizeChange = () => {
427✔
140
  setResizeInfo();
6✔
141
  ResizeEventProvider.fireEvent('resize', {
6✔
142
    height: internalWindowSize.height,
143
    width: internalWindowSize.width
144
  });
145
};
146

147
const handleResizeTimeout = () => {
427✔
148
  handleResizeChange();
6✔
149
  iResizeTimeout = null;
6✔
150
};
151

152
const handleResizeEvent = () => {
427✔
153
  const wasL = internalOrientation.landscape;
12✔
154
  const isL = isLandscape();
12✔
155
  if (wasL !== isL) {
12✔
156
    handleOrientationChange();
8✔
157
  }
158
  // throttle resize events because most browsers throw one or more resize events per pixel
159
  // for every resize event inside the period from 150ms (starting from the first resize event),
160
  // we only fire one resize event after this period
161
  if (!iResizeTimeout) {
12✔
162
    iResizeTimeout = window.setTimeout(handleResizeTimeout, 150);
7✔
163
  }
164
};
165

166
// re-export everything from the web components device
167
export * from '@ui5/webcomponents-base/dist/Device.js';
168
// export all media methods
169
export { attachMediaHandler, detachMediaHandler, getCurrentRange } from './Media.js';
170

171
// resize events
172
export const attachResizeHandler = (fnFunction: (windowSize: IWindowSize) => void): void => {
427✔
173
  if (!eventListenersInitialized) {
3✔
174
    initEventListeners();
3✔
175
  }
176
  ResizeEventProvider.attachEvent('resize', fnFunction);
3✔
177
};
178

179
export const detachResizeHandler = (fnFunction: (windowSize: IWindowSize) => void) => {
427✔
180
  ResizeEventProvider.detachEvent('resize', fnFunction);
3✔
181
};
182

183
// orientation change events
184
export const getOrientation = (): IOrientation => {
427✔
185
  return internalOrientation;
×
186
};
187

188
export const attachOrientationChangeHandler = (fnFunction: (orientation: IOrientation) => void): void => {
427✔
189
  if (!eventListenersInitialized) {
2!
190
    initEventListeners();
×
191
  }
192
  OrientationEventProvider.attachEvent('orientation', fnFunction);
2✔
193
};
194

195
export const detachOrientationChangeHandler = (fnFunction: (orientation: IOrientation) => void) => {
427✔
196
  OrientationEventProvider.detachEvent('orientation', fnFunction);
2✔
197
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc