-
-
Notifications
You must be signed in to change notification settings - Fork 391
/
Utils.ts
230 lines (195 loc) · 6.51 KB
/
Utils.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
import { DeviceInterface, MobileDeviceInterface, Platform, platformFromString } from '@standardnotes/snjs'
import { IsDesktopPlatform, IsWebPlatform } from '@/Constants/Version'
import { EMAIL_REGEX } from '../Constants/Constants'
import { MediaQueryBreakpoints } from '@/Hooks/useMediaQuery'
declare const process: {
env: {
NODE_ENV: string | null | undefined
}
}
export const isDev = process.env.NODE_ENV === 'development'
export function getPlatformString() {
try {
const platform = navigator.platform.toLowerCase()
let trimmed = ''
if (platform.includes('mac')) {
trimmed = 'mac'
} else if (platform.includes('win')) {
trimmed = 'windows'
} else if (platform.includes('linux')) {
trimmed = 'linux'
} else {
/** Treat other platforms as linux */
trimmed = 'linux'
}
return trimmed + (isDesktopApplication() ? '-desktop' : '-web')
} catch (e) {
return 'linux-web'
}
}
export function getPlatform(device: DeviceInterface | MobileDeviceInterface): Platform {
if ('platform' in device) {
return device.platform
}
return platformFromString(getPlatformString())
}
export function isSameDay(dateA: Date, dateB: Date): boolean {
return (
dateA.getFullYear() === dateB.getFullYear() &&
dateA.getMonth() === dateB.getMonth() &&
dateA.getDate() === dateB.getDate()
)
}
/** Via https://davidwalsh.name/javascript-debounce-function */
export function debounce(this: any, func: any, wait: number, immediate = false) {
let timeout: NodeJS.Timeout | null
return () => {
// eslint-disable-next-line @typescript-eslint/no-this-alias, no-invalid-this
const context = this
// eslint-disable-next-line prefer-rest-params
const args = arguments
const later = function () {
timeout = null
if (!immediate) {
func.apply(context, args)
}
}
const callNow = immediate && !timeout
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(later, wait)
if (callNow) {
func.apply(context, args)
}
}
}
// https://tc39.github.io/ecma262/#sec-array.prototype.includes
if (!Array.prototype.includes) {
// eslint-disable-next-line no-extend-native
Object.defineProperty(Array.prototype, 'includes', {
value: function (searchElement: any, fromIndex: number) {
if (this == null) {
throw new TypeError('"this" is null or not defined')
}
// 1. Let O be ? ToObject(this value).
const o = Object(this)
// 2. Let len be ? ToLength(? Get(O, "length")).
const len = o.length >>> 0
// 3. If len is 0, return false.
if (len === 0) {
return false
}
// 4. Let n be ? ToInteger(fromIndex).
// (If fromIndex is undefined, this step produces the value 0.)
const n = fromIndex | 0
// 5. If n ≥ 0, then
// a. Let k be n.
// 6. Else n < 0,
// a. Let k be len + n.
// b. If k < 0, let k be 0.
let k = Math.max(n >= 0 ? n : len - Math.abs(n), 0)
function sameValueZero(x: number, y: number) {
return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y))
}
// 7. Repeat, while k < len
while (k < len) {
// a. Let elementK be the result of ? Get(O, ! ToString(k)).
// b. If SameValueZero(searchElement, elementK) is true, return true.
if (sameValueZero(o[k], searchElement)) {
return true
}
// c. Increase k by 1.
k++
}
// 8. Return false
return false
},
})
}
export async function preventRefreshing(message: string, operation: () => Promise<void> | void) {
const onBeforeUnload = window.onbeforeunload
try {
window.onbeforeunload = () => message
await operation()
} finally {
window.onbeforeunload = onBeforeUnload
}
}
if (!IsWebPlatform && !IsDesktopPlatform) {
throw Error('Neither __WEB__ nor __DESKTOP__ is true. Check your configuration files.')
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function destroyAllObjectProperties(object: any): void {
for (const prop of Object.getOwnPropertyNames(object)) {
try {
delete object[prop]
// eslint-disable-next-line no-empty
} catch (error) {}
}
}
export function isDesktopApplication() {
return IsDesktopPlatform
}
export function getDesktopVersion() {
return window.electronAppVersion
}
export const isEmailValid = (email: string): boolean => {
return EMAIL_REGEX.test(email)
}
export const openInNewTab = (url: string) => {
const newWindow = window.open(url, '_blank', 'noopener,noreferrer')
if (newWindow) {
newWindow.opener = null
}
}
export const convertStringifiedBooleanToBoolean = (value: string) => {
return value !== 'false'
}
// https://stackoverflow.com/questions/9038625/detect-if-device-is-ios/9039885#9039885
export const isIOS = () =>
(/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) ||
(navigator.userAgent.includes('Mac') && 'ontouchend' in document && navigator.maxTouchPoints > 1) ||
window.platform === Platform.Ios
export const isAndroid = () => navigator.userAgent.toLowerCase().includes('android')
// https://stackoverflow.com/a/57527009/2504429
export const disableIosTextFieldZoom = () => {
const addMaximumScaleToMetaViewport = () => {
const viewportMetaElement = document.querySelector('meta[name=viewport]')
if (viewportMetaElement !== null) {
let content = viewportMetaElement.getAttribute('content')
if (!content) {
return
}
const maximumScaleRegex = /maximum-scale=[0-9.]+/g
if (maximumScaleRegex.test(content)) {
content = content.replace(maximumScaleRegex, 'maximum-scale=1.0')
} else {
content = [content, 'maximum-scale=1.0'].join(', ')
}
viewportMetaElement.setAttribute('content', content)
}
}
if (isIOS()) {
addMaximumScaleToMetaViewport()
}
}
export const isMobileScreen = () => window.matchMedia(MediaQueryBreakpoints.sm).matches
export const isTabletScreen = () =>
!isMobileScreen() &&
window.matchMedia(MediaQueryBreakpoints.md).matches &&
!window.matchMedia(MediaQueryBreakpoints.lg).matches
export const isTabletOrMobileScreen = () => isMobileScreen() || isTabletScreen()
export const getBase64FromBlob = (blob: Blob) => {
return new Promise<string>((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => {
if (reader.result) {
resolve(reader.result.toString())
} else {
reject()
}
}
reader.readAsDataURL(blob)
})
}