From d73bf086099ec47e275d239a6521b08834f6b687 Mon Sep 17 00:00:00 2001 From: Paul Straw Date: Wed, 13 Jan 2016 00:56:29 -0800 Subject: [PATCH] Add caption support. Closes #7 --- README.md | 2 ++ dist/luminous-basic.css | 18 ++++++++++++++++-- dist/luminous-basic.min.css | 2 +- dist/luminous.js | 27 ++++++++++++++++++++++++--- dist/luminous.min.js | 2 +- src/css/luminous-basic.css | 18 ++++++++++++++++-- src/js/Lightbox.js | 18 ++++++++++++++++-- src/js/Luminous.js | 5 ++++- test/lightbox.js | 12 ++++++------ 9 files changed, 86 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 29101f88..b3515acc 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,8 @@ var options = { namespace: null, // Which attribute to pull the lightbox image source from. sourceAttribute: 'href', + // Which attribute to pull the caption from, if any. + captionAttribute: null, // The event to listen to on the _trigger_ element: triggers opening. openTrigger: 'click', // The event to listen to on the _lightbox_ element: triggers closing. diff --git a/dist/luminous-basic.css b/dist/luminous-basic.css index c886b725..2e78c18c 100644 --- a/dist/luminous-basic.css +++ b/dist/luminous-basic.css @@ -39,7 +39,7 @@ } .lum-lightbox { - background: rgba(0, 0, 0, 0.5); + background: rgba(0, 0, 0, 0.6); } .lum-lightbox-inner { @@ -53,6 +53,13 @@ position: relative; } +.lum-lightbox-inner .lum-lightbox-caption { + margin: 0 auto; + color: #fff; + max-width: 700px; + text-align: center; +} + .lum-lightbox-loader { display: block; position: absolute; @@ -107,11 +114,18 @@ /* This media query makes screens less than 460px wide display in a "fullscreen"-esque mode. Users can then scroll around inside the lightbox to see the entire image. */ @media (max-width: 460px) { - .lum-lightbox-inner { + .lum-lightbox-image-wrapper { + display: block; overflow: auto; -webkit-overflow-scrolling: touch; } + .lum-lightbox-caption { + width: 100%; + position: absolute; + bottom: 0; + } + .lum-lightbox-inner img { max-width: none; max-height: none; diff --git a/dist/luminous-basic.min.css b/dist/luminous-basic.min.css index 05370673..eb713ea6 100644 --- a/dist/luminous-basic.min.css +++ b/dist/luminous-basic.min.css @@ -1 +1 @@ -@keyframes a{0%{opacity:0}to{opacity:1}}@keyframes b{0%{transform:scale(.5);opacity:0}to{transform:scale(1);opacity:1}}@keyframes c{0%{transform:translate(-50%,-50%) rotate(0)}50%{transform:translate(-50%,-50%) rotate(-180deg)}to{transform:translate(-50%,-50%) rotate(-1turn)}}@keyframes d{0%{transform:scale(1)}10%{transform:scale(1.2) translateX(6px)}25%{transform:scale(1.3) translateX(8px)}40%{transform:scale(1.2) translateX(6px)}50%{transform:scale(1)}60%{transform:scale(.8) translateX(6px)}75%{transform:scale(.7) translateX(8px)}90%{transform:scale(.8) translateX(6px)}to{transform:scale(1)}}@keyframes e{0%{transform:scale(1)}10%{transform:scale(1.2) translateX(-6px)}25%{transform:scale(1.3) translateX(-8px)}40%{transform:scale(1.2) translateX(-6px)}50%{transform:scale(1)}60%{transform:scale(.8) translateX(-6px)}75%{transform:scale(.7) translateX(-8px)}90%{transform:scale(.8) translateX(-6px)}to{transform:scale(1)}}.lum-lightbox{background:rgba(0,0,0,.5)}.lum-lightbox-inner{top:2.5%;right:2.5%;bottom:2.5%;left:2.5%}.lum-lightbox-inner img{position:relative}.lum-lightbox-loader{display:block;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:66px;height:20px;animation:c 1.8s infinite linear}.lum-lightbox-loader:after,.lum-lightbox-loader:before{content:"";display:block;width:20px;height:20px;position:absolute;top:50%;margin-top:-10px;border-radius:20px;background:hsla(0,0%,100%,.9)}.lum-lightbox-loader:before{left:0;animation:d 1.8s infinite linear}.lum-lightbox-loader:after{right:0;animation:e 1.8s infinite linear;animation-delay:-.9s}.lum-lightbox.lum-opening{animation:a .18s ease-out}.lum-lightbox.lum-opening .lum-lightbox-inner{animation:b .18s ease-out}.lum-lightbox.lum-closing{animation:a .3s ease-in;animation-direction:reverse}.lum-lightbox.lum-closing .lum-lightbox-inner{animation:b .3s ease-in;animation-direction:reverse}@media (max-width:460px){.lum-lightbox-inner{overflow:auto;-webkit-overflow-scrolling:touch}.lum-lightbox-inner img{max-width:none;max-height:none;display:block}} \ No newline at end of file +@keyframes a{0%{opacity:0}to{opacity:1}}@keyframes b{0%{transform:scale(.5);opacity:0}to{transform:scale(1);opacity:1}}@keyframes c{0%{transform:translate(-50%,-50%) rotate(0)}50%{transform:translate(-50%,-50%) rotate(-180deg)}to{transform:translate(-50%,-50%) rotate(-1turn)}}@keyframes d{0%{transform:scale(1)}10%{transform:scale(1.2) translateX(6px)}25%{transform:scale(1.3) translateX(8px)}40%{transform:scale(1.2) translateX(6px)}50%{transform:scale(1)}60%{transform:scale(.8) translateX(6px)}75%{transform:scale(.7) translateX(8px)}90%{transform:scale(.8) translateX(6px)}to{transform:scale(1)}}@keyframes e{0%{transform:scale(1)}10%{transform:scale(1.2) translateX(-6px)}25%{transform:scale(1.3) translateX(-8px)}40%{transform:scale(1.2) translateX(-6px)}50%{transform:scale(1)}60%{transform:scale(.8) translateX(-6px)}75%{transform:scale(.7) translateX(-8px)}90%{transform:scale(.8) translateX(-6px)}to{transform:scale(1)}}.lum-lightbox{background:rgba(0,0,0,.6)}.lum-lightbox-inner{top:2.5%;right:2.5%;bottom:2.5%;left:2.5%}.lum-lightbox-inner img{position:relative}.lum-lightbox-inner .lum-lightbox-caption{margin:0 auto;color:#fff;max-width:700px;text-align:center}.lum-lightbox-loader{display:block;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:66px;height:20px;animation:c 1.8s infinite linear}.lum-lightbox-loader:after,.lum-lightbox-loader:before{content:"";display:block;width:20px;height:20px;position:absolute;top:50%;margin-top:-10px;border-radius:20px;background:hsla(0,0%,100%,.9)}.lum-lightbox-loader:before{left:0;animation:d 1.8s infinite linear}.lum-lightbox-loader:after{right:0;animation:e 1.8s infinite linear;animation-delay:-.9s}.lum-lightbox.lum-opening{animation:a .18s ease-out}.lum-lightbox.lum-opening .lum-lightbox-inner{animation:b .18s ease-out}.lum-lightbox.lum-closing{animation:a .3s ease-in;animation-direction:reverse}.lum-lightbox.lum-closing .lum-lightbox-inner{animation:b .3s ease-in;animation-direction:reverse}@media (max-width:460px){.lum-lightbox-image-wrapper{display:block;overflow:auto;-webkit-overflow-scrolling:touch}.lum-lightbox-caption{width:100%;position:absolute;bottom:0}.lum-lightbox-inner img{max-width:none;max-height:none;display:block}} \ No newline at end of file diff --git a/dist/luminous.js b/dist/luminous.js index 25340740..75fa4fc6 100644 --- a/dist/luminous.js +++ b/dist/luminous.js @@ -32,7 +32,7 @@ var Lightbox = (function () { this._sizeImgWrapperEl = function () { var style = _this.imgWrapperEl.style; style.width = _this.innerEl.clientWidth + 'px'; - style.height = _this.innerEl.clientHeight + 'px'; + style.height = _this.innerEl.clientHeight - _this.captionEl.clientHeight + 'px'; }; this._completeOpen = function () { @@ -56,10 +56,12 @@ var Lightbox = (function () { var triggerEl = _options$triggerEl === undefined ? (0, _throwIfMissing2.default)() : _options$triggerEl; var _options$sourceAttrib = options.sourceAttribute; var sourceAttribute = _options$sourceAttrib === undefined ? (0, _throwIfMissing2.default)() : _options$sourceAttrib; + var _options$captionAttri = options.captionAttribute; + var captionAttribute = _options$captionAttri === undefined ? (0, _throwIfMissing2.default)() : _options$captionAttri; var _options$includeImgix = options.includeImgixJSClass; var includeImgixJSClass = _options$includeImgix === undefined ? false : _options$includeImgix; - this.settings = { namespace: namespace, parentEl: parentEl, triggerEl: triggerEl, sourceAttribute: sourceAttribute, includeImgixJSClass: includeImgixJSClass }; + this.settings = { namespace: namespace, parentEl: parentEl, triggerEl: triggerEl, sourceAttribute: sourceAttribute, captionAttribute: captionAttribute, includeImgixJSClass: includeImgixJSClass }; if (!(0, _dom.isDOMElement)(this.settings.parentEl)) { throw new TypeError('`new Lightbox` requires a DOM element passed as `parentEl`.'); @@ -109,14 +111,27 @@ var Lightbox = (function () { this.imgEl = document.createElement('img'); positionHelperEl.appendChild(this.imgEl); + this.captionEl = document.createElement('p'); + (0, _dom.addClasses)(this.captionEl, this._buildClasses('lightbox-caption')); + positionHelperEl.appendChild(this.captionEl); + this.settings.parentEl.appendChild(this.el); this._updateImgSrc(); + this._updateCaption(); if (this.settings.includeImgixJSClass) { this.imgEl.classList.add('imgix-fluid'); } } + }, { + key: '_updateCaption', + value: function _updateCaption() { + var captionAttr = this.settings.captionAttribute; + if (captionAttr) { + this.captionEl.innerText = this.settings.triggerEl.getAttribute(captionAttr); + } + } }, { key: '_updateImgSrc', value: function _updateImgSrc() { @@ -139,6 +154,7 @@ var Lightbox = (function () { // Make sure to re-set the `img` `src`, in case it's been changed // by someone/something else. this._updateImgSrc(); + this._updateCaption(); (0, _dom.addClasses)(this.el, this.openClasses); @@ -230,6 +246,10 @@ var Luminous = (function () { var // Which attribute to pull the lightbox image source from. sourceAttribute = _options$sourceAttrib === undefined ? 'href' : _options$sourceAttrib; + var _options$captionAttri = options.captionAttribute; + var + // Which attribute to pull the caption from, if any. + captionAttribute = _options$captionAttri === undefined ? null : _options$captionAttri; var _options$openTrigger = options.openTrigger; var // The event to listen to on the _trigger_ element: triggers opening. @@ -272,7 +292,7 @@ var Luminous = (function () { // section of README.md for more information. injectBaseStyles = _options$injectBaseSt === undefined ? true : _options$injectBaseSt; - this.settings = { namespace: namespace, sourceAttribute: sourceAttribute, openTrigger: openTrigger, closeTrigger: closeTrigger, closeWithEscape: closeWithEscape, closeOnScroll: closeOnScroll, appendToSelector: appendToSelector, onOpen: onOpen, onClose: onClose, includeImgixJSClass: includeImgixJSClass, injectBaseStyles: injectBaseStyles }; + this.settings = { namespace: namespace, sourceAttribute: sourceAttribute, captionAttribute: captionAttribute, openTrigger: openTrigger, closeTrigger: closeTrigger, closeWithEscape: closeWithEscape, closeOnScroll: closeOnScroll, appendToSelector: appendToSelector, onOpen: onOpen, onClose: onClose, includeImgixJSClass: includeImgixJSClass, injectBaseStyles: injectBaseStyles }; if (this.settings.injectBaseStyles) { (0, _injectBaseStylesheet2.default)(); @@ -290,6 +310,7 @@ var Luminous = (function () { parentEl: document.querySelector(this.settings.appendToSelector), triggerEl: this.trigger, sourceAttribute: this.settings.sourceAttribute, + captionAttribute: this.settings.captionAttribute, includeImgixJSClass: this.settings.includeImgixJSClass }); } diff --git a/dist/luminous.min.js b/dist/luminous.min.js index b279684a..b6ac8a00 100644 --- a/dist/luminous.min.js +++ b/dist/luminous.min.js @@ -1 +1 @@ -!function e(t,n,i){function s(o,r){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!r&&a)return a(o,!0);if(l)return l(o,!0);var u=new Error("Cannot find module '"+o+"'");throw u.code="MODULE_NOT_FOUND",u}var d=n[o]={exports:{}};t[o][0].call(d.exports,function(e){var n=t[o][1][e];return s(n?n:e)},d,d.exports,e,t,n,i)}return n[o].exports}for(var l="function"==typeof require&&require,o=0;o { let style = this.imgWrapperEl.style; style.width = `${this.innerEl.clientWidth}px` - style.height = `${this.innerEl.clientHeight}px` + style.height = `${this.innerEl.clientHeight - this.captionEl.clientHeight}px` }; + _updateCaption() { + let captionAttr = this.settings.captionAttribute; + if (captionAttr) { + this.captionEl.innerText = this.settings.triggerEl.getAttribute(captionAttr); + } + } + _updateImgSrc() { let imageURL = this.settings.triggerEl.getAttribute(this.settings.sourceAttribute); @@ -96,6 +109,7 @@ export default class Lightbox { // Make sure to re-set the `img` `src`, in case it's been changed // by someone/something else. this._updateImgSrc(); + this._updateCaption(); addClasses(this.el, this.openClasses); diff --git a/src/js/Luminous.js b/src/js/Luminous.js index 78041a23..6a70921b 100644 --- a/src/js/Luminous.js +++ b/src/js/Luminous.js @@ -24,6 +24,8 @@ export default class Luminous { namespace = null, // Which attribute to pull the lightbox image source from. sourceAttribute = 'href', + // Which attribute to pull the caption from, if any. + captionAttribute = null, // The event to listen to on the _trigger_ element: triggers opening. openTrigger = 'click', // The event to listen to on the _lightbox_ element: triggers closing. @@ -49,7 +51,7 @@ export default class Luminous { injectBaseStyles = true, } = options - this.settings = { namespace, sourceAttribute, openTrigger, closeTrigger, closeWithEscape, closeOnScroll, appendToSelector, onOpen, onClose, includeImgixJSClass, injectBaseStyles }; + this.settings = { namespace, sourceAttribute, captionAttribute, openTrigger, closeTrigger, closeWithEscape, closeOnScroll, appendToSelector, onOpen, onClose, includeImgixJSClass, injectBaseStyles }; if (this.settings.injectBaseStyles) { injectBaseStylesheet(); @@ -109,6 +111,7 @@ export default class Luminous { parentEl: document.querySelector(this.settings.appendToSelector), triggerEl: this.trigger, sourceAttribute: this.settings.sourceAttribute, + captionAttribute: this.settings.captionAttribute, includeImgixJSClass: this.settings.includeImgixJSClass, }); } diff --git a/test/lightbox.js b/test/lightbox.js index bb922710..4949d00b 100644 --- a/test/lightbox.js +++ b/test/lightbox.js @@ -32,7 +32,7 @@ describe('Lightbox', () => { expect(() => { let triggerEl = document.querySelector('.test-anchor'); - new Lightbox({namespace: 'test', parentEl: document.body, triggerEl: triggerEl, sourceAttribute: 'href'}); + new Lightbox({namespace: 'test', parentEl: document.body, triggerEl: triggerEl, sourceAttribute: 'href', captionAttribute: null}); }).not.toThrowError(); }); @@ -40,14 +40,14 @@ describe('Lightbox', () => { expect(() => { let triggerEl = document.querySelector('.test-anchor'); - new Lightbox({namespace: 'test', parentEl: '.not-an-element', triggerEl: triggerEl, sourceAttribute: 'href'}); + new Lightbox({namespace: 'test', parentEl: '.not-an-element', triggerEl: triggerEl, sourceAttribute: 'href', captionAttribute: null}); }).toThrowError(TypeError, '`new Lightbox` requires a DOM element passed as `parentEl`.'); }); it('assigns the correct class to its element', () => { let triggerEl = document.querySelector('.test-anchor'); - let lightbox = new Lightbox({namespace: 'test-namespace', parentEl: document.body, triggerEl: triggerEl, sourceAttribute: 'href'}); + let lightbox = new Lightbox({namespace: 'test-namespace', parentEl: document.body, triggerEl: triggerEl, sourceAttribute: 'href', captionAttribute: null}); lightbox.open(); lightbox.close(); @@ -61,7 +61,7 @@ describe('Lightbox', () => { let triggerEl = document.querySelector('.test-anchor'); - let lightbox = new Lightbox({namespace: 'lum', parentEl: demoDiv, triggerEl: triggerEl, sourceAttribute: 'href'}); + let lightbox = new Lightbox({namespace: 'lum', parentEl: demoDiv, triggerEl: triggerEl, sourceAttribute: 'href', captionAttribute: null}); lightbox.open(); lightbox.close(); @@ -71,7 +71,7 @@ describe('Lightbox', () => { it('cleans up its element when destroyed', () => { let triggerEl = document.querySelector('.test-anchor'); - let lightbox = new Lightbox({namespace: 'to-destroy', parentEl: document.body, triggerEl: triggerEl, sourceAttribute: 'href'}); + let lightbox = new Lightbox({namespace: 'to-destroy', parentEl: document.body, triggerEl: triggerEl, sourceAttribute: 'href', captionAttribute: null}); lightbox.open(); lightbox.close(); lightbox.destroy(); @@ -82,7 +82,7 @@ describe('Lightbox', () => { it('adds the `imgix-fluid` param if configured', () => { let triggerEl = document.querySelector('.test-anchor'); - let lightbox = new Lightbox({namespace: 'fluid', parentEl: document.body, triggerEl: triggerEl, sourceAttribute: 'href', includeImgixJSClass: true}); + let lightbox = new Lightbox({namespace: 'fluid', parentEl: document.body, triggerEl: triggerEl, sourceAttribute: 'href', captionAttribute: null, includeImgixJSClass: true}); lightbox.open(); lightbox.close();