Last active
January 6, 2016 18:05
-
-
Save FuriouZz/01b0375505bc54d505cc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"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