Skip to content

Commit 45272e8

Browse files
committed
Implement media query match() function and expose parse()
1 parent e3a25b4 commit 45272e8

File tree

1 file changed

+74
-12
lines changed

1 file changed

+74
-12
lines changed

index.js

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,84 @@ See the accompanying LICENSE file for terms.
66

77
'use strict';
88

9-
module.exports = match;
9+
exports.match = matchQuery;
10+
exports.parse = parseQuery;
1011

1112
// -----------------------------------------------------------------------------
1213

13-
function match(mediaQuery, values) {
14-
return parseQuery(mediaQuery);
15-
}
16-
17-
// -- Utilities ----------------------------------------------------------------
18-
1914
var RE_MEDIA_QUERY = /(?:(only|not)?\s*([^\s\(\)]+)\s*and\s*)?(.+)?/i,
2015
RE_MQ_EXPRESSION = /\(\s*([^\s\:\)]+)\s*(?:\:\s*([^\s\)]+))?\s*\)/,
2116
RE_MQ_FEATURE = /^(?:(min|max)-)?(.+)/,
2217
RE_LENGTH_UNIT = /(em|rem|px|cm|mm|in|pt|pc)?$/,
2318
RE_RESOLUTION_UNIT = /(dpi|dpcm|dppx)?$/;
2419

20+
function matchQuery(mediaQuery, values) {
21+
return parseQuery(mediaQuery).some(function (query) {
22+
var inverse = query.inverse;
23+
24+
// Either the parsed or specified `type` is "all", or the types must be
25+
// equal for a match.
26+
var typeMatch = query.type === 'all' || values.type === 'all' ||
27+
values.type === query.type;
28+
29+
// Quit early when `type` doesn't match, but take "not" into account.
30+
if ((typeMatch && inverse) || !(typeMatch || inverse)) {
31+
return false;
32+
}
33+
34+
var expressionsMatch = query.expressions.every(function (expression) {
35+
var feature = expression.feature,
36+
modifier = expression.modifier,
37+
expValue = expression.value,
38+
value = values[feature];
39+
40+
// Missing or falsy values don't match.
41+
if (!value) { return false; }
42+
43+
switch (feature) {
44+
case 'orientation':
45+
case 'scan':
46+
return value.toLowerCase() === expValue.toLowerCase();
47+
48+
case 'width':
49+
case 'height':
50+
case 'device-width':
51+
case 'device-height':
52+
expValue = toPx(expValue);
53+
value = toPx(value);
54+
break;
55+
56+
case 'resolution':
57+
expValue = toDpi(expValue);
58+
value = toDpi(value);
59+
break;
60+
61+
case 'aspect-ratio':
62+
case 'device-aspect-ratio':
63+
expValue = toDecimal(expValue);
64+
value = toDecimal(value);
65+
break;
66+
67+
case 'grid':
68+
case 'color':
69+
case 'color-index':
70+
case 'monochrome':
71+
expValue = parseInt(expValue, 10) || 1;
72+
value = parseInt(value, 10) || 0;
73+
break;
74+
}
75+
76+
switch (modifier) {
77+
case 'min': return value >= expValue;
78+
case 'max': return value <= expValue;
79+
default : return value === expValue;
80+
}
81+
});
82+
83+
return (expressionsMatch && !inverse) || (!expressionsMatch && inverse);
84+
});
85+
}
86+
2587
function parseQuery(mediaQuery) {
2688
return mediaQuery.split(',').map(function (query) {
2789
var captures = query.match(RE_MEDIA_QUERY),
@@ -30,9 +92,8 @@ function parseQuery(mediaQuery) {
3092
expressions = captures[3],
3193
parsed = {};
3294

33-
parsed.only = !!modifier && modifier.toLowerCase() === 'only';
34-
parsed.not = !!modifier && modifier.toLowerCase() === 'not';
35-
parsed.type = type ? type.toLowerCase() : 'all';
95+
parsed.inverse = !!modifier && modifier.toLowerCase() === 'not';
96+
parsed.type = type ? type.toLowerCase() : 'all';
3697

3798
// Split expressions into a list.
3899
expressions = expressions.match(/\([^\)]+\)/g);
@@ -42,9 +103,8 @@ function parseQuery(mediaQuery) {
42103
feature = captures[1].toLowerCase().match(RE_MQ_FEATURE);
43104

44105
return {
45-
feature : feature[0],
46106
modifier: feature[1],
47-
property: feature[2],
107+
feature : feature[2],
48108
value : captures[2]
49109
};
50110
});
@@ -53,6 +113,8 @@ function parseQuery(mediaQuery) {
53113
});
54114
}
55115

116+
// -- Utilities ----------------------------------------------------------------
117+
56118
function toDecimal(ratio) {
57119
var decimal = Number(ratio),
58120
numbers;

0 commit comments

Comments
 (0)