@@ -21,23 +21,20 @@ import {MediaChange} from '../media-change';
21
21
*/
22
22
@Injectable ( { providedIn : 'root' } )
23
23
export class MatchMedia {
24
- protected _registry : Map < string , MediaQueryList > ;
25
- protected _source : BehaviorSubject < MediaChange > ;
26
- protected _observable$ : Observable < MediaChange > ;
24
+ protected _registry = new Map < string , MediaQueryList > ( ) ;
25
+ protected _source = new BehaviorSubject < MediaChange > ( new MediaChange ( true ) ) ;
26
+ protected _observable$ = this . _source . asObservable ( ) ;
27
27
28
28
constructor ( protected _zone : NgZone ,
29
29
@Inject ( PLATFORM_ID ) protected _platformId : Object ,
30
30
@Inject ( DOCUMENT ) protected _document : any ) {
31
- this . _registry = new Map < string , MediaQueryList > ( ) ;
32
- this . _source = new BehaviorSubject < MediaChange > ( new MediaChange ( true ) ) ;
33
- this . _observable$ = this . _source . asObservable ( ) ;
34
31
}
35
32
36
33
/**
37
34
* For the specified mediaQuery?
38
35
*/
39
36
isActive ( mediaQuery : string ) : boolean {
40
- let mql = this . _registry . get ( mediaQuery ) ;
37
+ const mql = this . _registry . get ( mediaQuery ) ;
41
38
return ! ! mql ? mql . matches : false ;
42
39
}
43
40
@@ -55,9 +52,7 @@ export class MatchMedia {
55
52
}
56
53
57
54
return this . _observable$ . pipe (
58
- filter ( ( change : MediaChange ) => {
59
- return mediaQuery ? ( change . mediaQuery === mediaQuery ) : true ;
60
- } )
55
+ filter ( change => ( mediaQuery ? ( change . mediaQuery === mediaQuery ) : true ) )
61
56
) ;
62
57
}
63
58
@@ -66,111 +61,93 @@ export class MatchMedia {
66
61
* mediaQuery. Each listener emits specific MediaChange data to observers
67
62
*/
68
63
registerQuery ( mediaQuery : string | string [ ] ) {
69
- let list = normalizeQuery ( mediaQuery ) ;
64
+ const list = Array . isArray ( mediaQuery ) ? Array . from ( new Set ( mediaQuery ) ) : [ mediaQuery ] ;
70
65
71
66
if ( list . length > 0 ) {
72
- this . _prepareQueryCSS ( list , this . _document ) ;
73
-
74
- list . forEach ( query => {
75
- let mql = this . _registry . get ( query ) ;
76
- let onMQLEvent = ( e : MediaQueryListEvent ) => {
77
- this . _zone . run ( ( ) => {
78
- let change = new MediaChange ( e . matches , query ) ;
79
- this . _source . next ( change ) ;
80
- } ) ;
81
- } ;
82
-
83
- if ( ! mql ) {
84
- mql = this . _buildMQL ( query ) ;
85
- mql . addListener ( onMQLEvent ) ;
86
- this . _registry . set ( query , mql ) ;
87
- }
88
-
89
- if ( mql . matches ) {
90
- onMQLEvent ( mql as unknown as MediaQueryListEvent ) ;
91
- }
92
- } ) ;
67
+ buildQueryCss ( list , this . _document ) ;
93
68
}
69
+
70
+ list . forEach ( query => {
71
+ const onMQLEvent = ( e : MediaQueryListEvent ) => {
72
+ this . _zone . run ( ( ) => this . _source . next ( new MediaChange ( e . matches , query ) ) ) ;
73
+ } ;
74
+
75
+ let mql = this . _registry . get ( query ) ;
76
+
77
+ if ( ! mql ) {
78
+ mql = this . _buildMQL ( query ) ;
79
+ mql . addListener ( onMQLEvent ) ;
80
+ this . _registry . set ( query , mql ) ;
81
+ }
82
+
83
+ if ( mql . matches ) {
84
+ onMQLEvent ( mql as unknown as MediaQueryListEvent ) ;
85
+ }
86
+ } ) ;
94
87
}
95
88
96
89
/**
97
90
* Call window.matchMedia() to build a MediaQueryList; which
98
91
* supports 0..n listeners for activation/deactivation
99
92
*/
100
93
protected _buildMQL ( query : string ) : MediaQueryList {
101
- let canListen = isPlatformBrowser ( this . _platformId ) &&
102
- ! ! ( < any > window ) . matchMedia ( 'all' ) . addListener ;
103
-
104
- return canListen ? ( < any > window ) . matchMedia ( query ) : {
105
- matches : query === 'all' || query === '' ,
106
- media : query ,
107
- addListener : ( ) => {
108
- } ,
109
- removeListener : ( ) => {
110
- }
111
- } as unknown as MediaQueryList ;
94
+ return constructMql ( query , isPlatformBrowser ( this . _platformId ) ) ;
112
95
}
96
+ }
113
97
114
- /**
115
- * For Webkit engines that only trigger the MediaQueryList Listener
116
- * when there is at least one CSS selector for the respective media query.
117
- *
118
- * @param mediaQueries
119
- * @param _document
120
- */
121
- protected _prepareQueryCSS ( mediaQueries : string [ ] , _document : Document ) {
122
- const list : string [ ] = mediaQueries . filter ( it => ! ALL_STYLES [ it ] ) ;
123
- if ( list . length > 0 ) {
124
- const query = list . join ( ', ' ) ;
98
+ /**
99
+ * Private global registry for all dynamically-created, injected style tags
100
+ * @see prepare(query)
101
+ */
102
+ const ALL_STYLES : { [ key : string ] : any } = { } ;
103
+
104
+ /**
105
+ * For Webkit engines that only trigger the MediaQueryList Listener
106
+ * when there is at least one CSS selector for the respective media query.
107
+ *
108
+ * @param mediaQueries
109
+ * @param _document
110
+ */
111
+ function buildQueryCss ( mediaQueries : string [ ] , _document : Document ) {
112
+ const list = mediaQueries . filter ( it => ! ALL_STYLES [ it ] ) ;
113
+ if ( list . length > 0 ) {
114
+ const query = list . join ( ', ' ) ;
125
115
126
- try {
127
- let styleEl = _document . createElement ( 'style' ) ;
116
+ try {
117
+ const styleEl = _document . createElement ( 'style' ) ;
128
118
129
- styleEl . setAttribute ( 'type' , 'text/css' ) ;
130
- if ( ! ( styleEl as any ) . styleSheet ) {
131
- let cssText = `
119
+ styleEl . setAttribute ( 'type' , 'text/css' ) ;
120
+ if ( ! ( styleEl as any ) . styleSheet ) {
121
+ const cssText = `
132
122
/*
133
123
@angular/flex-layout - workaround for possible browser quirk with mediaQuery listeners
134
124
see http://bit.ly/2sd4HMP
135
125
*/
136
126
@media ${ query } {.fx-query-test{ }}
137
127
` ;
138
- styleEl . appendChild ( _document . createTextNode ( cssText ) ) ;
139
- }
128
+ styleEl . appendChild ( _document . createTextNode ( cssText ) ) ;
129
+ }
140
130
141
- _document . head ! . appendChild ( styleEl ) ;
131
+ _document . head ! . appendChild ( styleEl ) ;
142
132
143
- // Store in private global registry
144
- list . forEach ( mq => ALL_STYLES [ mq ] = styleEl ) ;
133
+ // Store in private global registry
134
+ list . forEach ( mq => ALL_STYLES [ mq ] = styleEl ) ;
145
135
146
- } catch ( e ) {
147
- console . error ( e ) ;
148
- }
136
+ } catch ( e ) {
137
+ console . error ( e ) ;
149
138
}
150
139
}
151
140
}
152
141
153
- /**
154
- * Private global registry for all dynamically-created, injected style tags
155
- * @see prepare(query)
156
- */
157
- const ALL_STYLES : { [ key : string ] : any } = { } ;
158
-
159
- /**
160
- * Always convert to unique list of queries; for iteration in ::registerQuery()
161
- */
162
- function normalizeQuery ( mediaQuery : string | string [ ] ) : string [ ] {
163
- return ( typeof mediaQuery === 'undefined' ) ? [ ] :
164
- ( typeof mediaQuery === 'string' ) ? [ mediaQuery ] : unique ( mediaQuery as string [ ] ) ;
165
- }
142
+ function constructMql ( query : string , isBrowser : boolean ) : MediaQueryList {
143
+ const canListen = isBrowser && ! ! ( < any > window ) . matchMedia ( 'all' ) . addListener ;
166
144
167
- /**
168
- * Filter duplicate mediaQueries in the list
169
- */
170
- function unique ( list : string [ ] ) : string [ ] {
171
- let seen : { [ key : string ] : boolean } = { } ;
172
- return list . filter ( item => {
173
- return seen . hasOwnProperty ( item ) ? false : ( seen [ item ] = true ) ;
174
- } ) ;
145
+ return canListen ? ( < any > window ) . matchMedia ( query ) : {
146
+ matches : query === 'all' || query === '' ,
147
+ media : query ,
148
+ addListener : ( ) => {
149
+ } ,
150
+ removeListener : ( ) => {
151
+ }
152
+ } as unknown as MediaQueryList ;
175
153
}
176
-
0 commit comments