@@ -16,31 +16,107 @@ if ( typeof window !== "undefined" ) {
16
16
document . addEventListener ( "test" , null , { get passive ( ) { supportsPassive = true } } ) ;
17
17
} catch ( e ) { }
18
18
19
- const userAgent = window . navigator . userAgent . toLowerCase ( ) ;
20
- const mobileKeywords = [
21
- 'android' ,
22
- 'iphone' ,
23
- 'ipad' ,
24
- 'ipod' ,
25
- 'webos' ,
26
- 'blackberry' ,
27
- 'windows phone' ,
28
- 'opera mini' ,
29
- 'mobile' ,
30
- 'tablet'
31
- ] ;
32
-
33
- const _isTablet = / ( i p a d | t a b l e t | ( a n d r o i d (? ! .* m o b i l e ) ) | ( w i n d o w s (? ! .* p h o n e ) ( .* t o u c h ) ) | k i n d l e | p l a y b o o k | s i l k | ( p u f f i n (? ! .* ( I P | A P | W P ) ) ) ) / . test ( userAgent ) ;
34
- const _isMobile = mobileKeywords . some ( keyword => userAgent . includes ( keyword ) ) ;
35
- const _isAndroid = [ 'android' ] . some ( keyword => userAgent . includes ( keyword ) ) ;
19
+ const detectDeviceType = ( ) => {
20
+ // 1. First check if window and navigator are available (SSR compatibility)
21
+ if ( typeof window === 'undefined' || ! navigator ) {
22
+ return 'desktop' ; // Default to desktop
23
+ }
36
24
25
+ // 2. Get user agent string
26
+ const ua = navigator . userAgent . toLowerCase ( ) ;
27
+
28
+ // 3. Get platform info
29
+ const platform = navigator . platform . toLowerCase ( ) ;
30
+
31
+ // 4. Check screen characteristics using window.matchMedia
32
+ const isTouch = ( 'ontouchstart' in window ) || navigator . maxTouchPoints > 0 ;
33
+
34
+ const isPortrait = window . matchMedia ( '(orientation: portrait)' ) . matches ;
35
+ const isLandscape = window . matchMedia ( '(orientation: landscape)' ) . matches ;
36
+
37
+ // 5. Get screen dimensions
38
+ const screenWidth = window . screen . width ;
39
+ const screenHeight = window . screen . height ;
40
+ const minScreenSize = Math . min ( screenWidth , screenHeight ) ;
41
+ const maxScreenSize = Math . max ( screenWidth , screenHeight ) ;
42
+
43
+ // Define device characteristics
44
+ const isTablet = (
45
+ // Traditional UA detection
46
+ / i p a d / . test ( ua ) ||
47
+ ( / a n d r o i d / . test ( ua ) && ! / m o b i l e / . test ( ua ) ) ||
48
+ / t a b l e t / . test ( ua ) ||
49
+ / p l a y b o o k / . test ( ua ) ||
50
+ / n e x u s ( 7 | 9 | 1 0 ) / . test ( ua ) ||
51
+ / s m - t / . test ( ua ) ||
52
+ / h u a w e i ( .* ) m e d i a p a d / . test ( ua ) ||
53
+
54
+ // Special detection for iPad Pro and newer iPads
55
+ ( navigator . platform === 'MacIntel' && navigator . maxTouchPoints > 1 ) ||
56
+
57
+ // Screen size characteristics (tablets typically fall within this range)
58
+ ( minScreenSize >= 600 && maxScreenSize <= 1366 && isTouch ) ||
59
+
60
+ // Specific device detection
61
+ / k i n d l e | s i l k | k f t t | k f o t | k f j w a | k f j w i | k f s o w i | k f t h w a | k f t h w i | k f a p w a | k f a p w i / i. test ( ua )
62
+ ) ;
63
+
64
+ const isMobile = (
65
+ ! isTablet && ( // Prevent tablets from being detected as phones
66
+ // Traditional mobile device detection
67
+ / i p h o n e | i p o d | a n d r o i d .* m o b i l e | w i n d o w s p h o n e | m o b i / . test ( ua ) ||
68
+
69
+ // Screen size characteristics (phones typically smaller than 600px)
70
+ ( minScreenSize < 600 && isTouch ) ||
71
+
72
+ // Additional mobile device detection
73
+ / b l a c k b e r r y | \b b b \d + | m e e g o | w e b o s | p a l m | p h o n e | p o c k e t | m o b i l e | m i n i | i e m o b i l e / i. test ( ua )
74
+ )
75
+ ) ;
76
+
77
+ // 6. Comprehensive decision logic
78
+ if ( isMobile ) {
79
+ // Additional check for small tablets
80
+ if ( maxScreenSize >= 1024 && isTouch ) {
81
+ return 'tablet' ;
82
+ }
83
+ return 'mobile' ;
84
+ }
85
+
86
+ if ( isTablet ) {
87
+ // Additional check for touch-enabled laptops
88
+ if ( maxScreenSize > 1366 && / w i n d o w s / . test ( ua ) ) {
89
+ return 'desktop' ;
90
+ }
91
+ return 'tablet' ;
92
+ }
93
+
94
+ // 7. Check for touch-enabled laptops
95
+ if ( isTouch && / w i n d o w s / . test ( ua ) && maxScreenSize > 1366 ) {
96
+ return 'desktop' ;
97
+ }
98
+
99
+ return 'desktop' ;
100
+ } ;
101
+
102
+ const _ua = navigator . userAgent . toLowerCase ( ) ;
103
+ const _vendor = navigator . vendor . toLowerCase ( ) ;
104
+ const _isSafari = (
105
+ / s a f a r i / . test ( _ua ) &&
106
+ / a p p l e c o m p u t e r / . test ( _vendor ) &&
107
+ ! / c h r o m e / . test ( _ua ) &&
108
+ ! / c h r o m i u m / . test ( _ua ) &&
109
+ ! / a n d r o i d / . test ( _ua )
110
+ ) ;
111
+
112
+ const _isAndroid = / a n d r o i d / . test ( _ua ) ;
37
113
38
114
browser = {
39
- isTablet : _isTablet ,
40
- isMobile : _isMobile ,
115
+ isTablet : detectDeviceType ( ) === 'tablet' ,
116
+ isMobile : detectDeviceType ( ) === 'mobile' ,
41
117
isAndroid : _isAndroid ,
42
- isPC : ! _isTablet && ! _isMobile ,
43
- isSafari : ! ! navigator . userAgent . match ( / V e r s i o n \/ [ \d \. ] + . * S a f a r i / ) , /*Test to 9, 10. */
118
+ isPC : detectDeviceType ( ) === 'desktop' ,
119
+ isSafari : _isSafari ,
44
120
isIE : ! ! window . ActiveXObject || "ActiveXObject" in window , /*Test to 6 ~ 11 (not edge) */
45
121
supportsPassive : supportsPassive
46
122
} ;
0 commit comments