Skip to content

Commit 2c39d03

Browse files
authored
Merge pull request #28 from nemtsov/feature/vc-refactor
Added events
2 parents ff538b7 + 7dd2fa8 commit 2c39d03

File tree

8 files changed

+220
-86
lines changed

8 files changed

+220
-86
lines changed

examples/simple/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import lightbox from '../../';
22

3-
lightbox.init({
3+
window.lightbox = lightbox.init({
44
imageSelector: '.project-image',
55
bgColor: '#000',
66
opacity: 0.7

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "lightbox",
3-
"version": "4.1.0",
3+
"version": "4.2.0",
44
"description": "Image lightbox",
55
"main": "src",
66
"scripts": {
@@ -20,7 +20,7 @@
2020
},
2121
"homepage": "https://github.com/behance/lightbox#readme",
2222
"dependencies": {
23-
"idle-timer": "nemtsov/idle-timer#6061205",
23+
"idle-timer": "git+https://github.com/nemtsov/idle-timer#8fc0007",
2424
"jquery": "~2.1.1",
2525
"tinycolor2": "^1.4.1"
2626
},

sass/lightbox.scss

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ $button-padding: 40px;
2323
position: fixed;
2424
right: 0;
2525
top: 0;
26-
z-index: 1001;
26+
z-index: 1002;
2727
} // #lightbox-blocking
2828

2929
#lightbox-wrap {
@@ -35,6 +35,7 @@ $button-padding: 40px;
3535
text-align: center;
3636
top: 0;
3737
width: 100%;
38+
z-index: 1001;
3839

3940
.lightbox-contents {
4041
@extend %user-select-none;
@@ -76,7 +77,7 @@ $button-padding: 40px;
7677

7778
margin: auto;
7879
position: relative;
79-
z-index: 1002;
80+
z-index: 1003;
8081

8182
.control {
8283
cursor: pointer;

src/Chrome.js src/ChromeView.js

+57-33
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,47 @@ const LEFT_ARROW_KEYCODE = 37;
88
const RIGHT_ARROW_KEYCODE = 39;
99
const EXTRAS_HIDDEN_CLASS = 'extras-hidden';
1010

11-
export default class Chrome {
12-
constructor(props) {
11+
export default class ChromeView {
12+
constructor($context, controller, props) {
13+
this._$context = $context;
14+
this._controller = controller;
1315
this._props = props;
1416
this._$view = $(lightboxTemplate);
1517
this._$contents = this._$view.find('.js-contents');
18+
this._bindToController();
1619
}
1720

1821
init() {
1922
const act = (name, event) => {
20-
event.stopPropagation();
21-
this._props[`on${name}`]();
23+
if (event) { event.stopImmediatePropagation(); }
24+
this._controller[name]();
2225
};
2326

24-
this._props.$context
27+
this._idleTimer = idleTimer({
28+
callback: () => act('hideExtras'),
29+
activeCallback: () => act('showExtras'),
30+
idleTime: this._props.idleTimeInMs
31+
});
32+
33+
this._$context
2534
.on('click.lightbox', '.js-next', (e) => act('next', e))
2635
.on('click.lightbox', '.js-prev', (e) => act('prev', e))
2736
.on('click.lightbox', (e) => act('close', e));
2837

29-
$(document).on('keyup.lightbox', (e) => {
38+
$(document).on('keydown.lightbox', (e) => {
3039
switch (e.keyCode) {
31-
case LEFT_ARROW_KEYCODE: act('prev', e); break;
32-
case RIGHT_ARROW_KEYCODE: act('next', e); break;
40+
case LEFT_ARROW_KEYCODE:
41+
this._idleTimer.idle();
42+
act('prev', e);
43+
break;
44+
case RIGHT_ARROW_KEYCODE:
45+
this._idleTimer.idle();
46+
act('next', e);
47+
break;
3348
case ESCAPE_KEYCODE: act('close', e); break;
3449
}
3550
});
3651

37-
this._idleTimer = idleTimer({
38-
callback: () => this.hideExtras(),
39-
activeCallback: () => this.showExtras(),
40-
idleTime: this._props.idleTimeInMs
41-
});
42-
4352
this._$view
4453
.find('.js-blocking')
4554
.css({
@@ -52,34 +61,20 @@ export default class Chrome {
5261
.attr('fill', tinycolor(this._props.bgColor)
5362
.isLight() ? '#000' : '#FFF');
5463

55-
this._props.$context.append(this._$view);
64+
this.showExtras();
65+
66+
this._$context.append(this._$view);
5667
}
5768

5869
renderSlide(slide) {
59-
const picture = slide.$node.data('picture');
60-
const src = slide.$node.data(this._props.imageSrcDataAttr);
61-
let $content;
62-
63-
if (picture) {
64-
$content = $('<picture />');
65-
picture.sources.forEach(({ srcset, media_query: media }) => {
66-
$('<source />', { srcset, media }).appendTo($content);
67-
});
68-
const { src, alt } = picture.img;
69-
$('<img />', { src, alt }).appendTo($content);
70-
}
71-
else {
72-
$content = $('<img />', { src: src });
73-
}
74-
75-
this._$contents.empty().append($content);
70+
this._$contents.html(this._getSlideContent(slide));
7671
}
7772

7873
destroy() {
7974
this._$view.remove();
8075

8176
$(document)
82-
.add(this._props.$context)
77+
.add(this._$context)
8378
.off('.lightbox');
8479

8580
if (this._idleTimer) {
@@ -94,4 +89,33 @@ export default class Chrome {
9489
showExtras() {
9590
this._$view.removeClass(EXTRAS_HIDDEN_CLASS);
9691
}
92+
93+
_bindToController() {
94+
this._controller.on({
95+
open: slide => { this.init(); this.renderSlide(slide); },
96+
close: () => this.destroy(),
97+
prev: slide => this.renderSlide(slide),
98+
next: slide => this.renderSlide(slide),
99+
extrasHidden: slide => this.hideExtras(slide),
100+
extrasShown: slide => this.showExtras(slide)
101+
});
102+
}
103+
104+
_getSlideContent(slide) {
105+
const picture = slide.$node.data('picture');
106+
const src = slide.$node.data(this._props.imageSrcDataAttr);
107+
let $content;
108+
if (picture) {
109+
$content = $('<picture />');
110+
picture.sources.forEach(({ srcset, media_query: media }) => {
111+
$('<source />', { srcset, media }).appendTo($content);
112+
});
113+
const { src, alt } = picture.img;
114+
$('<img />', { src, alt }).appendTo($content);
115+
}
116+
else {
117+
$content = $('<img />', { src: src });
118+
}
119+
return $content;
120+
}
97121
}

src/Lightbox.js src/Controller.js

+55-45
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,85 @@
11
import $ from 'jquery';
2-
import Chrome from './Chrome';
3-
4-
export default class Lightbox {
5-
constructor(props) {
6-
this._props = Object.assign({
7-
context: document.body,
8-
idleTimeInMs: 5000,
9-
imageSelector: '.js-lightbox',
10-
imageSrcDataAttr: 'src',
11-
bgColor: '#fff',
12-
opacity: '0.94',
13-
isCircular: true
14-
}, props);
15-
16-
this._$context = $(this._props.context);
2+
3+
export default class Controller {
4+
constructor($context, props) {
5+
this._props = props;
6+
this._$context = $context;
7+
this._$eventNode = $('<e/>');
178
this._$links = this._$context.find(`:not(a) > ${this._props.imageSelector}`);
189
this._slides = this._createSlides(this._$links);
19-
20-
this._chrome = new Chrome({
21-
$context: this._$context,
22-
onnext: () => this.next(),
23-
onprev: () => this.prev(),
24-
onclose: () => this.close(),
25-
bgColor: this._props.bgColor,
26-
opacity: this._props.opacity,
27-
imageSrcDataAttr: this._props.imageSrcDataAttr,
28-
idleTimeInMs: this._props.idleTimeInMs,
29-
});
30-
31-
this.init();
10+
this._bind();
3211
}
3312

34-
init() {
35-
const self = this;
36-
this._$links.addClass('lightbox-link').click(function(e) {
37-
e.stopPropagation();
38-
self.open(self._slides.filter(slide => slide.$node.is(this))[0]);
39-
});
13+
on(eventName, cb) {
14+
const removeEvent = func => ((e, ...args) => func.apply(null, args));
15+
if (typeof eventName === 'object') {
16+
Object.keys(eventName).forEach(key => eventName[key] = removeEvent(eventName[key]));
17+
}
18+
this._$eventNode.on(eventName, removeEvent(cb));
4019
}
4120

42-
destroy() {
43-
this._$links.removeClass('lightbox-link').off('click');
44-
this.close();
21+
off(eventName, cb) {
22+
this._$eventNode.off(eventName, cb);
4523
}
4624

47-
open(slide) {
48-
this._chrome.init();
25+
open(slideId) {
26+
const slide = this._slides[slideId];
4927
this._activeSlideId = slide.id;
50-
this._chrome.renderSlide(slide);
28+
this._trigger('open', [slide]);
5129
}
5230

5331
close() {
54-
this._chrome.destroy();
32+
this._trigger('close');
5533
}
5634

5735
next() {
5836
const next = this._slides[this._activeSlideId + 1];
37+
if (!this._props.isCircular && !next) { return; }
38+
5939
const firstId = 0;
6040
const nextId = this._activeSlideId + 1;
61-
if (!this._props.isCircular && !next) { return; }
6241
this._activeSlideId = next ? nextId : firstId;
63-
this._chrome.renderSlide(this._slides[this._activeSlideId]);
42+
const activeSlide = this._slides[this._activeSlideId];
43+
44+
this._trigger('next', activeSlide);
6445
}
6546

6647
prev() {
6748
const prev = this._slides[this._activeSlideId - 1];
49+
if (!this._props.isCircular && !prev) { return; }
50+
6851
const lastId = this._slides.length - 1;
6952
const prevId = this._activeSlideId - 1;
70-
if (!this._props.isCircular && !prev) { return; }
7153
this._activeSlideId = prev ? prevId : lastId;
72-
this._chrome.renderSlide(this._slides[this._activeSlideId]);
54+
const activeSlide = this._slides[this._activeSlideId];
55+
56+
this._trigger('prev', activeSlide);
57+
}
58+
59+
hideExtras() {
60+
this._trigger('extrasHidden');
61+
}
62+
63+
showExtras() {
64+
this._trigger('extrasShown');
65+
}
66+
67+
destroy() {
68+
this.close();
69+
this._$eventNode.off();
70+
this._$links.removeClass('lightbox-link').off('click');
71+
}
72+
73+
_bind() {
74+
const self = this;
75+
this._$links.addClass('lightbox-link').click(function(e) {
76+
e.stopPropagation();
77+
self.open(self._slides.filter(slide => slide.$node.is(this))[0].id);
78+
});
79+
}
80+
81+
_trigger(eventName, params) {
82+
this._$eventNode.trigger(eventName, params);
7383
}
7484

7585
_createSlides($links) {

src/index.js

+18-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
11
import 'style!../sass/lightbox.scss';
2-
import Lightbox from './Lightbox';
2+
import $ from 'jquery';
3+
import Controller from './Controller';
4+
import ChromeView from './ChromeView';
35

46
export default {
57
init(props) {
6-
return new Lightbox(props);
8+
props = Object.assign({
9+
context: document.body,
10+
idleTimeInMs: 5000,
11+
imageSelector: '.js-lightbox',
12+
imageSrcDataAttr: 'src',
13+
bgColor: '#fff',
14+
opacity: '0.94',
15+
isCircular: true
16+
}, props);
17+
18+
const $context = $(props.context);
19+
const controller = new Controller($context, props);
20+
new ChromeView($context, controller, props);
21+
22+
return controller;
723
}
824
};

test/.eslintrc

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"jasmine": true
55
},
66
"globals": {
7-
"affix": true
7+
"affix": true,
8+
"setFixtures": true
89
}
910
}

0 commit comments

Comments
 (0)