UNPKG

6.36 kBJavaScriptView Raw
1'use strict';
2
3import $ from 'jquery';
4
5// Default set of media queries
6const defaultQueries = {
7 'default' : 'only screen',
8 landscape : 'only screen and (orientation: landscape)',
9 portrait : 'only screen and (orientation: portrait)',
10 retina : 'only screen and (-webkit-min-device-pixel-ratio: 2),' +
11 'only screen and (min--moz-device-pixel-ratio: 2),' +
12 'only screen and (-o-min-device-pixel-ratio: 2/1),' +
13 'only screen and (min-device-pixel-ratio: 2),' +
14 'only screen and (min-resolution: 192dpi),' +
15 'only screen and (min-resolution: 2dppx)'
16 };
17
18
19// matchMedia() polyfill - Test a CSS media type/query in JS.
20// Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license
21let matchMedia = window.matchMedia || (function() {
22 'use strict';
23
24 // For browsers that support matchMedium api such as IE 9 and webkit
25 var styleMedia = (window.styleMedia || window.media);
26
27 // For those that don't support matchMedium
28 if (!styleMedia) {
29 var style = document.createElement('style'),
30 script = document.getElementsByTagName('script')[0],
31 info = null;
32
33 style.type = 'text/css';
34 style.id = 'matchmediajs-test';
35
36 script && script.parentNode && script.parentNode.insertBefore(style, script);
37
38 // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers
39 info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle;
40
41 styleMedia = {
42 matchMedium(media) {
43 var text = `@media ${media}{ #matchmediajs-test { width: 1px; } }`;
44
45 // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers
46 if (style.styleSheet) {
47 style.styleSheet.cssText = text;
48 } else {
49 style.textContent = text;
50 }
51
52 // Test if media query is true or false
53 return info.width === '1px';
54 }
55 }
56 }
57
58 return function(media) {
59 return {
60 matches: styleMedia.matchMedium(media || 'all'),
61 media: media || 'all'
62 };
63 }
64})();
65
66var MediaQuery = {
67 queries: [],
68
69 current: '',
70
71 /**
72 * Initializes the media query helper, by extracting the breakpoint list from the CSS and activating the breakpoint watcher.
73 * @function
74 * @private
75 */
76 _init() {
77 var self = this;
78 var $meta = $('meta.foundation-mq');
79 if(!$meta.length){
80 $('<meta class="foundation-mq">').appendTo(document.head);
81 }
82
83 var extractedStyles = $('.foundation-mq').css('font-family');
84 var namedQueries;
85
86 namedQueries = parseStyleToObject(extractedStyles);
87
88 for (var key in namedQueries) {
89 if(namedQueries.hasOwnProperty(key)) {
90 self.queries.push({
91 name: key,
92 value: `only screen and (min-width: ${namedQueries[key]})`
93 });
94 }
95 }
96
97 this.current = this._getCurrentSize();
98
99 this._watcher();
100 },
101
102 /**
103 * Checks if the screen is at least as wide as a breakpoint.
104 * @function
105 * @param {String} size - Name of the breakpoint to check.
106 * @returns {Boolean} `true` if the breakpoint matches, `false` if it's smaller.
107 */
108 atLeast(size) {
109 var query = this.get(size);
110
111 if (query) {
112 return matchMedia(query).matches;
113 }
114
115 return false;
116 },
117
118 /**
119 * Checks if the screen matches to a breakpoint.
120 * @function
121 * @param {String} size - Name of the breakpoint to check, either 'small only' or 'small'. Omitting 'only' falls back to using atLeast() method.
122 * @returns {Boolean} `true` if the breakpoint matches, `false` if it does not.
123 */
124 is(size) {
125 size = size.trim().split(' ');
126 if(size.length > 1 && size[1] === 'only') {
127 if(size[0] === this._getCurrentSize()) return true;
128 } else {
129 return this.atLeast(size[0]);
130 }
131 return false;
132 },
133
134 /**
135 * Gets the media query of a breakpoint.
136 * @function
137 * @param {String} size - Name of the breakpoint to get.
138 * @returns {String|null} - The media query of the breakpoint, or `null` if the breakpoint doesn't exist.
139 */
140 get(size) {
141 for (var i in this.queries) {
142 if(this.queries.hasOwnProperty(i)) {
143 var query = this.queries[i];
144 if (size === query.name) return query.value;
145 }
146 }
147
148 return null;
149 },
150
151 /**
152 * Gets the current breakpoint name by testing every breakpoint and returning the last one to match (the biggest one).
153 * @function
154 * @private
155 * @returns {String} Name of the current breakpoint.
156 */
157 _getCurrentSize() {
158 var matched;
159
160 for (var i = 0; i < this.queries.length; i++) {
161 var query = this.queries[i];
162
163 if (matchMedia(query.value).matches) {
164 matched = query;
165 }
166 }
167
168 if (typeof matched === 'object') {
169 return matched.name;
170 } else {
171 return matched;
172 }
173 },
174
175 /**
176 * Activates the breakpoint watcher, which fires an event on the window whenever the breakpoint changes.
177 * @function
178 * @private
179 */
180 _watcher() {
181 $(window).off('resize.zf.mediaquery').on('resize.zf.mediaquery', () => {
182 var newSize = this._getCurrentSize(), currentSize = this.current;
183
184 if (newSize !== currentSize) {
185 // Change the current media query
186 this.current = newSize;
187
188 // Broadcast the media query change on the window
189 $(window).trigger('changed.zf.mediaquery', [newSize, currentSize]);
190 }
191 });
192 }
193};
194
195
196
197// Thank you: https://github.com/sindresorhus/query-string
198function parseStyleToObject(str) {
199 var styleObject = {};
200
201 if (typeof str !== 'string') {
202 return styleObject;
203 }
204
205 str = str.trim().slice(1, -1); // browsers re-quote string style values
206
207 if (!str) {
208 return styleObject;
209 }
210
211 styleObject = str.split('&').reduce(function(ret, param) {
212 var parts = param.replace(/\+/g, ' ').split('=');
213 var key = parts[0];
214 var val = parts[1];
215 key = decodeURIComponent(key);
216
217 // missing `=` should be `null`:
218 // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
219 val = val === undefined ? null : decodeURIComponent(val);
220
221 if (!ret.hasOwnProperty(key)) {
222 ret[key] = val;
223 } else if (Array.isArray(ret[key])) {
224 ret[key].push(val);
225 } else {
226 ret[key] = [ret[key], val];
227 }
228 return ret;
229 }, {});
230
231 return styleObject;
232}
233
234export {MediaQuery};