Skip to content

Commit

Permalink
Merge pull request #28 from nemtsov/feature/vc-refactor
Browse files Browse the repository at this point in the history
Added events
  • Loading branch information
nemtsov authored Oct 4, 2016
2 parents ff538b7 + 7dd2fa8 commit 2c39d03
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 86 deletions.
2 changes: 1 addition & 1 deletion examples/simple/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import lightbox from '../../';

lightbox.init({
window.lightbox = lightbox.init({
imageSelector: '.project-image',
bgColor: '#000',
opacity: 0.7
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lightbox",
"version": "4.1.0",
"version": "4.2.0",
"description": "Image lightbox",
"main": "src",
"scripts": {
Expand All @@ -20,7 +20,7 @@
},
"homepage": "https://github.com/behance/lightbox#readme",
"dependencies": {
"idle-timer": "nemtsov/idle-timer#6061205",
"idle-timer": "git+https://github.com/nemtsov/idle-timer#8fc0007",
"jquery": "~2.1.1",
"tinycolor2": "^1.4.1"
},
Expand Down
5 changes: 3 additions & 2 deletions sass/lightbox.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ $button-padding: 40px;
position: fixed;
right: 0;
top: 0;
z-index: 1001;
z-index: 1002;
} // #lightbox-blocking

#lightbox-wrap {
Expand All @@ -35,6 +35,7 @@ $button-padding: 40px;
text-align: center;
top: 0;
width: 100%;
z-index: 1001;

.lightbox-contents {
@extend %user-select-none;
Expand Down Expand Up @@ -76,7 +77,7 @@ $button-padding: 40px;

margin: auto;
position: relative;
z-index: 1002;
z-index: 1003;

.control {
cursor: pointer;
Expand Down
90 changes: 57 additions & 33 deletions src/Chrome.js → src/ChromeView.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,47 @@ const LEFT_ARROW_KEYCODE = 37;
const RIGHT_ARROW_KEYCODE = 39;
const EXTRAS_HIDDEN_CLASS = 'extras-hidden';

export default class Chrome {
constructor(props) {
export default class ChromeView {
constructor($context, controller, props) {
this._$context = $context;
this._controller = controller;
this._props = props;
this._$view = $(lightboxTemplate);
this._$contents = this._$view.find('.js-contents');
this._bindToController();
}

init() {
const act = (name, event) => {
event.stopPropagation();
this._props[`on${name}`]();
if (event) { event.stopImmediatePropagation(); }
this._controller[name]();
};

this._props.$context
this._idleTimer = idleTimer({
callback: () => act('hideExtras'),
activeCallback: () => act('showExtras'),
idleTime: this._props.idleTimeInMs
});

this._$context
.on('click.lightbox', '.js-next', (e) => act('next', e))
.on('click.lightbox', '.js-prev', (e) => act('prev', e))
.on('click.lightbox', (e) => act('close', e));

$(document).on('keyup.lightbox', (e) => {
$(document).on('keydown.lightbox', (e) => {
switch (e.keyCode) {
case LEFT_ARROW_KEYCODE: act('prev', e); break;
case RIGHT_ARROW_KEYCODE: act('next', e); break;
case LEFT_ARROW_KEYCODE:
this._idleTimer.idle();
act('prev', e);
break;
case RIGHT_ARROW_KEYCODE:
this._idleTimer.idle();
act('next', e);
break;
case ESCAPE_KEYCODE: act('close', e); break;
}
});

this._idleTimer = idleTimer({
callback: () => this.hideExtras(),
activeCallback: () => this.showExtras(),
idleTime: this._props.idleTimeInMs
});

this._$view
.find('.js-blocking')
.css({
Expand All @@ -52,34 +61,20 @@ export default class Chrome {
.attr('fill', tinycolor(this._props.bgColor)
.isLight() ? '#000' : '#FFF');

this._props.$context.append(this._$view);
this.showExtras();

this._$context.append(this._$view);
}

renderSlide(slide) {
const picture = slide.$node.data('picture');
const src = slide.$node.data(this._props.imageSrcDataAttr);
let $content;

if (picture) {
$content = $('<picture />');
picture.sources.forEach(({ srcset, media_query: media }) => {
$('<source />', { srcset, media }).appendTo($content);
});
const { src, alt } = picture.img;
$('<img />', { src, alt }).appendTo($content);
}
else {
$content = $('<img />', { src: src });
}

this._$contents.empty().append($content);
this._$contents.html(this._getSlideContent(slide));
}

destroy() {
this._$view.remove();

$(document)
.add(this._props.$context)
.add(this._$context)
.off('.lightbox');

if (this._idleTimer) {
Expand All @@ -94,4 +89,33 @@ export default class Chrome {
showExtras() {
this._$view.removeClass(EXTRAS_HIDDEN_CLASS);
}

_bindToController() {
this._controller.on({
open: slide => { this.init(); this.renderSlide(slide); },
close: () => this.destroy(),
prev: slide => this.renderSlide(slide),
next: slide => this.renderSlide(slide),
extrasHidden: slide => this.hideExtras(slide),
extrasShown: slide => this.showExtras(slide)
});
}

_getSlideContent(slide) {
const picture = slide.$node.data('picture');
const src = slide.$node.data(this._props.imageSrcDataAttr);
let $content;
if (picture) {
$content = $('<picture />');
picture.sources.forEach(({ srcset, media_query: media }) => {
$('<source />', { srcset, media }).appendTo($content);
});
const { src, alt } = picture.img;
$('<img />', { src, alt }).appendTo($content);
}
else {
$content = $('<img />', { src: src });
}
return $content;
}
}
100 changes: 55 additions & 45 deletions src/Lightbox.js → src/Controller.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,85 @@
import $ from 'jquery';
import Chrome from './Chrome';

export default class Lightbox {
constructor(props) {
this._props = Object.assign({
context: document.body,
idleTimeInMs: 5000,
imageSelector: '.js-lightbox',
imageSrcDataAttr: 'src',
bgColor: '#fff',
opacity: '0.94',
isCircular: true
}, props);

this._$context = $(this._props.context);

export default class Controller {
constructor($context, props) {
this._props = props;
this._$context = $context;
this._$eventNode = $('<e/>');
this._$links = this._$context.find(`:not(a) > ${this._props.imageSelector}`);
this._slides = this._createSlides(this._$links);

this._chrome = new Chrome({
$context: this._$context,
onnext: () => this.next(),
onprev: () => this.prev(),
onclose: () => this.close(),
bgColor: this._props.bgColor,
opacity: this._props.opacity,
imageSrcDataAttr: this._props.imageSrcDataAttr,
idleTimeInMs: this._props.idleTimeInMs,
});

this.init();
this._bind();
}

init() {
const self = this;
this._$links.addClass('lightbox-link').click(function(e) {
e.stopPropagation();
self.open(self._slides.filter(slide => slide.$node.is(this))[0]);
});
on(eventName, cb) {
const removeEvent = func => ((e, ...args) => func.apply(null, args));
if (typeof eventName === 'object') {
Object.keys(eventName).forEach(key => eventName[key] = removeEvent(eventName[key]));
}
this._$eventNode.on(eventName, removeEvent(cb));
}

destroy() {
this._$links.removeClass('lightbox-link').off('click');
this.close();
off(eventName, cb) {
this._$eventNode.off(eventName, cb);
}

open(slide) {
this._chrome.init();
open(slideId) {
const slide = this._slides[slideId];
this._activeSlideId = slide.id;
this._chrome.renderSlide(slide);
this._trigger('open', [slide]);
}

close() {
this._chrome.destroy();
this._trigger('close');
}

next() {
const next = this._slides[this._activeSlideId + 1];
if (!this._props.isCircular && !next) { return; }

const firstId = 0;
const nextId = this._activeSlideId + 1;
if (!this._props.isCircular && !next) { return; }
this._activeSlideId = next ? nextId : firstId;
this._chrome.renderSlide(this._slides[this._activeSlideId]);
const activeSlide = this._slides[this._activeSlideId];

this._trigger('next', activeSlide);
}

prev() {
const prev = this._slides[this._activeSlideId - 1];
if (!this._props.isCircular && !prev) { return; }

const lastId = this._slides.length - 1;
const prevId = this._activeSlideId - 1;
if (!this._props.isCircular && !prev) { return; }
this._activeSlideId = prev ? prevId : lastId;
this._chrome.renderSlide(this._slides[this._activeSlideId]);
const activeSlide = this._slides[this._activeSlideId];

this._trigger('prev', activeSlide);
}

hideExtras() {
this._trigger('extrasHidden');
}

showExtras() {
this._trigger('extrasShown');
}

destroy() {
this.close();
this._$eventNode.off();
this._$links.removeClass('lightbox-link').off('click');
}

_bind() {
const self = this;
this._$links.addClass('lightbox-link').click(function(e) {
e.stopPropagation();
self.open(self._slides.filter(slide => slide.$node.is(this))[0].id);
});
}

_trigger(eventName, params) {
this._$eventNode.trigger(eventName, params);
}

_createSlides($links) {
Expand Down
20 changes: 18 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
import 'style!../sass/lightbox.scss';
import Lightbox from './Lightbox';
import $ from 'jquery';
import Controller from './Controller';
import ChromeView from './ChromeView';

export default {
init(props) {
return new Lightbox(props);
props = Object.assign({
context: document.body,
idleTimeInMs: 5000,
imageSelector: '.js-lightbox',
imageSrcDataAttr: 'src',
bgColor: '#fff',
opacity: '0.94',
isCircular: true
}, props);

const $context = $(props.context);
const controller = new Controller($context, props);
new ChromeView($context, controller, props);

return controller;
}
};
3 changes: 2 additions & 1 deletion test/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"jasmine": true
},
"globals": {
"affix": true
"affix": true,
"setFixtures": true
}
}
Loading

0 comments on commit 2c39d03

Please sign in to comment.