-
Notifications
You must be signed in to change notification settings - Fork 1
/
bom.ts
98 lines (93 loc) · 2.67 KB
/
bom.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import * as is from '../is/is';
/**
* Acts just like a regular window resize but fixes resize thrashing that
* happens on mobile during scrolling.
*
* The issue is that on mobile, there is that browser URL bar. As the user
* scrolls, the url bar scrolls way with it, increasing the viewport
* height. The window fires the resize event (since it is a different size).
*
* This causes a situation where, as the user scrolls through a page on
* mobile, resize events are unnecessarily called if you only care
* about the "width" changing.
*
* The method creates a listener on the window resize except it retains
* memory of the last browser width. If the browser width hasn't
* changed, it will cull/cut off that event.
*
* ```ts
* let done = bom.smartResize(()=> {
* console.log('window resize but called when user scrolls on mobile')
* }, { passive: true});
*
*
* // Call later to remove listener.
* done();
*
* ```
*
*
* This isn't applied on non-mobile browsers.
* @param {Function} callback
* @param {Object} options The resize options such as passive: true
* @return {Function} A function that which when called, will automatically
* remove that attached listener from the window.
*/
export function smartResize(callback: Function, options: Object): Function {
let width = 0;
const handler: EventListener = e => {
const currentWidth = window.innerWidth;
const allowCallback = !is.mobile() || width !== currentWidth;
if (allowCallback) {
callback(e);
width = currentWidth;
}
};
window.addEventListener('resize', handler, options);
return () => {
window.removeEventListener('resize', handler);
};
}
/**
* Returns a promise that resolves after the given amount of time.
*/
export function sleep(durationMs: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, durationMs));
}
/**
* Checks the current browser and appends a css class name to the element.
*
* ```
* // Now this element would receive a class name of the current browser such
* // as 'safari', 'ios'
* bom.appendBrowserNameToElement(element);
* ```
* @param element
*/
export function appendBrowserNameToElement(element: HTMLElement) {
const checks: {[key: string]: Function} = {
ieOrEdge: is.ieOrEdge,
edge: is.edge,
ie: is.ie,
mobile: is.mobile,
safari: is.safari,
chrome: is.chrome,
chromeOs: is.chrome,
firefox: is.firefox,
ios: is.ios,
ipad: is.ipad,
android: is.android,
};
for (const key in checks) {
if (checks[key]()) {
element.classList.add(key);
}
}
}
/**
* Degu BOM (browser object model) function
*/
export const bom = {
smartResize,
appendBrowserNameToElement,
};