Skip to content

Instantly share code, notes, and snippets.

@FuriouZz
Last active January 6, 2016 18:05
Show Gist options
  • Save FuriouZz/01b0375505bc54d505cc to your computer and use it in GitHub Desktop.
Save FuriouZz/01b0375505bc54d505cc to your computer and use it in GitHub Desktop.
"use strict";
/**
* Rupture.js
*
* ------------------------------------------------------------
*
* Available methods:
*
* Rupture.activate()
* Rupture.desactivate()
* Rupture.below()
* Rupture.above()
* Rupture.between()
* Rupture.at()
* Rupture.matchMedia()
*
* ------------------------------------------------------------
*
* You can override Rupture scales:
*
* Rupture.scales = [0, 460, 768, 800, 990, 1600];
*
* ------------------------------------------------------------
*
* You can override Rupture scale names:
*
* Rupture.scale_names = ['xs','s','m','l','xl','hd'];
*
* ------------------------------------------------------------
*
*/
const Utils = {
/**
* Debounce a callback function like scroll/resize
* {Function} func — Function to call
* {Number} threshold — Delay before function execution
* {Boolean} execAsap — Execute the function as soon as possible
* @return {Function}
*/
debounce(func, threshold, execAsap) {
var timeout;
return function debounced () {
var obj = this, args = arguments;
function delayed () {
if (!execAsap)
func.apply(obj, args);
timeout = null;
}
if (timeout)
clearTimeout(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = setTimeout(delayed, threshold || 50);
};
}
}
Object.freeze(Utils);
class Rupture {
constructor(){
this.mobile_cutoff = '400px';
this.desktop_cutoff = '1050px';
this.hd_cutoff = '1800px';
this.use_device_width = false;
this.scales = [0 , this.mobile_cutoff, '600px', '800px', this.desktop_cutoff, this.hd_cutoff];
this.scale_names = ['xs','s','m','l','xl','hd'];
this._bindEvents();
}
_bindEvents() {
this._onResize = this._onResize.bind(this);
// this._onDebounceResize = Utils.debounce(this._onResize, 100)
}
/**
* `activate` attach resize event
*/
activate() {
this._currentScaleIndex = null;
// window.addEventListener('resize', this._onDebounceResize);
window.addEventListener('resize', this._onResize);
this._onResize();
}
/**
* `activate` detach resize event
*/
desactivate() {
document.body.classList.remove(`rupture-${this.scale_names[this._currentScaleIndex]}`);
this._currentScaleIndex = 0;
// window.removeEventListener('resize', this._onDebounceResize);
window.removeEventListener('resize', this._onResize);
}
/**
* `below` equivalent to `max-width`
* {String || Number} scaleNameOrSize — Can be a scale name or a size in pixel
* {String || Number} strict — true: (gt or lt) | false (gte or lte)
* @return {Boolean}
*/
below(scaleNameOrSize, strict = true, orientation=null, use_device_width=this.use_device_width){
let max = this._getQuery('max', scaleNameOrSize, strict, use_device_width);
return this.matchMedia(max, orientation);
}
/**
* `above` equivalent to `min-width`
* {String || Number} scaleNameOrSize — Can be a scale name or a size in pixel
* {String || Number} strict — true: (gt or lt) | false (gte or lte)
* @return {Boolean}
*/
above(scaleNameOrSize, strict = true, orientation=null, use_device_width=this.use_device_width){
let min = this._getQuery('min', scaleNameOrSize, strict, use_device_width);
return this.matchMedia(min, orientation);
}
/**
* `between` equivalent to `(min-width: value0) and (max-width: value1)`
* {String || Number} scaleNameOrSize0 — The first scale or size
* {String || Number} scaleNameOrSize1 — The second scale or size
* {String || Number} strict — true: (gt or lt) | false (gte or lte)
* @return {Boolean}
*/
between(scaleNameOrSize0, scaleNameOrSize1, strict = true, orientation=null, use_device_width=this.use_device_width){
let min = this._getQuery('min', scaleNameOrSize0, strict);
let max = this._getQuery('max', scaleNameOrSize1, strict);
return this.matchMedia(`${min} and ${max}`, orientation);
}
/**
* `at` equivalent to `(min-width: value0) and (max-width: value1)`
* {String || Number} scaleNameOrSize — Can be a scale name or a size in pixel
* {String || Number} strict — true: (gt or lt) | false (gte or lte)
* @return {Boolean}
*/
at(scaleNameOrSize, strict = true, orientation=null, use_device_width=this.use_device_width){
return this.between(scaleNameOrSize, scaleNameOrSize, strict, orientation, use_device_width);
}
/**
* `matchMedia` test a media query
* {String} mediaQuery — The media query, you want to test
* @return {Boolean} — Return the matchMedia result
*/
matchMedia(mediaQuery, orientation=null){
if (orientation !== null) {
mediaQuery += ` and (orientation: ${orientation})`
}
return window.matchMedia(`${mediaQuery}`).matches;
}
/**
* `current` gives the actual context
*/
current(){
return this.scale_names[this._currentScaleIndex];
}
/**
* `_getQuery` builds a media query from arguments
* {String} limit — The value can be `min` or `max`
* {String || Number} scaleNameOrSize — Can be a scale name or a size in pixel
* {String || Number} strict — true: (gt or lt) | false (gte or lte)
* @return {String} — Return a media query
*/
_getQuery(limit, scaleNameOrSize, strict = false, use_device_width=this.use_device_width) {
let number;
let scales = this._getScales(scaleNameOrSize);
// Test if it is a scale and it exists
if (scales !== false && typeof scales[limit] === "number") {
number = scales[limit];
}
// Test if it is a number
else if (!isNaN(scaleNameOrSize) || !isNaN(parseInt(scaleNameOrSize))) {
number = parseInt(scaleNameOrSize);
}
if (typeof number === "number") {
if( strict && limit === "min" ) {
number++;
}
if( strict && limit === "max" ) {
number--;
}
let query = `(${limit}-width: ${number}px)`;
if (use_device_width) {
query += ` and (device-${limit}-width: ${number}px)`;
}
return query;
}
console.warn("It's not a scale or a number");
return "";
}
/**
* `_getScales` search the `value` in the scale list
* {String} value — The scale name
* @return {Boolean || Object} — Return an object with min and max size. Return false if the scale does not exist
*/
_getScales(value) {
var index = this.scale_names.indexOf(value);
if (index > -1) {
return { min: parseInt(this.scales[index]), max: parseInt(this.scales[index+1]) };
}
return { min: 0, max: 0 };
}
/**
* `_onResize` Update the body class
* {Object} e — Event object
* @return void
*/
_onResize(e) {
let tmp = this._currentScaleIndex;
for (var i = 0; i < this.scales.length; i++) {
if(this.above(this.scales[i])) {
this._currentScaleIndex = i;
}
}
if (tmp === this._currentScaleIndex) { return; }
document.body.classList.remove(`rupture-${this.scale_names[tmp]}`);
document.body.classList.add(`rupture-${this.scale_names[this._currentScaleIndex]}`);
}
/**
*
* Get the current breakpoint
*
*/
getBreakpoint(strict=true, orientation=null, use_device_width=this.use_device_width) {
for (var i = 0; i < this.scales.length; i++) {
if(this.below(this.scales[i], strict, orientation, use_device_width)) {
return {
scale_name: this.scale_names[i],
scale: this.scales[i],
index: i
}
}
}
}
}
const _rupture = new Rupture();
module.exports = _rupture;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment