@@ -76,56 +76,59 @@ export class MatchMedia {
76
76
observe ( mediaQuery ?: string ) : Observable < MediaChange > {
77
77
this . registerQuery ( mediaQuery ) ;
78
78
79
- return this . _observable$ . filter ( ( change : MediaChange ) => {
80
- return mediaQuery ? ( change . mediaQuery === mediaQuery ) : true ;
81
- } ) ;
79
+ return this . _observable$
80
+ . filter ( ( change : MediaChange ) => {
81
+ return mediaQuery ? ( change . mediaQuery === mediaQuery ) : true ;
82
+ } ) ;
82
83
}
83
84
84
85
/**
85
86
* Based on the BreakPointRegistry provider, register internal listeners for each unique
86
87
* mediaQuery. Each listener emits specific MediaChange data to observers
87
88
*/
88
- registerQuery ( mediaQuery : string ) {
89
- if ( mediaQuery ) {
90
- let mql = this . _registry . get ( mediaQuery ) ;
91
- let onMQLEvent = ( e : MediaQueryList ) => {
92
- this . _zone . run ( ( ) => {
93
- let change = new MediaChange ( e . matches , mediaQuery ) ;
94
- this . _source . next ( change ) ;
95
- } ) ;
96
- } ;
89
+ registerQuery ( mediaQuery : string | Array < string > ) {
90
+ let list = normalizeQuery ( mediaQuery ) ;
91
+
92
+ if ( list . length > 0 ) {
93
+ prepareQueryCSS ( list ) ;
94
+
95
+ list . forEach ( query => {
96
+ let mql = this . _registry . get ( query ) ;
97
+ let onMQLEvent = ( e : MediaQueryList ) => {
98
+ this . _zone . run ( ( ) => {
99
+ let change = new MediaChange ( e . matches , query ) ;
100
+ this . _source . next ( change ) ;
101
+ } ) ;
102
+ } ;
97
103
98
- if ( ! mql ) {
99
- mql = this . _buildMQL ( mediaQuery ) ;
100
- mql . addListener ( onMQLEvent ) ;
101
- this . _registry . set ( mediaQuery , mql ) ;
102
- }
104
+ if ( ! mql ) {
105
+ mql = this . _buildMQL ( query ) ;
106
+ mql . addListener ( onMQLEvent ) ;
107
+ this . _registry . set ( query , mql ) ;
108
+ }
103
109
104
- if ( mql . matches ) {
105
- onMQLEvent ( mql ) ; // Announce activate range for initial subscribers
106
- }
110
+ if ( mql . matches ) {
111
+ onMQLEvent ( mql ) ; // Announce activate range for initial subscribers
112
+ }
113
+ } ) ;
107
114
}
108
-
109
115
}
110
116
111
117
/**
112
118
* Call window.matchMedia() to build a MediaQueryList; which
113
119
* supports 0..n listeners for activation/deactivation
114
120
*/
115
121
protected _buildMQL ( query : string ) : MediaQueryList {
116
- prepareQueryCSS ( query ) ;
117
-
118
122
let canListen = ! ! ( < any > window ) . matchMedia ( 'all' ) . addListener ;
119
123
return canListen ? ( < any > window ) . matchMedia ( query ) : < MediaQueryList > {
120
- matches : query === 'all' || query === '' ,
121
- media : query ,
122
- addListener : ( ) => {
123
- } ,
124
- removeListener : ( ) => {
125
- }
126
- } ;
124
+ matches : query === 'all' || query === '' ,
125
+ media : query ,
126
+ addListener : ( ) => {
127
+ } ,
128
+ removeListener : ( ) => {
129
+ }
130
+ } ;
127
131
}
128
-
129
132
}
130
133
131
134
/**
@@ -135,31 +138,55 @@ export class MatchMedia {
135
138
const ALL_STYLES = { } ;
136
139
137
140
/**
138
- * For Webkit engines that only trigger the MediaQueryListListener
141
+ * For Webkit engines that only trigger the MediaQueryList Listener
139
142
* when there is at least one CSS selector for the respective media query.
140
143
*
141
144
* @param query string The mediaQuery used to create a faux CSS selector
142
145
*
143
146
*/
144
- function prepareQueryCSS ( query ) {
145
- if ( ! ALL_STYLES [ query ] ) {
147
+ function prepareQueryCSS ( mediaQueries : Array < string > ) {
148
+ let list = mediaQueries . filter ( it => ! ALL_STYLES [ it ] ) ;
149
+ if ( list . length > 0 ) {
150
+ let query = list . join ( ", " ) ;
146
151
try {
147
152
let style = document . createElement ( 'style' ) ;
148
153
149
154
style . setAttribute ( 'type' , 'text/css' ) ;
150
155
if ( ! style [ 'styleSheet' ] ) {
151
- let cssText = `@media ${ query } {.fx-query-test{ }}` ;
156
+ let cssText = `/*
157
+ @angular/flex-layout - workaround for possible browser quirk with mediaQuery listeners
158
+ see http://bit.ly/2sd4HMP
159
+ */
160
+ @media ${ query } {.fx-query-test{ }}` ;
152
161
style . appendChild ( document . createTextNode ( cssText ) ) ;
153
162
}
154
163
155
164
document . getElementsByTagName ( 'head' ) [ 0 ] . appendChild ( style ) ;
156
165
157
166
// Store in private global registry
158
- ALL_STYLES [ query ] = style ;
167
+ list . forEach ( mq => ALL_STYLES [ mq ] = style ) ;
159
168
160
169
} catch ( e ) {
161
170
console . error ( e ) ;
162
171
}
163
172
}
164
173
}
165
174
175
+ /**
176
+ * Always convert to unique list of queries; for iteration in ::registerQuery()
177
+ */
178
+ function normalizeQuery ( mediaQuery : string | Array < string > ) : Array < string > {
179
+ return ( typeof mediaQuery === 'undefined' ) ? [ ] :
180
+ ( typeof mediaQuery === 'string' ) ? [ mediaQuery ] : unique ( mediaQuery as Array < string > ) ;
181
+ }
182
+
183
+ /**
184
+ * Filter duplicate mediaQueries in the list
185
+ */
186
+ function unique ( list : Array < string > ) : Array < string > {
187
+ let seen = { } ;
188
+ return list . filter ( item => {
189
+ return seen . hasOwnProperty ( item ) ? false : ( seen [ item ] = true ) ;
190
+ } ) ;
191
+ }
192
+
0 commit comments