351 lines
6.7 KiB
JavaScript
351 lines
6.7 KiB
JavaScript
/* breakpoints.js v0.1-dev | @ajlkn | MIT licensed */
|
|
|
|
var breakpoints = (function() { "use strict"; var _ = {
|
|
|
|
/**
|
|
* List.
|
|
* @var {array}
|
|
*/
|
|
list: null,
|
|
|
|
/**
|
|
* Media cache.
|
|
* @var {object}
|
|
*/
|
|
media: {},
|
|
|
|
/**
|
|
* Events.
|
|
* @var {array}
|
|
*/
|
|
events: [],
|
|
|
|
/**
|
|
* Initialize.
|
|
* @param {array} list List.
|
|
*/
|
|
init: function(list) {
|
|
|
|
// Set list.
|
|
_.list = list;
|
|
|
|
// Add event listeners.
|
|
window.addEventListener('resize', _.poll);
|
|
window.addEventListener('orientationchange', _.poll);
|
|
window.addEventListener('load', _.poll);
|
|
window.addEventListener('fullscreenchange', _.poll);
|
|
|
|
},
|
|
|
|
/**
|
|
* Determines if a given query is active.
|
|
* @param {string} query Query.
|
|
* @return {bool} True if yes, false if no.
|
|
*/
|
|
active: function(query) {
|
|
|
|
var breakpoint, op, media,
|
|
a, x, y, units;
|
|
|
|
// Media for this query doesn't exist? Generate it.
|
|
if (!(query in _.media)) {
|
|
|
|
// Determine operator, breakpoint.
|
|
|
|
// Greater than or equal.
|
|
if (query.substr(0, 2) == '>=') {
|
|
|
|
op = 'gte';
|
|
breakpoint = query.substr(2);
|
|
|
|
}
|
|
|
|
// Less than or equal.
|
|
else if (query.substr(0, 2) == '<=') {
|
|
|
|
op = 'lte';
|
|
breakpoint = query.substr(2);
|
|
|
|
}
|
|
|
|
// Greater than.
|
|
else if (query.substr(0, 1) == '>') {
|
|
|
|
op = 'gt';
|
|
breakpoint = query.substr(1);
|
|
|
|
}
|
|
|
|
// Less than.
|
|
else if (query.substr(0, 1) == '<') {
|
|
|
|
op = 'lt';
|
|
breakpoint = query.substr(1);
|
|
|
|
}
|
|
|
|
// Not.
|
|
else if (query.substr(0, 1) == '!') {
|
|
|
|
op = 'not';
|
|
breakpoint = query.substr(1);
|
|
|
|
}
|
|
|
|
// Equal.
|
|
else {
|
|
|
|
op = 'eq';
|
|
breakpoint = query;
|
|
|
|
}
|
|
|
|
// Build media.
|
|
if (breakpoint && breakpoint in _.list) {
|
|
|
|
a = _.list[breakpoint];
|
|
|
|
// Range.
|
|
if (Array.isArray(a)) {
|
|
|
|
x = parseInt(a[0]);
|
|
y = parseInt(a[1]);
|
|
|
|
if (!isNaN(x))
|
|
units = a[0].substr(String(x).length);
|
|
else if (!isNaN(y))
|
|
units = a[1].substr(String(y).length);
|
|
else
|
|
return;
|
|
|
|
// Max only.
|
|
if (isNaN(x)) {
|
|
|
|
switch (op) {
|
|
|
|
// Greater than or equal (>= 0 / anything)
|
|
case 'gte':
|
|
media = 'screen';
|
|
break;
|
|
|
|
// Less than or equal (<= y)
|
|
case 'lte':
|
|
media = 'screen and (max-width: ' + y + units + ')';
|
|
break;
|
|
|
|
// Greater than (> y)
|
|
case 'gt':
|
|
media = 'screen and (min-width: ' + (y + 1) + units + ')';
|
|
break;
|
|
|
|
// Less than (< 0 / invalid)
|
|
case 'lt':
|
|
media = 'screen and (max-width: -1px)';
|
|
break;
|
|
|
|
// Not (> y)
|
|
case 'not':
|
|
media = 'screen and (min-width: ' + (y + 1) + units + ')';
|
|
break;
|
|
|
|
// Equal (<= y)
|
|
default:
|
|
media = 'screen and (max-width: ' + y + units + ')';
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Min only.
|
|
else if (isNaN(y)) {
|
|
|
|
switch (op) {
|
|
|
|
// Greater than or equal (>= x)
|
|
case 'gte':
|
|
media = 'screen and (min-width: ' + x + units + ')';
|
|
break;
|
|
|
|
// Less than or equal (<= inf / anything)
|
|
case 'lte':
|
|
media = 'screen';
|
|
break;
|
|
|
|
// Greater than (> inf / invalid)
|
|
case 'gt':
|
|
media = 'screen and (max-width: -1px)';
|
|
break;
|
|
|
|
// Less than (< x)
|
|
case 'lt':
|
|
media = 'screen and (max-width: ' + (x - 1) + units + ')';
|
|
break;
|
|
|
|
// Not (< x)
|
|
case 'not':
|
|
media = 'screen and (max-width: ' + (x - 1) + units + ')';
|
|
break;
|
|
|
|
// Equal (>= x)
|
|
default:
|
|
media = 'screen and (min-width: ' + x + units + ')';
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Min and max.
|
|
else {
|
|
|
|
switch (op) {
|
|
|
|
// Greater than or equal.
|
|
case 'gte':
|
|
media = 'screen and (min-width: ' + x + units + ')';
|
|
break;
|
|
|
|
// Less than or equal.
|
|
case 'lte':
|
|
media = 'screen and (max-width: ' + y + units + ')';
|
|
break;
|
|
|
|
// Greater than.
|
|
case 'gt':
|
|
media = 'screen and (min-width: ' + (y + 1) + units + ')';
|
|
break;
|
|
|
|
// Less than.
|
|
case 'lt':
|
|
media = 'screen and (max-width: ' + (x - 1) + units + ')';
|
|
break;
|
|
|
|
// Not.
|
|
case 'not':
|
|
media = 'screen and (max-width: ' + (x - 1) + units + '), screen and (min-width: ' + (y + 1) + units + ')';
|
|
break;
|
|
|
|
// Equal.
|
|
default:
|
|
media = 'screen and (min-width: ' + x + units + ') and (max-width: ' + y + units + ')';
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// String.
|
|
else {
|
|
|
|
// Missing a media type? Prefix with "screen".
|
|
if (a.charAt(0) == '(')
|
|
media = 'screen and ' + a;
|
|
|
|
// Otherwise, use as-is.
|
|
else
|
|
media = a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Cache.
|
|
_.media[query] = (media ? media : false);
|
|
|
|
}
|
|
|
|
return (
|
|
_.media[query] === false
|
|
? false
|
|
: window.matchMedia(_.media[query]).matches
|
|
);
|
|
|
|
},
|
|
|
|
/**
|
|
* Registers an event.
|
|
* @param {string} query Query.
|
|
* @param {function} handler Handler.
|
|
*/
|
|
on: function(query, handler) {
|
|
|
|
// Register event.
|
|
_.events.push({
|
|
query: query,
|
|
handler: handler,
|
|
state: false
|
|
});
|
|
|
|
// Query active *right now*? Call handler.
|
|
if (_.active(query))
|
|
(handler)();
|
|
|
|
},
|
|
|
|
/**
|
|
* Polls for events.
|
|
*/
|
|
poll: function() {
|
|
|
|
var i, e;
|
|
|
|
// Step through events.
|
|
for (i=0; i < _.events.length; i++) {
|
|
|
|
// Get event.
|
|
e = _.events[i];
|
|
|
|
// Active?
|
|
if (_.active(e.query)) {
|
|
|
|
// Hasn't been called yet?
|
|
if (!e.state) {
|
|
|
|
// Mark as called.
|
|
e.state = true;
|
|
|
|
// Call handler.
|
|
(e.handler)();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Otherwise ...
|
|
else {
|
|
|
|
// Previously called?
|
|
if (e.state) {
|
|
|
|
// Unmark as called.
|
|
e.state = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}; function __(list) { _.init(list); }; __._ = _; __.on = function(query, handler) { _.on(query, handler); }; __.active = function(query) { return _.active(query); }; return __; })();
|
|
|
|
// UMD Wrapper (github.com/umdjs/umd/blob/master/returnExports.js | @umdjs + @nason)
|
|
(function(root, factory) {
|
|
|
|
// AMD.
|
|
if (typeof define === 'function' && define.amd)
|
|
define([], factory);
|
|
|
|
// Node.
|
|
else if (typeof exports === 'object')
|
|
module.exports = factory();
|
|
|
|
// Breakpoints global.
|
|
else
|
|
root.breakpoints = factory();
|
|
|
|
}(this, function() { return breakpoints; })); |