Socket
Socket
Sign inDemoInstall

carousel-js

Package Overview
Dependencies
243
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.1.6 to 3.0.0

src/carousel-panel.js

11

bower.json

@@ -7,3 +7,3 @@ {

],
"description": "A carousel class",
"description": "Easily implement a dynamic carousel using minimal javascript. Supports Meteor, AngularJS, React, Polymer and any CSS library, e.g. Bootstrap. ",
"moduleType": [

@@ -16,6 +16,9 @@ "amd",

"carousel",
"carousel arrows",
"carousel panels",
"carousels",
"carousel thumbnails"
"vanilla carousel",
"es6 carousel",
"carousel component",
"carousel module",
"react carousel",
"angular carousel"
],

@@ -22,0 +25,0 @@ "license": "MIT",

{
"name": "carousel-js",
"version": "2.1.6",
"description": "A carousel class",
"version": "3.0.0",
"description": "Easily implement a dynamic carousel using minimal javascript. Supports Meteor, AngularJS, React, Polymer and any CSS library, e.g. Bootstrap. ",
"repository": {

@@ -19,6 +19,9 @@ "type": "git",

"carousel",
"carousel arrows",
"carousel panels",
"carousels",
"carousel thumbnails"
"vanilla carousel",
"es6 carousel",
"carousel component",
"carousel module",
"react carousel",
"angular carousel"
],

@@ -28,7 +31,7 @@ "main": "src/carousel.js",

"lodash": "^4.6.1",
"module-js": "^3.0.1",
"module-js": "^5.4.1",
"promise": "^7.1.1"
},
"devDependencies": {
"build-tools": "^3.0.2",
"build-tools": "^3.1.0",
"sinon": "^1.17.3"

@@ -35,0 +38,0 @@ },

[![Build Status](https://travis-ci.org/mkay581/carousel-js.svg?branch=master)](https://travis-ci.org/mkay581/carousel-js)
[![npm version](https://badge.fury.io/js/carousel-js.svg)](https://badge.fury.io/js/carousel-js)
[![Bower version](https://badge.fury.io/bo/carousel-js.svg)](https://badge.fury.io/bo/carousel-js)

@@ -6,3 +8,4 @@ # Carousel

A lightweight and flexible Carousel class that allows you to build fully functional, advanced Carousels with minimal javascript and markup.
This library is built using native vanilla javascript. Which means super fast performance. Supports IE10+, all major browsers and even mobile.
This library is built using native vanilla javascript (for performance) and adheres to latest ECMAScript specs.
Supports IE10+, all major browsers and even mobile.

@@ -9,0 +12,0 @@ ## Inspiration

'use strict';
import _ from 'lodash';
import Module from 'module-js';

@@ -19,3 +18,3 @@ /**

*/
class CarouselArrows extends Module {
class CarouselArrows {

@@ -48,3 +47,2 @@ /**

super(options);
this.options = options;

@@ -181,3 +179,2 @@

}
super.destroy();
}

@@ -184,0 +181,0 @@ }

'use strict';
import _ from 'lodash';
import Module from 'module-js';
import Promise from 'promise';
import CarouselPanel from './carousel-panel';

@@ -18,3 +18,3 @@ /**

*/
class CarouselPanels extends Module {
class CarouselPanels {

@@ -24,8 +24,9 @@ /**

* @param {object} options - Options passed into instance
* @param {HTMLCollection} options.panels - The panels in which to use for the carousel (an array of photos)
* @param {string} [options.assetLoadingClass] - The CSS class that gets added to an asset when it is loading
* @param {boolean} [options.autoLoadAssets] - Whether or not to automatically load assets when active
* @param {HTMLCollection|NodeList} options.panels - The panels in which to use for the carousel (an array of photos)
* @param {string} [options.assetLoadedClass] - The CSS class that gets added to a panel el when it is loaded
* @param {string} [options.panelActiveClass] - The CSS class that gets added to an panel when it becomes active
* @param {string} [options.panelBackClass] - The CSS class that gets added to all panel elements that appear before the current panel
* @param {string} [options.panelForwardClass] - The CSS class that gets added to all panel elements that appear ahead of the current panel
* @param {CarouselPanels~onChange} [options.onChange] - When the current panel is changed
* @param {string} [options.lazyLoadAttr] - The attribute containing the url path to content that is to be lazy loaded
* @param {string} [options.lazyLoadAttr] - The lazy loading attribute
*/

@@ -36,15 +37,22 @@ constructor (options) {

panels: [],
assetLoadingClass: 'carousel-asset-loading',
autoLoadAssets: true,
assetLoadedClass: 'carousel-asset-loaded',
panelActiveClass: 'carousel-panel-active',
panelLoadedClass: 'carousel-panel-loaded',
onChange: null,
lazyLoadAttr: 'data-src'
lazyLoadAttr: 'data-src',
panelBackClass: 'carousel-panel-behind',
panelForwardClass: 'carousel-panel-ahead'
}, options);
super(options);
if (!options.panels.length) {
console.error('carousel error: no panels were passed in constructor');
} else {
this._panelModules = this._setupPanelModules(options);
}
// add forward classes initially
this._panelModules.forEach((panel) => {
panel.el.classList.add(options.panelForwardClass);
});
this.options = options;

@@ -54,5 +62,26 @@ }

/**
* Sets up the panel module instances.
* @param {Object} options - The initialization options
* @returns {Array} Returns an array of the panel instances
* @private
*/
_setupPanelModules (options) {
let modules = [];
// panels can be either an array or an HTMLCollection so we
// are doing an old-school for loop to satisify both scenarios
for (let i = 0; i < options.panels.length; i++) {
modules[i] = new CarouselPanel(options.panels[i], {
activeClass: options.panelActiveClass,
lazyLoadAttr: options.lazyLoadAttr,
assetLoadedClass: options.assetLoadedClass,
loadedClass: options.panelLoadedClass
});
}
return modules;
}
/**
* Transitions to a panel of an index.
* @param {Number} index - The index number to go to
* @memberOf CarouselPanels
* @returns {Promise}

@@ -65,3 +94,3 @@ */

errorMsg,
promise = Promise.resolve();
promise;

@@ -76,6 +105,4 @@ if (typeof index !== 'number' || index > maxIndex || index < minIndex) {

} else {
promise = this.load(index);
this._updatePanels(index);
if (this.options.autoLoadAssets) {
promise = this.loadPanelAssets(index);
}
this._currentIndex = index;

@@ -91,13 +118,34 @@ if (this.options.onChange) {

* Makes all panels inactive except for the one at the index provided.
* @param {Number} index - The new index
* @memberOf CarouselPanels
* @param {Number} toIndex - The new index
* @private
*/
_updatePanels (index) {
var panels = this.options.panels,
prevIndex = this.getCurrentIndex();
if (prevIndex !== undefined) {
panels[prevIndex].classList.remove(this.options.panelActiveClass);
_updatePanels (toIndex) {
let fromIndex = this.getCurrentIndex();
let fromPanel = this._panelModules[fromIndex];
let toPanel = this._panelModules[toIndex];
let rangePanels = [];
let toAdd = '';
let toRemove = '';
if (fromIndex > toIndex) {
// include fromIndex but not toIndex
rangePanels = this._panelModules.slice(toIndex + 1, fromIndex + 1);
toAdd = this.options.panelForwardClass;
toRemove = this.options.panelBackClass;
} else if (fromIndex < toIndex) {
rangePanels = this._panelModules.slice(fromIndex, toIndex);
toAdd = this.options.panelBackClass;
toRemove = this.options.panelForwardClass;
}
panels[index].classList.add(this.options.panelActiveClass);
rangePanels.forEach((p) => {
p.el.classList.add(toAdd);
p.el.classList.remove(toRemove);
});
if (fromPanel) {
fromPanel.hide();
}
toPanel.el.classList.remove(this.options.panelForwardClass, this.options.panelBackClass);
toPanel.show();
}

@@ -108,3 +156,2 @@

* @returns {Number} Returns the index
* @memberOf CarouselPanels
*/

@@ -117,56 +164,21 @@ getCurrentIndex () {

* Loads assets for a given panel.
* @param {Number} index - The index of the panel containing the assets to load
* @memberOf CarouselPanels
* @param {Number} idx - The index of the panel containing the assets to load
* @returns {Promise}
*/
loadPanelAssets (index) {
var options = this.options,
panel = options.panels[index],
assets = panel.querySelectorAll('[' + options.lazyLoadAttr + ']'),
loadPromises = [];
// convert NodeList to real array in order to call Array methods on it
assets = Array.prototype.slice.call(assets);
// if panel has lazy load attribute, add to loadable assets
if (panel.getAttribute(options.lazyLoadAttr)) {
assets.push(panel);
load (idx) {
let panelModule = this._panelModules[idx];
if (panelModule.loaded) {
return Promise.resolve();
}
assets.forEach(function (el) {
if (el.tagName.toLowerCase() === 'img') {
loadPromises.push(this.loadPanelImageAsset(el));
}
}, this);
return Promise.all(loadPromises);
return panelModule.load();
}
/**
* Manually lazy loads a resource using an element's data attribute.
* @param {HTMLImageElement} img - The image element to load
* @memberOf CarouselPanels
* Loads assets for a given panel.
* @deprecated since 2.1.6
* @param {Number} index - The index of the panel containing the assets to load
* @returns {Promise}
*/
loadPanelImageAsset (img) {
var src = img.getAttribute(this.options.lazyLoadAttr),
loadingClass = this.options.assetLoadingClass;
img.classList.add(loadingClass);
return new Promise(function (resolve) {
img.onload = function () {
resolve(img);
};
img.onerror = function () {
// IE 9-11 have an issue where it automatically triggers an error on some images,
// and then will immediately trigger onload() causing intermittent errors to appear
// until this is fixed or we have a workaround, we will be resolving
// even if there is an error
resolve(img);
};
img.src = src;
}).then(function() {
img.classList.remove(loadingClass);
})
.catch(function () {
img.classList.remove(loadingClass);
});
loadPanelAssets (index) {
return this.load(index);
}

@@ -176,3 +188,2 @@

* Final cleanup of instance.
* @memberOf CarouselPanels
*/

@@ -186,4 +197,8 @@ destroy () {

}
this._currentIndex = null;
super.destroy();
this._currentIndex = undefined;
this._panelModules.forEach((module) => {
module.el.classList.remove(options.panelForwardClass, options.panelBackClass);
module.destroy();
});
}

@@ -190,0 +205,0 @@ }

'use strict';
import Module from 'module-js';
import _ from 'lodash';

@@ -17,3 +16,3 @@

*/
class CarouselThumbs extends Module {
class CarouselThumbs {

@@ -36,3 +35,2 @@ /**

super(options);
this.options = options;

@@ -148,3 +146,2 @@ this._thumbnailEventListener = this.onThumbnailEvent.bind(this);

}
super.destroy();
}

@@ -151,0 +148,0 @@ }

@@ -6,3 +6,2 @@ 'use strict';

import _ from 'lodash';
import Module from 'module-js';
/**

@@ -22,2 +21,5 @@ * A callback function that fires after a new active panel is set

* @param {string} [options.panelActiveClass] - The CSS class that gets added to an panel when it becomes active
* @param {string} [options.panelLoadedClass] - The CSS class that gets added to an panel when it is fully loaded
* @param {string} [options.panelBackClass] - The CSS class that gets added to all panel elements that appear before the current panel
* @param {string} [options.panelForwardClass] - The CSS class that gets added to all panel elements that appear ahead of the current panel
* @param {Carousel~onPanelChange} [options.onPanelChange] - When the current panel is changed

@@ -30,3 +32,3 @@ * @param {string} [options.lazyLoadAttr] - The attribute containing the url path to content that is to be lazy loaded

class Carousel extends Module {
class Carousel {

@@ -55,2 +57,5 @@ /**

panelActiveClass: 'carousel-panel-active',
panelLoadedClass: 'carousel-panel-loaded',
panelBackClass: 'carousel-panel-behind',
panelForwardClass: 'carousel-panel-ahead',
onPanelChange: null,

@@ -70,5 +75,4 @@ lazyLoadAttr: 'data-src',

super(options);
this.options = options;
this.subModules = {};
this._checkForInitErrors();

@@ -80,18 +84,15 @@ this.setup();

* Sets up the carousel instance and all controls.
* @memberOf Carousel
*/
setup () {
this.subModules = this.subModules || {};
if (!this.subModules.panels) {
this.subModules.panels = this.setupPanels(this.options);
this.subModules.panels = this._setupPanels(this.options);
}
if (this.options.thumbnails.length && !this.subModules.thumbnails) {
this.subModules.thumbnails = this.setupThumbs(this.options);
this.subModules.thumbnails = this._setupThumbs(this.options);
}
if ((this.options.leftArrow || this.options.rightArrow) && !this.subModules.arrows) {
this.subModules.arrows = this.setupArrows(this.options);
this.subModules.arrows = this._setupArrows(this.options);
}

@@ -108,4 +109,5 @@

* @return {CarouselThumbs} Returns thumbnail instance
* @private
*/
setupThumbs (options) {
_setupThumbs (options) {
return new CarouselThumbs(_.extend({}, options, {

@@ -120,4 +122,5 @@ onChange: this.onThumbnailChange.bind(this)

* @return {CarouselPanels} Returns panels instance
* @private
*/
setupPanels (options) {
_setupPanels (options) {
if (options.panels.length) {

@@ -134,4 +137,5 @@ return new CarouselPanels(_.extend({}, options, {

* @return {CarouselArrows} Returns arrows instance
* @private
*/
setupArrows (options) {
_setupArrows (options) {
var internalOptions;

@@ -149,3 +153,2 @@ // make clone of original options

* @private
* @memberOf Carousel
*/

@@ -166,3 +169,2 @@ _checkForInitErrors () {

* @param {Number} index - The new index
* @memberOf Carousel
*/

@@ -186,3 +188,2 @@ onPanelChange (index) {

* @param {Number} index - The new index
* @memberOf Carousel
*/

@@ -218,3 +219,2 @@ onThumbnailChange (index) {

* @param {Number} index - The index number to go to
* @memberOf Carousel
*/

@@ -249,3 +249,2 @@ goTo (index) {

* @returns {Number} Returns the index
* @memberOf Carousel
*/

@@ -269,4 +268,15 @@ getCurrentIndex () {

}
/**
* Destroys all sub modules.
*/
destroy () {
for (let key in this.subModules) {
if (this.subModules.hasOwnProperty(key) && this.subModules[key]) {
this.subModules[key].destroy();
}
}
}
}
module.exports = Carousel;

@@ -0,3 +1,3 @@

'use strict';
var sinon = require('sinon');
var TestUtils = require('test-utils');
var CarouselArrows = require('../src/carousel-arrows');

@@ -108,3 +108,3 @@ var assert = require('assert');

assert.equal(rightArrowClickSpy.callCount, 0);
rightArrow.dispatchEvent(TestUtils.createEvent('click'));
rightArrow.click();
assert.equal(rightArrowClickSpy.callCount, 1);

@@ -123,6 +123,6 @@ arrowsView.destroy();

arrowsView.destroy();
rightArrow.dispatchEvent(TestUtils.createEvent('click'));
rightArrow.click();
assert.equal(rightArrowClickSpy.callCount, 0);
});
it('should NOT call onRightArrowClick callback when a disabled right arrow is clicked', function () {

@@ -137,7 +137,7 @@ var fixture = document.getElementById('qunit-fixture');

arrowsView.disableRightArrow();
rightArrow.dispatchEvent(TestUtils.createEvent('click'));
rightArrow.click();
assert.equal(rightArrowClickSpy.callCount, 0);
arrowsView.destroy();
});
it('should call onLeftArrowClick callback when left arrow is clicked', function () {

@@ -152,7 +152,7 @@ var fixture = document.getElementById('qunit-fixture');

assert.equal(leftArrowClickSpy.callCount, 0);
leftArrow.dispatchEvent(TestUtils.createEvent('click'));
leftArrow.click();
assert.equal(leftArrowClickSpy.callCount, 1);
arrowsView.destroy();
});
it('should NOT trigger onLeftArrowClick callback when left arrow is clicked after destruction', function () {

@@ -167,6 +167,6 @@ var fixture = document.getElementById('qunit-fixture');

arrowsView.destroy();
leftArrow.dispatchEvent(TestUtils.createEvent('click'));
leftArrow.click();
assert.equal(leftArrowClickSpy.callCount, 0);
});
it('should add disabled css class on left arrow when update() is called on first panel index', function () {

@@ -192,3 +192,3 @@ var fixture = document.getElementById('qunit-fixture');

});
it('should add disabled css class on right arrow when update() is called on last panel index', function () {

@@ -214,3 +214,3 @@ var fixture = document.getElementById('qunit-fixture');

});
it('should NOT add disabled css class to left arrow when update() is called on last panel index when there are more panels', function () {

@@ -236,3 +236,3 @@ var fixture = document.getElementById('qunit-fixture');

});
it('should NOT add disabled css class to right arrow when update() is called on first panel index when there are more panels', function () {

@@ -258,3 +258,3 @@ var fixture = document.getElementById('qunit-fixture');

});
it('should add disabled css class to both left and right arrows when update() is called on the only panel that exists', function () {

@@ -280,3 +280,3 @@ var fixture = document.getElementById('qunit-fixture');

});
it('should remove disabled css class from left arrow after updating to second panel', function () {

@@ -306,3 +306,3 @@ var fixture = document.getElementById('qunit-fixture');

});
it('should remove disabled css class from right arrow after updating to second panel after last panel', function () {

@@ -309,0 +309,0 @@ var fixture = document.getElementById('qunit-fixture');

@@ -0,46 +1,21 @@

"use strict";
var CarouselPanels = require('./../src/carousel-panels');
var CarouselPanel = require('./../src/carousel-panel');
var sinon = require('sinon');
var CarouselPanels = require('../src/carousel-panels');
var assert = require('assert');
var _ = require('lodash');
var Promise = require('promise');
describe('Carousel Panels', function () {
it('loadPanelImageAsset() passes lazy loading attribute of the the image element passed to element kit\'s load() call', function () {
var image = document.createElement('img');
var testSrc = 'blank.jpg';
image.setAttribute('data-test-src', testSrc);
var panelsView = new CarouselPanels({panels: [image], lazyLoadAttr: 'data-test-src'});
panelsView.loadPanelImageAsset(image);
image.onload(); // trigger onload immediately
assert.ok(image.src, testSrc, 'correct src is set');
panelsView.destroy();
});
var createPanelInstance = function (el) {
var panel = sinon.createStubInstance(CarouselPanel);
panel.load = sinon.stub().returns(Promise.resolve());
panel.show = sinon.stub().returns(Promise.resolve());
panel.hide = sinon.stub().returns(Promise.resolve());
panel.el = el;
return panel;
};
it('loadPanelImageAsset() should add loading class to image element initially', function () {
var image = document.createElement('img');
var imageLoadingClass = 'loading';
var panelsView = new CarouselPanels({panels: [image], assetLoadingClass: imageLoadingClass});
panelsView.loadPanelImageAsset(image);
assert.ok(image.classList.contains(imageLoadingClass), 'loading class is added initially');
panelsView.destroy();
});
it('loadPanelImageAsset() should remove loading class when image is done loading', function (done) {
var image = document.createElement('img');
var imageLoadingClass = 'loading';
var panelsView = new CarouselPanels({panels: [image], assetLoadingClass: imageLoadingClass});
panelsView.loadPanelImageAsset(image).then(function () {
assert.ok(!image.classList.contains(imageLoadingClass), 'once image is loaded, the loading class is removed');
panelsView.destroy();
done();
});
// delay following code until the loadPanelImageAssets()
// call stack has completed since it is wrapped in a Promise
_.defer(function () {
image.onload();
});
});
it('going to a panel that is an image should call loadPanelImageAsset() with that image element', function () {
var fixture = document.getElementById('qunit-fixture');
it('should pass the same index passed to goTo to the load call', function () {
var carouselEl = document.createElement('div');

@@ -55,13 +30,12 @@ var baseUrl = 'http://test/';

var images = carouselEl.getElementsByTagName('img');
var loadPanelImageAssetStub = sinon.stub(CarouselPanels.prototype, 'loadPanelImageAsset');
var panelsView = new CarouselPanels({panels: carouselEl.getElementsByTagName('img')});
panelsView.goTo(2);
assert.equal(loadPanelImageAssetStub.args[0][0], images[2], 'third image element was passed to loadPanelImageAsset() method');
loadPanelImageAssetStub.restore();
var loadSpy = sinon.stub(panelsView, 'load').returns(Promise.resolve());
var testIndex = 2;
panelsView.goTo(testIndex);
assert.equal(loadSpy.args[0][0], testIndex);
panelsView.destroy();
loadSpy.restore();
});
it('should pass all image elements inside a panel to loadPanelImageAsset() when transitioning to the panel', function () {
var fixture = document.getElementById('qunit-fixture');
it('should call Carousel Panel\'s load method appropriately', function () {
var carouselEl = document.createElement('div');

@@ -79,14 +53,212 @@ var baseUrl = 'http://test2/';

'</div>';
var loadPanelImageAssetStub = sinon.stub(CarouselPanels.prototype, 'loadPanelImageAsset');
var loadStub = sinon.stub(CarouselPanel.prototype, 'load').returns(Promise.resolve());
var panelsView = new CarouselPanels({
panels: carouselEl.getElementsByClassName('carousel-panel')
});
var images = carouselEl.getElementsByTagName('img');
panelsView.goTo(0);
assert.equal(loadPanelImageAssetStub.args[0][0], images[0], 'first panel\'s first image element was passed to loadPanelImageAsset()');
assert.equal(loadPanelImageAssetStub.args[1][0], images[1], 'first panel\'s second image element was passed to loadPanelImageAsset()');
assert.equal(loadStub.callCount, 1);
panelsView.goTo(1);
assert.equal(loadStub.callCount, 2);
panelsView.destroy();
loadPanelImageAssetStub.restore();
loadStub.restore();
});
it('should call the show method of the Carousel Panel instance that matches the index passed to the goTo()', function () {
var carouselEl = document.createElement('div');
carouselEl.innerHTML =
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>';
var panelEls = carouselEl.getElementsByClassName('carousel-panel');
var firstPanelInstance = createPanelInstance(panelEls[0]);
var secondPanelInstance = createPanelInstance(panelEls[1]);
var thirdPanelInstance = createPanelInstance(panelEls[2]);
var setupPanelModulesStub = sinon.stub(CarouselPanels.prototype, '_setupPanelModules').returns([
firstPanelInstance, secondPanelInstance, thirdPanelInstance
]);
var panelsView = new CarouselPanels({
panels: panelEls
});
return panelsView.goTo(0).then(function () {
assert.equal(firstPanelInstance.show.callCount, 1);
assert.equal(secondPanelInstance.show.callCount, 0);
return panelsView.goTo(2).then(function () {
assert.equal(thirdPanelInstance.show.callCount, 1);
assert.equal(firstPanelInstance.show.callCount, 1);
panelsView.destroy();
setupPanelModulesStub.restore();
});
});
});
it('should call the load method of the Carousel Panel instance before calling show method when goTo() is called', function () {
var carouselEl = document.createElement('div');
carouselEl.innerHTML =
'<div class="carousel-panel"></div>';
var loadStub = sinon.stub(CarouselPanel.prototype, 'load').returns(Promise.resolve());
var showStub = sinon.stub(CarouselPanel.prototype, 'show').returns(Promise.resolve());
var panelsView = new CarouselPanels({
panels: carouselEl.getElementsByClassName('carousel-panel')
});
panelsView.goTo(0);
assert.equal(loadStub.calledBefore(showStub), true);
panelsView.destroy();
showStub.restore();
loadStub.restore();
});
it('should call the hide method of previous Carousel Panel instance when calling goTo() on a new index', function () {
var carouselEl = document.createElement('div');
carouselEl.innerHTML =
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>';
var panelEls = carouselEl.getElementsByClassName('carousel-panel');
var firstPanelInstance = createPanelInstance(panelEls[0]);
var secondPanelInstance = createPanelInstance(panelEls[1]);
var thirdPanelInstance = createPanelInstance(panelEls[2]);
var setupPanelModulesStub = sinon.stub(CarouselPanels.prototype, '_setupPanelModules').returns([
firstPanelInstance, secondPanelInstance, thirdPanelInstance
]);
var panelsView = new CarouselPanels({
panels: panelEls
});
assert.equal(firstPanelInstance.hide.callCount, 0);
assert.equal(secondPanelInstance.hide.callCount, 0);
assert.equal(thirdPanelInstance.hide.callCount, 0);
return panelsView.goTo(0).then(function () {
assert.equal(firstPanelInstance.hide.callCount, 0);
assert.equal(secondPanelInstance.hide.callCount, 0);
assert.equal(thirdPanelInstance.hide.callCount, 0);
return panelsView.goTo(2).then(function () {
assert.equal(firstPanelInstance.hide.callCount, 1);
assert.equal(secondPanelInstance.hide.callCount, 0);
assert.equal(thirdPanelInstance.hide.callCount, 0);
return panelsView.goTo(1).then(function () {
assert.equal(firstPanelInstance.hide.callCount, 1);
assert.equal(secondPanelInstance.hide.callCount, 0);
assert.equal(thirdPanelInstance.hide.callCount, 1);
panelsView.destroy();
setupPanelModulesStub.restore();
})
});
});
});
it('should add a forward css class to panel element when advancing to previous one', function () {
var carouselEl = document.createElement('div');
carouselEl.innerHTML =
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>';
var panelEls = carouselEl.getElementsByClassName('carousel-panel');
var firstPanelInstance = createPanelInstance(panelEls[0]);
var secondPanelInstance = createPanelInstance(panelEls[1]);
var thirdPanelInstance = createPanelInstance(panelEls[2]);
var setupPanelModulesStub = sinon.stub(CarouselPanels.prototype, '_setupPanelModules').returns([
firstPanelInstance, secondPanelInstance, thirdPanelInstance
]);
var forwardClass = 'panel-ahead';
var panelsView = new CarouselPanels({
panels: panelEls,
panelForwardClass: forwardClass
});
assert.ok(firstPanelInstance.el.classList.contains(forwardClass));
assert.ok(secondPanelInstance.el.classList.contains(forwardClass));
assert.ok(thirdPanelInstance.el.classList.contains(forwardClass));
return panelsView.goTo(0).then(function () {
assert.ok(!firstPanelInstance.el.classList.contains(forwardClass));
assert.ok(secondPanelInstance.el.classList.contains(forwardClass));
assert.ok(thirdPanelInstance.el.classList.contains(forwardClass));
return panelsView.goTo(2).then(function () {
assert.ok(!firstPanelInstance.el.classList.contains(forwardClass));
assert.ok(!secondPanelInstance.el.classList.contains(forwardClass));
assert.ok(!thirdPanelInstance.el.classList.contains(forwardClass));
return panelsView.goTo(1).then(function () {
assert.ok(!firstPanelInstance.el.classList.contains(forwardClass));
assert.ok(!secondPanelInstance.el.classList.contains(forwardClass));
assert.ok(thirdPanelInstance.el.classList.contains(forwardClass));
return panelsView.goTo(0).then(function () {
assert.ok(!firstPanelInstance.el.classList.contains(forwardClass));
assert.ok(secondPanelInstance.el.classList.contains(forwardClass));
assert.ok(thirdPanelInstance.el.classList.contains(forwardClass));
panelsView.destroy();
setupPanelModulesStub.restore();
});
})
});
});
});
it('should add a behind css class to panel element when advancing to previous one', function () {
var carouselEl = document.createElement('div');
carouselEl.innerHTML =
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>';
var panelEls = carouselEl.getElementsByClassName('carousel-panel');
var firstPanelInstance = createPanelInstance(panelEls[0]);
var secondPanelInstance = createPanelInstance(panelEls[1]);
var thirdPanelInstance = createPanelInstance(panelEls[2]);
var setupPanelModulesStub = sinon.stub(CarouselPanels.prototype, '_setupPanelModules').returns([
firstPanelInstance, secondPanelInstance, thirdPanelInstance
]);
var behindClass = 'panel-behind';
var panelsView = new CarouselPanels({
panels: panelEls,
panelBackClass: behindClass
});
assert.ok(!firstPanelInstance.el.classList.contains(behindClass));
assert.ok(!secondPanelInstance.el.classList.contains(behindClass));
assert.ok(!thirdPanelInstance.el.classList.contains(behindClass));
return panelsView.goTo(0).then(function () {
assert.ok(!firstPanelInstance.el.classList.contains(behindClass));
assert.ok(!secondPanelInstance.el.classList.contains(behindClass));
assert.ok(!thirdPanelInstance.el.classList.contains(behindClass));
return panelsView.goTo(2).then(function () {
assert.ok(firstPanelInstance.el.classList.contains(behindClass));
assert.ok(secondPanelInstance.el.classList.contains(behindClass));
assert.ok(!thirdPanelInstance.el.classList.contains(behindClass));
return panelsView.goTo(1).then(function () {
assert.ok(firstPanelInstance.el.classList.contains(behindClass));
assert.ok(!secondPanelInstance.el.classList.contains(behindClass));
assert.ok(!thirdPanelInstance.el.classList.contains(behindClass));
return panelsView.goTo(0).then(function () {
assert.ok(!firstPanelInstance.el.classList.contains(behindClass));
assert.ok(!secondPanelInstance.el.classList.contains(behindClass));
assert.ok(!thirdPanelInstance.el.classList.contains(behindClass));
panelsView.destroy();
setupPanelModulesStub.restore();
});
})
});
});
});
it('should NOT call show() method on panel instance again if currently showing', function () {
var carouselEl = document.createElement('div');
var baseUrl = 'http://test/';
carouselEl.innerHTML =
'<img class="carousel-item" src="blank.jpg" data-src="' + baseUrl + 'c1.jpg" />' +
'<img class="carousel-item" src="blank.jpg" data-src="' + baseUrl + 'c2.jpg" />' +
'<img class="carousel-item" src="blank.jpg" data-src="' + baseUrl + 'c3.jpg" />' +
'<img class="carousel-item" src="blank.jpg" data-src="' + baseUrl + 'c4.jpg" />' +
'<img class="carousel-item" src="blank.jpg" data-src="' + baseUrl + 'c5.jpg" />';
var showCallCount = 0;
var showStub = sinon.stub(CarouselPanel.prototype, 'show').returns(Promise.resolve());
var panelsView = new CarouselPanels({panels: carouselEl.getElementsByTagName('img')});
var testIndex = 2;
panelsView.goTo(testIndex);
showCallCount++;
panelsView.goTo(testIndex);
assert.equal(showStub.callCount, showCallCount);
panelsView.destroy();
showStub.restore();
});
});

@@ -0,15 +1,62 @@

'use strict';
var sinon = require('sinon');
var Carousel = require('../src/carousel');
var CarouselArrows = require('../src/carousel-arrows');
var CarouselThumbs = require('../src/carousel-thumbs');
var CarouselPanels = require('../src/carousel-panels');
var Carousel = require('../src/carousel');
var assert = require('assert');
var TestUtils = require('test-utils');
var CarouselPanels = require('../src/carousel');
describe('Carousel', function () {
var fixture;
it('should reflect correct index when transitioning through panels', function () {
var fixture = document.getElementById('qunit-fixture');
it('should instantiate CarouselPanels with correct options when it is instantiated', function () {
var carouselEl = document.createElement('div');
var panel = document.createElement('div');
carouselEl.appendChild(panel);
var backClass = 'panel-transition-backwards-yo';
var forwardClass = 'panel-transition-forward-son';
var carousel = new Carousel({
panels: [panel],
panelBackClass: backClass,
panelForwardClass: forwardClass
});
assert.equal(carousel.subModules.panels.options.panels[0], panel);
assert.equal(carousel.subModules.panels.options.panels.length, 1);
assert.equal(carousel.subModules.panels.options.panelBackClass, backClass);
assert.equal(carousel.subModules.panels.options.panelForwardClass, forwardClass);
carousel.destroy();
});
it('should call CarouselPanels destroy on destroy()', function () {
var panelsDestroySpy = sinon.spy(CarouselPanels.prototype, 'destroy');
var carouselEl = document.createElement('div');
carouselEl.innerHTML =
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>';
var panels = carouselEl.getElementsByClassName('carousel-panel');
var carouselView = new Carousel({panels: panels});
assert.equal(panelsDestroySpy.callCount, 0);
carouselView.destroy();
assert.equal(panelsDestroySpy.callCount, 1, 'CarouselPanels destroy was called');
panelsDestroySpy.restore();
});
it('should pass first parameter of goTo() to CarouselPanels.goTo()', function () {
var carouselEl = document.createElement('div');
carouselEl.innerHTML =
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>';
var panels = carouselEl.getElementsByClassName('carousel-panel');
var carouselView = new Carousel({panels: panels});
var carouselGoToStub = sinon.stub(carouselView, 'goTo');
carouselView.goTo(2); // go to second index
assert.deepEqual(carouselGoToStub.args[0], [2]);
carouselGoToStub.restore();
carouselView.destroy();
});
it('should remove active class when calling goTo() with an index for any other panel but the current one', function () {
var carouselEl = document.createElement('div');
var activeClass = 'carousel-panel-active';

@@ -22,22 +69,60 @@ carouselEl.innerHTML =

var panels = carouselEl.getElementsByClassName('carousel-panel');
var carouselView = new Carousel({panels: panels});
carouselView.goTo(0); // go to first panel
carouselView.goTo(2); // go to third panel
assert.ok(!panels[0].classList.contains(activeClass));
carouselView.destroy();
});
it('should return CarouselPanel\'s getCurrentIndex() when getCurrentIndex() is called', function () {
var carouselEl = document.createElement('div');
carouselEl.innerHTML =
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>';
var carouselPanelsGetCurrentIndexStub = sinon.stub(CarouselPanels.prototype, 'getCurrentIndex');
var panels = carouselEl.getElementsByClassName('carousel-panel');
var carouselView = new Carousel({panels: panels});
var panelReturnValue = 2500;
carouselPanelsGetCurrentIndexStub.returns(panelReturnValue);
assert.equal(carouselView.getCurrentIndex(), panelReturnValue);
carouselView.destroy();
carouselPanelsGetCurrentIndexStub.restore();
});
it('should invoke the onPanelChange function with the index passed to goTo()', function () {
var carouselEl = document.createElement('div');
carouselEl.innerHTML =
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>';
var panels = carouselEl.getElementsByClassName('carousel-panel');
var panelChangeSpy = sinon.spy();
var carouselView = new Carousel({
panels: panels,
onPanelChange: panelChangeSpy
});
assert.equal(carouselView.getCurrentIndex(), 0, 'getCurrentIndex() returns 0 on initialize');
assert.ok(panels[0].classList.contains(activeClass), 'active class has been applied to first panel');
assert.equal(panelChangeSpy.callCount, 1, 'onPanelChange callback was fired since init auto-navigates to first panel');
carouselView.goTo(2); // go to second index
assert.equal(carouselView.getCurrentIndex(), 2, 'after transitioning to second panel, getCurrentIndex() returns 2');
assert.ok(panels[2].classList.contains(activeClass), 'active class has been applied to second panel');
assert.ok(!panels[0].classList.contains(activeClass), 'active class has been removed from first panel');
assert.deepEqual(panelChangeSpy.args[1], [2], 'onPanelChange callback was fired with the second index as its first argument');
var panelChangeCallCount = 0;
var carouselView = new Carousel({panels: panels, onPanelChange: panelChangeSpy});
panelChangeCallCount++;
// trigger false on change within CarouselPanels instance
carouselView.subModules.panels.options.onChange(2);
assert.deepEqual(panelChangeSpy.args[panelChangeCallCount], [2]);
carouselView.destroy();
});
it('should not call goTo on initialize if initialIndex is set to false or null when instantiating', function () {
var carouselEl = document.createElement('div');
var panelEl = document.createElement('div');
carouselEl.appendChild(panelEl);
var panels = carouselEl.getElementsByClassName('carousel-panel');
var carouselGoToStub = sinon.stub(Carousel.prototype, 'goTo');
var carouselView = new Carousel({panels: [panelEl], initialIndex: false});
assert.equal(carouselGoToStub.callCount, 0);
carouselView.destroy();
carouselView = new Carousel({panels: [panelEl], initialIndex: null});
assert.equal(carouselGoToStub.callCount, 0);
carouselView.destroy();
carouselGoToStub.restore();
});
it('should call goTo() with the initialIndex option that is passed into constructor', function () {
var fixture = document.getElementById('qunit-fixture');
var carouselEl = document.createElement('div');
var activeClass = 'carousel-panel-active';
carouselEl.innerHTML =

@@ -60,4 +145,3 @@ '<div class="carousel-panel"></div>' +

it('should not cause unexpected behavior when trying to transition to a panel that is already showing', function () {
var fixture = document.getElementById('qunit-fixture');
it('should NOT invoke onPanelChange callback when calling goTo() if already on the panel index', function () {
var carouselEl = document.createElement('div');

@@ -73,16 +157,8 @@ var activeClass = 'carousel-panel-active';

var panelChangeCallCount = 0;
var carouselView = new Carousel({
panels: panels,
onPanelChange: panelChangeSpy
});
var carouselView = new Carousel({panels: panels, onPanelChange: panelChangeSpy});
panelChangeCallCount++;
carouselView.goTo(2);
panelChangeCallCount++;
assert.deepEqual(panelChangeSpy.args[panelChangeCallCount - 1], [2], 'after transitioning to second panel, onPanelChange callback was fired with the second index as its first argument');
assert.equal(carouselView.getCurrentIndex(), 2, 'getCurrentIndex() returns 2');
assert.ok(panels[2].classList.contains(activeClass), 'active class has been applied to second panel');
carouselView.goTo(2);
assert.equal(panelChangeSpy.callCount, panelChangeCallCount, 'after going to the second panel again, onPanelChange callback was NOT fired twice');
assert.equal(carouselView.getCurrentIndex(), 2, 'getCurrentIndex() still returns 2');
assert.ok(panels[2].classList.contains(activeClass), 'second panel still has active class');
assert.equal(panelChangeSpy.callCount, panelChangeCallCount);
carouselView.destroy();

@@ -92,3 +168,2 @@ });

it('should not crash when showing a panel that doesn\'t exists', function () {
var fixture = document.getElementById('qunit-fixture');
var carouselEl = document.createElement('div');

@@ -130,3 +205,2 @@ var activeClass = 'carousel-panel-active';

it('next() should call goTo() with correct parameters', function () {
var fixture = document.getElementById('qunit-fixture');
var carouselEl = document.createElement('div');

@@ -151,4 +225,3 @@ carouselEl.innerHTML =

it('should NOT instantiate CarouselArrows if no left or right arrow is declared in initialize options', function () {
var fixture = document.getElementById('qunit-fixture');
var carouselArrowsInitializeStub = sinon.stub(CarouselArrows.prototype, 'initialize');
var carouselArrowsInitializeStub = sinon.stub(CarouselArrows.prototype, 'constructor');
var carouselArrowsDestroyStub = sinon.stub(CarouselArrows.prototype, 'destroy');

@@ -170,30 +243,21 @@ var carouselEl = document.createElement('div');

it('should pass arrows and panels in initialize options to CarouselArrows', function () {
var fixture = document.getElementById('qunit-fixture');
var carouselArrowsInitializeSpy = sinon.spy(CarouselArrows.prototype, 'initialize');
var carouselArrowsDestroySpy = sinon.spy(CarouselArrows.prototype, 'destroy');
it('should pass arrow elements and proper options to CarouselArrows', function () {
var carouselEl = document.createElement('div');
carouselEl.innerHTML =
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>';
var panelEl = document.createElement('div');
carouselEl.appendChild(panelEl);
var leftArrow = document.createElement('div');
var rightArrow = document.createElement('div');
var panels = carouselEl.getElementsByClassName('carousel-panel');
var carouselView = new Carousel({
panels: panels,
panels: [panelEl],
leftArrow: leftArrow,
rightArrow: rightArrow
});
assert.deepEqual(carouselArrowsInitializeSpy.args[0][0].panels, panels, 'panels were passed to carousel arrows');
assert.deepEqual(carouselArrowsInitializeSpy.args[0][0].leftArrow, leftArrow, 'left arrow is passed to carousel arrows');
assert.deepEqual(carouselArrowsInitializeSpy.args[0][0].rightArrow, rightArrow, 'right arrow was passed to carousel arrows');
assert.deepEqual(carouselView.subModules.arrows.options.panels, [panelEl], 'panels were passed to carousel arrows');
assert.deepEqual(carouselView.subModules.arrows.options.leftArrow, leftArrow, 'left arrow is passed to carousel arrows');
assert.deepEqual(carouselView.subModules.arrows.options.rightArrow, rightArrow, 'right arrow was passed to carousel arrows');
carouselView.destroy();
carouselArrowsInitializeSpy.restore();
carouselArrowsDestroySpy.restore();
});
it('should call destroy on CarouselArrows when destroy() is called', function () {
var fixture = document.getElementById('qunit-fixture');
var carouselArrowsInitializeSpy = sinon.spy(CarouselArrows.prototype, 'initialize');
var carouselArrowsInitializeSpy = sinon.spy(CarouselArrows.prototype, 'constructor');
var carouselArrowsDestroySpy = sinon.spy(CarouselArrows.prototype, 'destroy');

@@ -220,5 +284,2 @@ var carouselEl = document.createElement('div');

it('should call onLeftArrowClick when left arrow is clicked', function () {
var fixture = document.getElementById('qunit-fixture');
var carouselArrowsInitializeSpy = sinon.spy(CarouselArrows.prototype, 'initialize');
var carouselArrowsDestroySpy = sinon.spy(CarouselArrows.prototype, 'destroy');
var carouselEl = document.createElement('div');

@@ -239,37 +300,21 @@ carouselEl.innerHTML =

carouselView.goTo(1);
var clickEvent = TestUtils.createEvent('click');
var clickEvent = new Event('click');
leftArrow.dispatchEvent(clickEvent);
assert.equal(leftArrowClickSpy.args[0][0], clickEvent, 'click callback was called and passed click event');
carouselView.destroy();
carouselArrowsInitializeSpy.restore();
carouselArrowsDestroySpy.restore();
});
it('should NOT instantiate CarouselThumbs if null/undefined is passed as thumbnail option', function () {
var fixture = document.getElementById('qunit-fixture');
var carouselThumbsInitializeStub = sinon.stub(CarouselThumbs.prototype, 'initialize');
var carouselThumbsDestroyStub = sinon.stub(CarouselThumbs.prototype, 'destroy');
var carouselView = new Carousel({
thumbnails: null
});
assert.equal(carouselThumbsInitializeStub.callCount, 0);
var carouselView = new Carousel({thumbnails: null});
assert.ok(!carouselView.subModules.thumbnails);
carouselView.destroy();
carouselThumbsInitializeStub.restore();
carouselThumbsDestroyStub.restore();
});
it('should NOT instantiate CarouselThumbs if no thumbnail elements are passed', function () {
var fixture = document.getElementById('qunit-fixture');
var carouselThumbsInitializeStub = sinon.stub(CarouselThumbs.prototype, 'initialize');
var carouselThumbsDestroyStub = sinon.stub(CarouselThumbs.prototype, 'destroy');
var carouselView = new Carousel();
assert.equal(carouselThumbsInitializeStub.callCount, 0);
assert.ok(!carouselView.subModules.thumbnails);
carouselView.destroy();
carouselThumbsInitializeStub.restore();
carouselThumbsDestroyStub.restore();
});
it('should pass thumbnail elements in CarouselThumbs initialize options', function () {
var fixture = document.getElementById('qunit-fixture');
var carouselThumbsInitializeSpy = sinon.spy(CarouselThumbs.prototype, 'initialize');
var carouselEl = document.createElement('div');

@@ -282,9 +327,7 @@ carouselEl.innerHTML =

var carouselView = new Carousel({thumbnails: thumbs});
assert.deepEqual(carouselThumbsInitializeSpy.args[0][0].thumbnails, thumbs, 'thumbnails were passed to CarouselThumbs initialize');
assert.deepEqual(carouselView.subModules.thumbnails.options.thumbnails, thumbs);
carouselView.destroy();
carouselThumbsInitializeSpy.restore();
});
it('should call CarouselThumbs destroy on destroy()', function () {
var fixture = document.getElementById('qunit-fixture');
var carouselThumbsDestroySpy = sinon.spy(CarouselThumbs.prototype, 'destroy');

@@ -304,21 +347,4 @@ var carouselEl = document.createElement('div');

it('should pass first parameter of goTo() to CarouselPanels.goTo()', function () {
var fixture = document.getElementById('qunit-fixture');
var carouselEl = document.createElement('div');
carouselEl.innerHTML =
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>' +
'<div class="carousel-panel"></div>';
var panels = carouselEl.getElementsByClassName('carousel-panel');
var carouselView = new Carousel({panels: panels});
var carouselPanelsGoToStub = sinon.stub(CarouselPanels.prototype, 'goTo');
var textIndexNum = 2;
carouselView.goTo(textIndexNum); // go to second index
assert.equal(carouselPanelsGoToStub.args[0][0], textIndexNum);
carouselPanelsGoToStub.restore();
carouselView.destroy();
});
it('should pass first parameter of goTo() to CarouselThumbs.goTo()', function () {
var fixture = document.getElementById('qunit-fixture');
var carouselEl = document.createElement('div');

@@ -325,0 +351,0 @@ carouselEl.innerHTML =

var sinon = require('sinon');
var TestUtils = require('test-utils');
var CarouselThumbs = require('../src/carousel-thumbs');

@@ -24,3 +23,3 @@ var assert = require('assert');

// click second thumbnail
thumbEls[1].dispatchEvent(TestUtils.createEvent('click'));
thumbEls[1].click();
goToCallCount++;

@@ -32,3 +31,3 @@ assert.ok(thumbEls[1].classList.contains(thumbActiveClass), 'after clicking on second thumbnail, second thumbnail has active class');

// click first thumbnail
thumbEls[0].dispatchEvent(TestUtils.createEvent('click'));
thumbEls[0].click();
goToCallCount++;

@@ -40,3 +39,3 @@ assert.ok(thumbEls[0].classList.contains(thumbActiveClass), 'after clicking on first thumbnail, first thumbnail has active class');

// click third thumbnail
thumbEls[2].dispatchEvent(TestUtils.createEvent('click'));
thumbEls[2].click();
goToCallCount++;

@@ -48,3 +47,3 @@ assert.ok(thumbEls[2].classList.contains(thumbActiveClass), 'after clicking on third thumbnail, third thumbnail has active class');

// click on third panel AGAIN
thumbEls[2].dispatchEvent(TestUtils.createEvent('click'));
thumbEls[2].click();
assert.ok(thumbEls[2].classList.contains(thumbActiveClass), 'after clicking on third thumbnail AGAIN, third thumbnail still has active class');

@@ -74,9 +73,9 @@ assert.ok(!thumbEls[0].classList.contains(thumbActiveClass), 'first thumbnail does not have active class');

// click second thumbnail
thumbEls[1].dispatchEvent(TestUtils.createEvent('click'));
thumbEls[1].click();
assert.ok(!thumbEls[1].classList.contains(thumbActiveClass), 'second thumbnail does not have active class when clicked');
// click first thumbnail
thumbEls[0].dispatchEvent(TestUtils.createEvent('click'));
thumbEls[0].click();
assert.ok(!thumbEls[0].classList.contains(thumbActiveClass), 'first thumbnail does not have active class when clicked');
// click third thumbnail
thumbEls[2].dispatchEvent(TestUtils.createEvent('click'));
thumbEls[2].click();
assert.ok(!thumbEls[2].classList.contains(thumbActiveClass), 'third thumbnail does not have active class when clicked');

@@ -102,7 +101,7 @@ });

// click second thumbnail
thumbEls[1].dispatchEvent(TestUtils.createEvent('click'));
thumbEls[1].click();
// click first thumbnail
thumbEls[0].dispatchEvent(TestUtils.createEvent('click'));
thumbEls[0].click();
// click third thumbnail
thumbEls[2].dispatchEvent(TestUtils.createEvent('click'));
thumbEls[2].click();
assert.equal(goToSpy.callCount, 0);

@@ -109,0 +108,0 @@ goToSpy.restore();

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc