326 lines
12 KiB
JavaScript
Executable File
326 lines
12 KiB
JavaScript
Executable File
/*! MediaMatch v.2.0.3 - Testing css media queries in Javascript. Authors & copyright (c) 2013: WebLinc, David Knight. */
|
|
|
|
window.matchMedia || (window.matchMedia = function (win) {
|
|
'use strict';
|
|
|
|
// Internal globals
|
|
var _doc = win.document,
|
|
_viewport = _doc.documentElement,
|
|
_queries = [],
|
|
_queryID = 0,
|
|
_type = '',
|
|
_features = {},
|
|
// only screen
|
|
// only screen and
|
|
// not screen
|
|
// not screen and
|
|
// screen
|
|
// screen and
|
|
_typeExpr = /\s*(only|not)?\s*(screen|print|[a-z\-]+)\s*(and)?\s*/i,
|
|
// (-vendor-min-width: 300px)
|
|
// (min-width: 300px)
|
|
// (width: 300px)
|
|
// (width)
|
|
// (orientation: portrait|landscape)
|
|
_mediaExpr = /^\s*\(\s*(-[a-z]+-)?(min-|max-)?([a-z\-]+)\s*(:?\s*([0-9]+(\.[0-9]+)?|portrait|landscape)(px|em|dppx|dpcm|rem|%|in|cm|mm|ex|pt|pc|\/([0-9]+(\.[0-9]+)?))?)?\s*\)\s*$/,
|
|
_timer = 0,
|
|
|
|
// Helper methods
|
|
|
|
/*
|
|
_matches
|
|
*/
|
|
_matches = function (media) {
|
|
// screen and (min-width: 400px), screen and (max-width: 500px)
|
|
var mql = (media.indexOf(',') !== -1 && media.split(',')) || [media],
|
|
mqIndex = mql.length - 1,
|
|
mqLength = mqIndex,
|
|
mq = null,
|
|
|
|
// not screen, screen
|
|
negateType = null,
|
|
negateTypeFound = '',
|
|
negateTypeIndex = 0,
|
|
negate = false,
|
|
type = '',
|
|
|
|
// (min-width: 400px), (min-width)
|
|
exprListStr = '',
|
|
exprList = null,
|
|
exprIndex = 0,
|
|
exprLength = 0,
|
|
expr = null,
|
|
|
|
prefix = '',
|
|
length = '',
|
|
unit = '',
|
|
value = '',
|
|
feature = '',
|
|
|
|
match = false;
|
|
|
|
if (media === '') {
|
|
return true;
|
|
}
|
|
|
|
do {
|
|
mq = mql[mqLength - mqIndex];
|
|
negate = false;
|
|
negateType = mq.match(_typeExpr);
|
|
|
|
if (negateType) {
|
|
negateTypeFound = negateType[0];
|
|
negateTypeIndex = negateType.index;
|
|
}
|
|
|
|
if (!negateType || ((mq.substring(0, negateTypeIndex).indexOf('(') === -1) && (negateTypeIndex || (!negateType[3] && negateTypeFound !== negateType.input)))) {
|
|
match = false;
|
|
continue;
|
|
}
|
|
|
|
exprListStr = mq;
|
|
|
|
negate = negateType[1] === 'not';
|
|
|
|
if (!negateTypeIndex) {
|
|
type = negateType[2];
|
|
exprListStr = mq.substring(negateTypeFound.length);
|
|
}
|
|
|
|
// Test media type
|
|
// Test type against this device or if 'all' or empty ''
|
|
match = type === _type || type === 'all' || type === '';
|
|
|
|
exprList = (exprListStr.indexOf(' and ') !== -1 && exprListStr.split(' and ')) || [exprListStr];
|
|
exprIndex = exprList.length - 1;
|
|
exprLength = exprIndex;
|
|
|
|
if (match && exprIndex >= 0 && exprListStr !== '') {
|
|
do {
|
|
expr = exprList[exprIndex].match(_mediaExpr);
|
|
|
|
if (!expr || !_features[expr[3]]) {
|
|
match = false;
|
|
break;
|
|
}
|
|
|
|
prefix = expr[2];
|
|
length = expr[5];
|
|
value = length;
|
|
unit = expr[7];
|
|
feature = _features[expr[3]];
|
|
|
|
// Convert unit types
|
|
if (unit) {
|
|
if (unit === 'px') {
|
|
// If unit is px
|
|
value = Number(length);
|
|
} else if (unit === 'em' || unit === 'rem') {
|
|
// Convert relative length unit to pixels
|
|
// Assumed base font size is 16px
|
|
value = 16 * length;
|
|
} else if (expr[8]) {
|
|
// Convert aspect ratio to decimal
|
|
value = (length / expr[8]).toFixed(2);
|
|
} else if (unit === 'dppx') {
|
|
// Convert resolution dppx unit to pixels
|
|
value = length * 96;
|
|
} else if (unit === 'dpcm') {
|
|
// Convert resolution dpcm unit to pixels
|
|
value = length * 0.3937;
|
|
} else {
|
|
// default
|
|
value = Number(length);
|
|
}
|
|
}
|
|
|
|
// Test for prefix min or max
|
|
// Test value against feature
|
|
if (prefix === 'min-' && value) {
|
|
match = feature >= value;
|
|
} else if (prefix === 'max-' && value) {
|
|
match = feature <= value;
|
|
} else if (value) {
|
|
match = feature === value;
|
|
} else {
|
|
match = !!feature;
|
|
}
|
|
|
|
// If 'match' is false, break loop
|
|
// Continue main loop through query list
|
|
if (!match) {
|
|
break;
|
|
}
|
|
} while (exprIndex--);
|
|
}
|
|
|
|
// If match is true, break loop
|
|
// Once matched, no need to check other queries
|
|
if (match) {
|
|
break;
|
|
}
|
|
} while (mqIndex--);
|
|
|
|
return negate ? !match : match;
|
|
},
|
|
|
|
/*
|
|
_setFeature
|
|
*/
|
|
_setFeature = function () {
|
|
// Sets properties of '_features' that change on resize and/or orientation.
|
|
var w = win.innerWidth || _viewport.clientWidth,
|
|
h = win.innerHeight || _viewport.clientHeight,
|
|
dw = win.screen.width,
|
|
dh = win.screen.height,
|
|
c = win.screen.colorDepth,
|
|
x = win.devicePixelRatio;
|
|
|
|
_features.width = w;
|
|
_features.height = h;
|
|
_features['aspect-ratio'] = (w / h).toFixed(2);
|
|
_features['device-width'] = dw;
|
|
_features['device-height'] = dh;
|
|
_features['device-aspect-ratio'] = (dw / dh).toFixed(2);
|
|
_features.color = c;
|
|
_features['color-index'] = Math.pow(2, c);
|
|
_features.orientation = (h >= w ? 'portrait' : 'landscape');
|
|
_features.resolution = (x && x * 96) || win.screen.deviceXDPI || 96;
|
|
_features['device-pixel-ratio'] = x || 1;
|
|
},
|
|
|
|
/*
|
|
_watch
|
|
*/
|
|
_watch = function () {
|
|
clearTimeout(_timer);
|
|
|
|
_timer = setTimeout(function () {
|
|
var query = null,
|
|
qIndex = _queryID - 1,
|
|
qLength = qIndex,
|
|
match = false;
|
|
|
|
if (qIndex >= 0) {
|
|
_setFeature();
|
|
|
|
do {
|
|
query = _queries[qLength - qIndex];
|
|
|
|
if (query) {
|
|
match = _matches(query.mql.media);
|
|
|
|
if ((match && !query.mql.matches) || (!match && query.mql.matches)) {
|
|
query.mql.matches = match;
|
|
|
|
if (query.listeners) {
|
|
for (var i = 0, il = query.listeners.length; i < il; i++) {
|
|
if (query.listeners[i]) {
|
|
query.listeners[i].call(win, query.mql);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} while(qIndex--);
|
|
}
|
|
|
|
|
|
}, 10);
|
|
},
|
|
|
|
/*
|
|
_init
|
|
*/
|
|
_init = function () {
|
|
var head = _doc.getElementsByTagName('head')[0],
|
|
style = _doc.createElement('style'),
|
|
info = null,
|
|
typeList = ['screen', 'print', 'speech', 'projection', 'handheld', 'tv', 'braille', 'embossed', 'tty'],
|
|
typeIndex = 0,
|
|
typeLength = typeList.length,
|
|
cssText = '#mediamatchjs { position: relative; z-index: 0; }',
|
|
eventPrefix = '',
|
|
addEvent = win.addEventListener || (eventPrefix = 'on') && win.attachEvent;
|
|
|
|
style.type = 'text/css';
|
|
style.id = 'mediamatchjs';
|
|
|
|
head.appendChild(style);
|
|
|
|
// Must be placed after style is inserted into the DOM for IE
|
|
info = (win.getComputedStyle && win.getComputedStyle(style)) || style.currentStyle;
|
|
|
|
// Create media blocks to test for media type
|
|
for ( ; typeIndex < typeLength; typeIndex++) {
|
|
cssText += '@media ' + typeList[typeIndex] + ' { #mediamatchjs { position: relative; z-index: ' + typeIndex + ' } }';
|
|
}
|
|
|
|
// Add rules to style element
|
|
if (style.styleSheet) {
|
|
style.styleSheet.cssText = cssText;
|
|
} else {
|
|
style.textContent = cssText;
|
|
}
|
|
|
|
// Get media type
|
|
_type = typeList[(info.zIndex * 1) || 0];
|
|
|
|
head.removeChild(style);
|
|
|
|
_setFeature();
|
|
|
|
// Set up listeners
|
|
addEvent(eventPrefix + 'resize', _watch, false);
|
|
addEvent(eventPrefix + 'orientationchange', _watch, false);
|
|
};
|
|
|
|
_init();
|
|
|
|
/*
|
|
A list of parsed media queries, ex. screen and (max-width: 400px), screen and (max-width: 800px)
|
|
*/
|
|
return function (media) {
|
|
var id = _queryID,
|
|
mql = {
|
|
matches : false,
|
|
media : media,
|
|
addListener : function addListener(listener) {
|
|
_queries[id].listeners || (_queries[id].listeners = []);
|
|
listener && _queries[id].listeners.push(listener);
|
|
},
|
|
removeListener : function removeListener(listener) {
|
|
var query = _queries[id],
|
|
i = 0,
|
|
il = 0;
|
|
|
|
if (!query) {
|
|
return;
|
|
}
|
|
|
|
il = query.listeners.length;
|
|
|
|
for ( ; i < il; i++) {
|
|
if (query.listeners[i] === listener) {
|
|
query.listeners.splice(i, 1);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
if (media === '') {
|
|
mql.matches = true;
|
|
return mql;
|
|
}
|
|
|
|
mql.matches = _matches(media);
|
|
|
|
_queryID = _queries.push({
|
|
mql : mql,
|
|
listeners : null
|
|
});
|
|
|
|
return mql;
|
|
};
|
|
}(window));
|