Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

wiggle.js

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

wiggle.js - npm Package Compare versions

Comparing version 1.0.0 to 1.1.0

demo.html

0

.eslintrc.js

@@ -0,0 +0,0 @@ module.exports = {

@@ -0,1 +1,5 @@

## [1.1.0] - 2017-05-21
### Changed
- remove window resize listener and use match media listener
## [1.0.0] - 2017-05-18

@@ -2,0 +6,0 @@ - Version bumped to stable after testing in production

@@ -0,0 +0,0 @@ module.exports = function (config) {

5

package.json
{
"name": "wiggle.js",
"version": "1.0.0",
"version": "1.1.0",
"description": "Media query change listener",

@@ -11,4 +11,3 @@ "main": "wiggle.js",

"keywords": [
"media-query",
"MediaQuery",
"media query",
"matchMedia",

@@ -15,0 +14,0 @@ "responsive",

# wiggle
Small wrapper around [matchMedia](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia)
to easily react on changes in page layout.
Subscribe and react to page breakpoints.
Ideal for responsive pages as it allows us to easily react with JS on page layout changes.
### When to use it
- We might need to swipe position of 2 elements with JS/jQuery when page layout changes from desktop to mobile layout and vice versa
- We want to optimize code to include only components that are used on current screen layout (in React, Vue, Angular...). Check "examples of usage in Vue.js" at the bottom for more info
- We might want to optimize page to load additional resources only if layout is desktop.
- In any other case when we want to execute custom JS code on specific page layout.
```javascript
/**
* Before using library we need to initialize it with desired breakpoint.
* Init returns new wiggle instance that allow us to listen for defined screens definitions
* Even thought we can have multiple instances of wiggle in 99% we should have only one instance.
* In order to use wiggle we need to initialize it.
* Init returns new wiggle instance that allow us to subscribe to defined rules
**/
var wiggle = Wiggle.init([{
minWidth: 992, // Default unit is px. Same as writing '992px'
name: 'desktop' // Name can be any string that is valid JS object property name and it have to be unique for each screen.
var screen = Wiggle.init([{
name: 'desktop', // Required and unique for instance. It can be any string that is valid JS object name
minWidth: 992
}, {
minWidth: '768',
maxWidth: '62em', // We can combine different measurements units but it does not mean we should!
name: 'tablet'
name: 'tablet',
minWidth: '768', // Can be number or string. In case of number it defaults to px measurements unit
maxWidth: '62em' // We can combine different measurements units but it does not mean we should!
}, {
maxWidth: 767,
name: 'mobile'
name: 'mobile',
maxWidth: 767
}]);
/**
* Add subscriber for 'mobile' screen.
* Subscriber will execute if current screen size is mobile and every time we switch from some other screens size to mobile.
* Instead of mobile we can subscribe to any other defined screen size like 'desktop' or 'tablet'
* Mobile screen size is defined during initialization of wiggle
**/
wiggle.on('mobile', function() {
console.log("Function that will be executed if current screen size is mobile and every time screen sizes switches to mobile");
// We are subscribing to names defined during initiation of wiggle.
screen.on('mobile', function() {
console.log('Function that will be executed if current screen size is mobile and every time screen size switches to mobile');
});
wiggle.on('mobile', function() {
console.log("We can have multiple listeners for same screen size and each will be executed.");
screen.on.change('mobile', function() {
console.log('Function that will be executed every time screen size switches to mobile.');
});
wiggle.on('desktop', function() {
console.log("Function that will be executed if current screen size is mobile and every time screen sizes switches to mobile.");
screen.on('desktop', function() {
console.log('Screen size is desktop');
});
wiggle.queueOn('mobile', function() {
console.log("function that will be executed every time screen sizes switches to mobile size");
screen.off('tablet', function() {
console.log('function that will be executed if screen size is not tablet and every time screen size stops being tablet');
});
wiggle.off('mobile', function() {
console.log("function that will be executed if screen size is not mobile and every time screen size stops being mobile");
screen.off.change('desktop', function() {
console.log('function that will be executed every time screen size stops being mobile');
});
wiggle.queueOff('mobile', function() {
console.log("function that will be executed every time screen size stops being mobile");
});
if(wiggle.is('desktop')) {
console.log("Current screen size is desktop");
if(screen.is('desktop')) {
console.log('Current screen size is desktop');
}
```
### Examples of usage in Vue.js
// We can have multiple instances of wiggle
var orientation = Wiggle.init([{
name: 'portrait',
mediaQuery: '(orientation: portrait)' // Raw media query
}, {
name: 'landscape',
mediaQuery: '(orientation: landscape)'
}]);
Basic premises is that we will have components that will need to be displayed only on desktop.
We can easily hide them with media-queries and display none. Problem with hiding them like that is that components will
still render and components code will still be executed which is far from ideal.
orientation.on('portrait', function() {
console.log('function that will be executed if screen is in portrait mode and every time screen switches to portrait mode');
});
With wiggle and v-if directive we can easily optimize that and render only components that are actually used on current screen layout.
```javascript
// Update view.type reactive Vuex store state with wiggle
wiggle.on('desktop', () => store.dispatch('changeViewType', View.type.DESKTOP));
wiggle.on('tablet', () => store.dispatch('changeViewType', View.type.TABLET));
wiggle.on('mobile', () => store.dispatch('changeViewType', View.type.MOBILE));
// Now in our vue component we can have computed property as this
computed: {
isDesktop() {
return this.$store.state.App.view.type === View.type.DESKTOP;
}
}
```
The above code allow us to do something like
```html
<widgets-sidebar v-if="isDesktop"><widgets-sidebar>
```
### Supported browsers
Wiggle is using [matchMedia](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia) to detect layout changes.
If you need to support browser that does not support matchMedia (IE9 and below) you need to include [matchMedia polyfill](https://github.com/paulirish/matchMedia.js) before using this library.
matchMedia is not supported in IE9 and below.
/*****************************************************
https://github.com/snovakovic/wiggle
author: stefan.novakovich@gmail.com
version: 0.7.0
version: 1.1.0
***************************************************/

@@ -17,5 +17,4 @@ (function(global, factory) {

function Instance(screens, resizeDelay) {
var doit;
var activeScreens = [];
function Instance(screens) {
var activeScreens = {};
var subscribers = {};

@@ -29,58 +28,39 @@ var subscribeType = {

Object.getOwnPropertyNames(subscribeType).forEach(function(name) {
subscribers[name] = {};
Object.keys(subscribeType).forEach(function(key) {
subscribers[key] = {};
});
window.addEventListener('resize', function() {
clearTimeout(doit);
doit = setTimeout(updateActiveScreens, resizeDelay);
}, true);
screens.forEach(function(screen) {
var mediaQuery = constructMediaQuery(screen);
var mql = window.matchMedia(mediaQuery);
updateActiveScreens();
screenSwitch(screen, mql);
mql.addListener(screenSwitch.bind(null, screen));
});
// Define private methods
// Private methods
function updateActiveScreens() {
screens.forEach(function(screen) {
isScreenActive(screen)
? activateScreen(screen.name)
: deactivateScreen(screen.name);
});
function screenSwitch(screen, mql) {
mql.matches ? activateScreen(screen) : deactivateScreen(screen);
}
function isScreenActive(screen) {
if (typeof screen === 'string') {
screen = getScreen(screen);
}
return Boolean(screen && (screen.minWidth || screen.maxWidth) &&
(!screen.minWidth || matchMedia('min-width', screen.minWidth)) &&
(!screen.maxWidth || matchMedia('max-width', screen.maxWidth)));
function sizeToMediaQuery(size, prop) {
size = typeof size === 'number' ? size + 'px' : size;
return size ? '(' + prop + ':' + size + ')' : '';
}
function activateScreen(name) {
if (!activeScreens[name]) {
activeScreens[name] = screen;
notifySubscribers(name, subscribeType.on);
function constructMediaQuery(screen) {
if (screen.mediaQuery) {
return screen.mediaQuery;
}
}
function deactivateScreen(name) {
if (activeScreens[name]) {
delete activeScreens[name];
notifySubscribers(name, subscribeType.off);
}
}
var minWidth = sizeToMediaQuery(screen.minWidth, 'min-width');
var maxWidth = sizeToMediaQuery(screen.maxWidth, 'max-width');
var appender = (minWidth && maxWidth) ? ' and ' : '';
function getScreen(name) {
for (var i = 0; i < screens.length; i++) {
if (name === screens[i].name) {
return screens[i];
}
}
return minWidth + appender + maxWidth;
}
function matchMedia(property, width) {
if (typeof width === 'number') { width += 'px'; }
return width ? window.matchMedia('(' + property + ':' + width + ')').matches : false;
function isScreenActive(name) {
return Boolean(activeScreens[name]);
}

@@ -90,3 +70,3 @@

var screenSubscribers = subscribers[type][screenName];
if (screenSubscribers && screenSubscribers.length) {
if (screenSubscribers) {
screenSubscribers.forEach(function(subscriber) {

@@ -98,3 +78,17 @@ subscriber.execute();

function subscribe(name, type, callback) {
function activateScreen(screen) {
if (!activeScreens[screen.name]) {
activeScreens[screen.name] = screen;
notifySubscribers(screen.name, subscribeType.on);
}
}
function deactivateScreen(screen) {
if (activeScreens[screen.name]) {
delete activeScreens[screen.name];
notifySubscribers(screen.name, subscribeType.off);
}
}
function subscribe(name, type, cb) {
subscribers[type][name] = subscribers[type][name] || [];

@@ -104,28 +98,28 @@ subscribers[type][name].push({

type: type,
execute: callback
execute: cb
});
}
// Export API
// Public
this.on = function(screenName, callback) {
if (isScreenActive(screenName)) { callback(); }
this.queueOn(screenName, callback);
this.on = function(name, cb) {
if (isScreenActive(name)) { cb(); }
this.on.change(name, cb);
};
this.queueOn = function(screenName, callback) {
subscribe(screenName, subscribeType.on, callback);
this.on.change = function(name, cb) {
subscribe(name, subscribeType.on, cb);
};
this.off = function(screenName, callback) {
if (!isScreenActive(screenName)) { callback(); }
this.queueOff(screenName, callback);
this.off = function(name, cb) {
if (!isScreenActive(name)) { cb(); }
this.off.change(name, cb);
};
this.queueOff = function(screenName, callback) {
subscribe(screenName, subscribeType.off, callback);
this.off.change = function(name, cb) {
subscribe(name, subscribeType.off, cb);
};
this.is = function(screenName) {
return Boolean(activeScreens[screenName]);
this.is = function(name) {
return Boolean(activeScreens[name]);
};

@@ -137,14 +131,13 @@

return {
init: function(screens, resizeDelay) {
// Validate screens
init: function(screens) {
var readme = 'Check readme file at https://github.com/snovakovic/wiggle for more info about configuring wiggle.';
var linkToReadme = 'Check readme file at https://github.com/snovakovic/wiggle for more info about configuring wiggle.';
if (!screens || !Array.isArray(screens)) {
throw Error('Wiggle: Missing required screens array configuration. ' + linkToReadme);
throw Error('Wiggle: Missing required screens array configuration. ' + readme);
}
screens.forEach(function(screen) {
if (typeof screen !== 'object' || !screen.name || (!screen.minWidth && !screen.maxWidth)) {
throw Error('Wiggle: Invalid screens configuration. ' + linkToReadme);
if (typeof screen !== 'object' || !screen.name
|| (!(screen.mediaQuery || screen.minWidth || screen.maxWidth))) {
throw Error('Wiggle: Invalid screens configuration. ' + readme);
}

@@ -155,5 +148,5 @@ });

return new Instance(screens, Number(resizeDelay) || 25);
return new Instance(screens);
}
}
})));
describe('Wiggle', function() {
var wiggle;
const screens = {
var screens = {
desktop: {

@@ -20,3 +20,3 @@ minWidth: 992,

function mockActiveScreen(name) {
size = screens[name].minWidth || screens[name].maxWidth;
var size = screens[name].minWidth || screens[name].maxWidth;
window.matchMedia = function(query) {

@@ -45,5 +45,5 @@ return {

expect(wiggle.on).toEqual(jasmine.any(Function));
expect(wiggle.queueOn).toEqual(jasmine.any(Function));
expect(wiggle.on.change).toEqual(jasmine.any(Function));
expect(wiggle.off).toEqual(jasmine.any(Function));
expect(wiggle.queueOff).toEqual(jasmine.any(Function));
expect(wiggle.off.change).toEqual(jasmine.any(Function));
expect(wiggle.is).toEqual(jasmine.any(Function));

@@ -108,3 +108,3 @@ });

it('queueOn/queueOff Listeners should be executed on resize', function(done) {
it('on.change/off.change Listeners should be executed on resize', function(done) {
var onDesktop = 0;

@@ -114,4 +114,4 @@ var offDesktop = 0;

// Initial screen size is on desktop
wiggle.queueOn('desktop', function() { onDesktop += 1; });
wiggle.queueOff('desktop', function() { offDesktop += 1; });
wiggle.on.change('desktop', function() { onDesktop += 1; });
wiggle.off.change('desktop', function() { offDesktop += 1; });

@@ -118,0 +118,0 @@ // Queue should not be triggered on first screen size

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc