From b55a6f3bf36a45282878fd8d886012dcbc5aa2ec Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Mon, 19 Apr 2021 14:31:53 +0200 Subject: [PATCH] Bug 28180: Add Chocolat to OPAC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See Bug 28179: Add the Chocolat gallery lightbox JS library Sponsored-by: Gerhard Sondermann Dialog e.K. (presseplus.de, presseshop.at, presseshop.ch) Signed-off-by: Rasmus Leißner --- .../opac-tmpl/lib/Chocolat/css/chocolat.css | 230 ++++++ .../opac-tmpl/lib/Chocolat/images/close.png | Bin 0 -> 1119 bytes .../lib/Chocolat/images/fullscreen-black.png | Bin 0 -> 658 bytes .../lib/Chocolat/images/fullscreen.png | Bin 0 -> 663 bytes .../opac-tmpl/lib/Chocolat/images/left.png | Bin 0 -> 1237 bytes .../opac-tmpl/lib/Chocolat/images/loader.gif | Bin 0 -> 3208 bytes .../opac-tmpl/lib/Chocolat/images/right.png | Bin 0 -> 1224 bytes .../opac-tmpl/lib/Chocolat/js/chocolat.js | 707 ++++++++++++++++++ 8 files changed, 937 insertions(+) create mode 100644 koha-tmpl/opac-tmpl/lib/Chocolat/css/chocolat.css create mode 100644 koha-tmpl/opac-tmpl/lib/Chocolat/images/close.png create mode 100644 koha-tmpl/opac-tmpl/lib/Chocolat/images/fullscreen-black.png create mode 100644 koha-tmpl/opac-tmpl/lib/Chocolat/images/fullscreen.png create mode 100644 koha-tmpl/opac-tmpl/lib/Chocolat/images/left.png create mode 100644 koha-tmpl/opac-tmpl/lib/Chocolat/images/loader.gif create mode 100644 koha-tmpl/opac-tmpl/lib/Chocolat/images/right.png create mode 100644 koha-tmpl/opac-tmpl/lib/Chocolat/js/chocolat.js diff --git a/koha-tmpl/opac-tmpl/lib/Chocolat/css/chocolat.css b/koha-tmpl/opac-tmpl/lib/Chocolat/css/chocolat.css new file mode 100644 index 00000000000..e5ad53cd1ac --- /dev/null +++ b/koha-tmpl/opac-tmpl/lib/Chocolat/css/chocolat.css @@ -0,0 +1,230 @@ +.chocolat-zoomable.chocolat-zoomed { + cursor: zoom-out; +} +.chocolat-open { + overflow: hidden; +} +.chocolat-overlay { + transition: opacity 0.4s ease, visibility 0s 0.4s ease; + height: 100%; + width: 100%; + position: fixed; + left: 0; + top: 0; + z-index: 10; + background-color: #fff; + visibility: hidden; + opacity: 0; +} +.chocolat-overlay.chocolat-visible { + transition: opacity 0.4s, visibility 0s; + visibility: visible; + opacity: 0.8; +} + +.chocolat-wrapper { + transition: opacity 0.4s ease, visibility 0s 0.4s ease; + width: 100%; + height: 100%; + position: fixed; + opacity: 0; + left: 0; + top: 0; + z-index: 16; + color: #fff; + visibility: hidden; +} +.chocolat-wrapper.chocolat-visible { + transition: opacity 0.4s, visibility 0s; + opacity: 1; + visibility: visible; +} + +.chocolat-zoomable .chocolat-img { + cursor: zoom-in; +} +.chocolat-loader { + transition: opacity 0.3s; + height: 32px; + width: 32px; + position: absolute; + left: 50%; + top: 50%; + margin-left: -16px; + margin-top: -16px; + z-index: 11; + background: url(../images/loader.gif); + opacity: 0; +} +.chocolat-loader.chocolat-visible { + opacity: 1; +} + +.chocolat-image-wrapper { + position: fixed; + width: 0px; + height: 0px; + left: 50%; + top: 50%; + z-index: 14; + text-align: left; + transform: translate(-50%, -50%); +} + +.chocolat-image-wrapper .chocolat-img { + position: absolute; + width: 100%; + height: 100%; +} +.chocolat-wrapper .chocolat-left { + width: 50px; + height: 100px; + cursor: pointer; + background: url(../images/left.png) 50% 50% no-repeat; + z-index: 17; + visibility: hidden; +} + +.chocolat-layout { + display: flex; + flex-direction: column; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; +} +.chocolat-image-canvas { + transition: opacity .2s; + opacity: 0; + flex-grow: 1; + align-self: stretch; +} +.chocolat-image-canvas.chocolat-visible { + opacity: 1; +} +.chocolat-center { + flex-grow: 1; + display: flex; + justify-content: center; + align-items: center; + user-select: none; +} + +.chocolat-wrapper .chocolat-right { + width: 50px; + height: 100px; + cursor: pointer; + background: url(../images/right.png) 50% 50% no-repeat; + z-index: 17; + visibility: hidden; +} +.chocolat-wrapper .chocolat-right.active { + visibility: visible; +} +.chocolat-wrapper .chocolat-left.active { + visibility: visible; +} +.chocolat-wrapper .chocolat-top { + height: 50px; + overflow: hidden; + z-index: 17; + flex-shrink: 0; +} +.chocolat-wrapper .chocolat-close { + width: 50px; + height: 50px; + cursor: pointer; + position: absolute; + top: 0; + right: 0; + background: url(../images/close.png) 50% 50% no-repeat; +} +.chocolat-wrapper .chocolat-bottom { + height: 40px; + font-size: 12px; + z-index: 17; + padding-left: 15px; + padding-right: 15px; + background: rgba(0, 0, 0, 0.2); + flex-shrink: 0; + display: flex; + align-items: center; + +} +.chocolat-wrapper .chocolat-set-title { + display: inline-block; + padding-right: 15px; + line-height: 1; + border-right: 1px solid rgba(255, 255, 255, 0.3); +} +.chocolat-wrapper .chocolat-pagination { + float: right; + display: inline-block; + padding-left: 15px; + padding-right: 15px; + margin-right: 15px; + /*border-right: 1px solid rgba(255, 255, 255, 0.2);*/ +} +.chocolat-wrapper .chocolat-fullscreen { + width: 16px; + height: 40px; + background: url(../images/fullscreen.png) 50% 50% no-repeat; + display: block; + cursor: pointer; + float: right; +} +.chocolat-wrapper .chocolat-description { + display: inline-block; + flex-grow: 1; + text-align: left; +} + +/* no container mode*/ +body.chocolat-open > .chocolat-overlay { + z-index: 15; +} +body.chocolat-open > .chocolat-loader { + z-index: 15; +} +body.chocolat-open > .chocolat-image-wrapper { + z-index: 17; +} + +/* container mode*/ +.chocolat-in-container .chocolat-wrapper, +.chocolat-in-container .chocolat-image-wrapper, +.chocolat-in-container .chocolat-overlay { + position: absolute; +} +.chocolat-in-container { + position: relative; +} + +.chocolat-zoomable.chocolat-zooming-in .chocolat-image-wrapper, +.chocolat-zoomable.chocolat-zooming-out .chocolat-image-wrapper { + transition: width .2s ease, height .2s ease; +} +.chocolat-zoomable.chocolat-zooming-in .chocolat-img, +.chocolat-zoomable.chocolat-zooming-out .chocolat-img { + transition: margin .2s ease; +} + +/* uncomment to hide controls when zoomed-in*/ +/* +.chocolat-zoomable .chocolat-top, +.chocolat-zoomable .chocolat-bottom, +.chocolat-zoomable .chocolat-right, +.chocolat-zoomable .chocolat-left { + transition: opacity .3s ease, visibility 0s .3s; + opacity: 1; +} + +.chocolat-zoomable.chocolat-zoomed .chocolat-top, +.chocolat-zoomable.chocolat-zoomed .chocolat-bottom, +.chocolat-zoomable.chocolat-zoomed .chocolat-right, +.chocolat-zoomable.chocolat-zoomed .chocolat-left { + visibility: hidden; + opacity: 0; +} +*/ diff --git a/koha-tmpl/opac-tmpl/lib/Chocolat/images/close.png b/koha-tmpl/opac-tmpl/lib/Chocolat/images/close.png new file mode 100644 index 0000000000000000000000000000000000000000..87631d1e68275986eff00bc4193f18ed81444a9b GIT binary patch literal 1119 zcmV-l1fctgP)KLZ*U+0v@6o#Kk zBy~|skq9maHzpVb!A%szeAFnH;fC8TlHlg{&NR8$`@v*xZFhqH4E+Z#x^m|~@B=Bh z_D6`z#6^szN*C?3dS~Xmobz%9%J006+AeKEk~$mo+Hx=)$+gd{Be=?au7%MwSKE(w z06f3j3Vfybi-4cs5CA8)JipuGe5^;gbs(z16K$puh-bj77cO@oz5`Xe6LdiQ05--e zdUr+J!EgknOF(tJ(ARjGpDr!D|DP|)O230GU?V`^?9Mg`TI*47*Ot|)F34wi|x6(8{ z6_MexaS<7&X?p50<-XgA%Cgo@;y4}^fr!X3j^mNFcH&bML#>9Dl_bfDF=m_xaRA1c zagrn_9#ifFz?&uMyHwdl0crvO%md(U-CLy~V*q2!s0P4YlA6=5=8-z0RgPoijzdJK zu^VZm`MX>9KDb3iq%O!T^znjaQLrp(D(EWEJn_mWSy^i*%f41bhJ(T2eH2CSDo**) z*}K;*rS5CsgDYU)TZ)YHY!&^XuDD6vsQJBvxK&%;q|RJFlFbh@H5$DJ0H)b1kWW&- z)M;KLZ*U+0v@6o#Kk zBy~|skq9maHzpVb!A%szeAFnH;fC8TlHlg{&NR8$`@v*xZFhqH4E+Z#x^m|~@B=Bh z_D6`z#6^szN*C?3dS~Xmobz%9%J006+AeKEk~$mo+Hx=)$+gd{Be=?au7%MwSKE(w z06f3j3Vfybi-4cs5CA8)JipuGe5^;gbs(z16K$puh-bj77cO@oz5`Xe6LdiQ05--e zdUr+J!EgknOF(tJ(ARjGpDr!D|DP|)O23rd6951J literal 0 KcmV+b0RR6000031 diff --git a/koha-tmpl/opac-tmpl/lib/Chocolat/images/fullscreen.png b/koha-tmpl/opac-tmpl/lib/Chocolat/images/fullscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..7be7be9be8ac4f4c30acb77f654057ead2deffad GIT binary patch literal 663 zcmV;I0%-k-P)KLZ*U+0v@6o#Kk zBy~|skq9maHzpVb!A%szeAFnH;fC8TlHlg{&NR8$`@v*xZFhqH4E+Z#x^m|~@B=Bh z_D6`z#6^szN*C?3dS~Xmobz%9%J006+AeKEk~$mo+Hx=)$+gd{Be=?au7%MwSKE(w z06f3j3Vfybi-4cs5CA8)JipuGe5^;gbs(z16K$puh-bj77cO@oz5`Xe6LdiQ05--e zdUr+J!EgknOF(tJ(ARjGpDr!D|DP|)O23(&4O002ovPDHLkV1jM|ACCY4 literal 0 KcmV+b0RR6000031 diff --git a/koha-tmpl/opac-tmpl/lib/Chocolat/images/left.png b/koha-tmpl/opac-tmpl/lib/Chocolat/images/left.png new file mode 100644 index 0000000000000000000000000000000000000000..185f77bd1c596a0c88dbfa1f7af82b7a077fdf9c GIT binary patch literal 1237 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 literal 0 KcmV+b0RR6000031 diff --git a/koha-tmpl/opac-tmpl/lib/Chocolat/images/right.png b/koha-tmpl/opac-tmpl/lib/Chocolat/images/right.png new file mode 100644 index 0000000000000000000000000000000000000000..5d46f36536015177bc1b6ca164c17213e235d139 GIT binary patch literal 1224 zcmV;(1ULJMP)KLZ*U+0v@6o#Kk zBy~|skq9maHzpVb!A%szeAFnH;fC8TlHlg{&NR8$`@v*xZFhqH4E+Z#x^m|~@B=Bh z_D6`z#6^szN*C?3dS~Xmobz%9%J006+AeKEk~$mo+Hx=)$+gd{Be=?au7%MwSKE(w z06f3j3Vfybi-4cs5CA8)JipuGe5^;gbs(z16K$puh-bj77cO@oz5`Xe6LdiQ05--e zdUr+J!EgknOF(tJ(ARjGpDr!D|DP|)O23o|CPYF= zf)L>$=rVZ-R6KPGgwBH3Ja~{U9SULDQ&5n{(2%)wFbRUdV~3C~tu0voKXqknOfD6C|(^C`p1oVeLaEw^&04@P%n64CHRh&qF z9E2nQPB9xTiO2nQ9E4{ECol?RK~&H`5Np7B?2!VrMM)zMl%X4Y<<@^+hgi2*hLdPf zuRa}OllkbZ4zXgg6aIa%d3K2*g;})gU>ANnM%h0t& zqtTmQulG)&Pss;Z_nO}iJ1#oibVKeFDxt*Tfo-cVIFT`rgJ zn*adl$Y!$O|CGz+u0$94B>Kcv6qae;Wt{o=vd*gC6gu z_AX4S3%u72?DL!qY;Vv-zlc<9rw&E<{R43$6N*KY*Q+=8l%tpfg6_fseyu;V6i{mvD4okxZp;4@zXt$Vo1tE0yQLWb0000 { + const handleTransitionEnd = () => { + el.removeEventListener('transitionend', handleTransitionEnd); + resolve(); + }; + + el.addEventListener('transitionend', handleTransitionEnd); + const classesBefore = el.getAttribute('class'); + const stylesBefore = el.getAttribute('style'); + triggeringFunc(); + + if (classesBefore === el.getAttribute('class') && stylesBefore === el.getAttribute('style')) { + handleTransitionEnd(); + } + + if (parseFloat(getComputedStyle(el)['transitionDuration']) === 0) { + handleTransitionEnd(); + } + }); + } + function loadImage({ + src, + srcset, + sizes + }) { + const image = new Image(); + image.src = src; + + if (srcset) { + image.srcset = srcset; + } + + if (sizes) { + image.sizes = sizes; + } + + if ('decode' in image) { + return new Promise((resolve, reject) => { + image.decode().then(() => { + resolve(image); + }).catch(() => { + reject(image); + }); + }); + } else { + return new Promise((resolve, reject) => { + image.onload = resolve(image); + image.onerror = reject(image); + }); + } + } + function fit(options) { + let height; + let width; + const { + imgHeight, + imgWidth, + containerHeight, + containerWidth, + canvasWidth, + canvasHeight, + imageSize + } = options; + const canvasRatio = canvasHeight / canvasWidth; + const containerRatio = containerHeight / containerWidth; + const imgRatio = imgHeight / imgWidth; + + if (imageSize == 'cover') { + if (imgRatio < containerRatio) { + height = containerHeight; + width = height / imgRatio; + } else { + width = containerWidth; + height = width * imgRatio; + } + } else if (imageSize == 'native') { + height = imgHeight; + width = imgWidth; + } else { + if (imgRatio > canvasRatio) { + height = canvasHeight; + width = height / imgRatio; + } else { + width = canvasWidth; + height = width * imgRatio; + } + + if (imageSize === 'scale-down' && (width >= imgWidth || height >= imgHeight)) { + width = imgWidth; + height = imgHeight; + } + } + + return { + height: height, + width: width + }; + } + function openFullScreen(wrapper) { + if (wrapper.requestFullscreen) { + return wrapper.requestFullscreen(); + } else if (wrapper.webkitRequestFullscreen) { + return wrapper.webkitRequestFullscreen(); + } else if (wrapper.msRequestFullscreen) { + return wrapper.msRequestFullscreen(); + } else { + return Promise.reject(); + } + } + function exitFullScreen() { + if (document.exitFullscreen) { + return document.exitFullscreen(); + } else if (document.webkitExitFullscreen) { + return document.webkitExitFullscreen(); + } else if (document.msExitFullscreen) { + return document.msExitFullscreen(); + } else { + return Promise.reject(); + } + } + + const defaults = { + container: document.body, + // window or element + className: undefined, + imageSize: 'scale-down', + // 'scale-down', 'contain', 'cover' or 'native' + fullScreen: false, + loop: false, + linkImages: true, + setIndex: 0, + firstImageIndex: 0, + lastImageIndex: false, + currentImageIndex: undefined, + allowZoom: true, + closeOnBackgroundClick: true, + setTitle: function () { + return ''; + }, + description: function () { + return this.images[this.settings.currentImageIndex].title; + }, + pagination: function () { + const last = this.settings.lastImageIndex + 1; + const position = this.settings.currentImageIndex + 1; + return position + '/' + last; + }, + + afterInitialize() {}, + + afterMarkup() {}, + + afterImageLoad() {}, + + afterClose() {}, + + zoomedPaddingX: function (canvasWidth, imgWidth) { + return 0; + }, + zoomedPaddingY: function (canvasHeight, imgHeight) { + return 0; + } + }; + class Chocolat { + constructor(elements, settings) { + this.settings = settings; + this.elems = {}; + this.images = []; + this.events = []; + this.state = { + fullScreenOpen: false, + initialZoomState: null, + initialized: false, + timer: false, + visible: false + }; + this._cssClasses = ['chocolat-open', 'chocolat-in-container', 'chocolat-cover', 'chocolat-zoomable', 'chocolat-zoomed', 'chocolat-zooming-in', 'chocolat-zooming-out']; + + if (NodeList.prototype.isPrototypeOf(elements) || HTMLCollection.prototype.isPrototypeOf(elements)) { + elements.forEach((el, i) => { + this.images.push({ + title: el.getAttribute('title'), + src: el.getAttribute('href'), + srcset: el.getAttribute('data-srcset'), + sizes: el.getAttribute('data-sizes') + }); + this.off(el, 'click.chocolat'); + this.on(el, 'click.chocolat', e => { + this.init(i); + e.preventDefault(); + }); + }); + } else { + this.images = elements; + } + + if (this.settings.container instanceof Element || this.settings.container instanceof HTMLElement) { + this.elems.container = this.settings.container; + } else { + this.elems.container = document.body; + } + + this.api = { + open: i => { + i = parseInt(i) || 0; + return this.init(i); + }, + close: () => { + return this.close(); + }, + next: () => { + return this.change(1); + }, + prev: () => { + return this.change(-1); + }, + goto: i => { + return this.open(i); + }, + current: () => { + return this.settings.currentImageIndex; + }, + position: () => { + return this.position(this.elems.img); + }, + destroy: () => { + return this.destroy(); + }, + set: (property, value) => { + this.settings[property] = value; + return value; + }, + get: property => { + return this.settings[property]; + }, + getElem: name => { + return this.elems[name]; + } + }; + } + + init(i) { + if (!this.state.initialized) { + this.markup(); + this.attachListeners(); + this.settings.lastImageIndex = this.images.length - 1; + this.state.initialized = true; + } + + this.settings.afterInitialize.call(this); + return this.load(i); + } + + load(index) { + if (!this.state.visible) { + this.state.visible = true; + setTimeout(() => { + this.elems.overlay.classList.add('chocolat-visible'); + this.elems.wrapper.classList.add('chocolat-visible'); + }, 0); + this.elems.container.classList.add('chocolat-open'); + } + + if (this.settings.fullScreen) { + openFullScreen(this.elems.wrapper); + } + + if (this.settings.currentImageIndex === index) { + return Promise.resolve(); + } + + let loaderTimer = setTimeout(() => { + this.elems.loader.classList.add('chocolat-visible'); + }, 1000); + let fadeOutPromise; + let image; + let fadeOutTimer = setTimeout(() => { + fadeOutTimer = undefined; + fadeOutPromise = transitionAsPromise(() => { + this.elems.imageCanvas.classList.remove('chocolat-visible'); + }, this.elems.imageCanvas); + }, 80); + return loadImage(this.images[index]).then(loadedImage => { + image = loadedImage; + + if (fadeOutTimer) { + clearTimeout(fadeOutTimer); + return Promise.resolve(); + } else { + return fadeOutPromise; + } + }).then(() => { + const nextIndex = index + 1; + + if (this.images[nextIndex] != undefined) { + loadImage(this.images[nextIndex]); + } + + this.settings.currentImageIndex = index; + this.elems.description.innerHTML = this.settings.description.call(this); + this.elems.pagination.textContent = this.settings.pagination.call(this); + this.arrows(); + return this.position(image).then(() => { + this.elems.loader.classList.remove('chocolat-visible'); + clearTimeout(loaderTimer); + return this.appear(image); + }); + }).then(() => { + this.elems.container.classList.toggle('chocolat-zoomable', this.zoomable(image, this.elems.wrapper)); + this.settings.afterImageLoad.call(this); + }); + } + + position({ + naturalHeight, + naturalWidth + }) { + const fitOptions = { + imgHeight: naturalHeight, + imgWidth: naturalWidth, + containerHeight: this.elems.container.clientHeight, + containerWidth: this.elems.container.clientWidth, + canvasWidth: this.elems.imageCanvas.clientWidth, + canvasHeight: this.elems.imageCanvas.clientHeight, + imageSize: this.settings.imageSize + }; + const { + width, + height + } = fit(fitOptions); + return transitionAsPromise(() => { + Object.assign(this.elems.imageWrapper.style, { + width: width + 'px', + height: height + 'px' + }); + }, this.elems.imageWrapper); + } + + appear(image) { + this.elems.imageWrapper.removeChild(this.elems.img); + this.elems.img = image; + this.elems.img.setAttribute('class', 'chocolat-img'); + this.elems.imageWrapper.appendChild(this.elems.img); + const fadeInPromise = transitionAsPromise(() => { + this.elems.imageCanvas.classList.add('chocolat-visible'); + }, this.elems.imageCanvas); + return fadeInPromise; + } + + change(step) { + if (!this.state.visible) { + return; + } + + if (!this.settings.linkImages) { + return; + } + + this.zoomOut(); + const requestedImage = this.settings.currentImageIndex + parseInt(step); + + if (requestedImage > this.settings.lastImageIndex) { + if (this.settings.loop) { + return this.load(this.settings.firstImageIndex); + } + } else if (requestedImage < this.settings.firstImageIndex) { + if (this.settings.loop) { + return this.load(this.settings.lastImageIndex); + } + } else { + return this.load(requestedImage); + } + } + + arrows() { + if (this.settings.loop) { + this.elems.left.classList.add('active'); + this.elems.right.classList.add('active'); + } else if (this.settings.linkImages) { + this.elems.right.classList.toggle('active', this.settings.currentImageIndex !== this.settings.lastImageIndex); + this.elems.left.classList.toggle('active', this.settings.currentImageIndex !== this.settings.firstImageIndex); + } else { + this.elems.left.classList.remove('active'); + this.elems.right.classList.remove('active'); + } + } + + close() { + if (this.state.fullScreenOpen) { + exitFullScreen(); + return; + } + + this.state.visible = false; + const promiseOverlay = transitionAsPromise(() => { + this.elems.overlay.classList.remove('chocolat-visible'); + }, this.elems.overlay); + const promiseWrapper = transitionAsPromise(() => { + this.elems.wrapper.classList.remove('chocolat-visible'); + }, this.elems.wrapper); + return Promise.all([promiseOverlay, promiseWrapper]).then(() => { + this.elems.container.classList.remove('chocolat-open'); + this.settings.afterClose.call(this); + }); + } + + destroy() { + for (let i = this.events.length - 1; i >= 0; i--) { + const { + element, + eventName + } = this.events[i]; + this.off(element, eventName); + } + + if (!this.state.initialized) { + return; + } + + if (this.state.fullScreenOpen) { + exitFullScreen(); + } + + this.settings.currentImageIndex = undefined; + this.state.visible = false; + this.state.initialized = false; + this.elems.container.classList.remove(...this._cssClasses); + this.elems.wrapper.parentNode.removeChild(this.elems.wrapper); + } + + markup() { + this.elems.container.classList.add('chocolat-open', this.settings.className); + + if (this.settings.imageSize == 'cover') { + this.elems.container.classList.add('chocolat-cover'); + } + + if (this.elems.container !== document.body) { + this.elems.container.classList.add('chocolat-in-container'); + } + + this.elems.wrapper = document.createElement('div'); + this.elems.wrapper.setAttribute('id', 'chocolat-content-' + this.settings.setIndex); + this.elems.wrapper.setAttribute('class', 'chocolat-wrapper'); + this.elems.container.appendChild(this.elems.wrapper); + this.elems.overlay = document.createElement('div'); + this.elems.overlay.setAttribute('class', 'chocolat-overlay'); + this.elems.wrapper.appendChild(this.elems.overlay); + this.elems.loader = document.createElement('div'); + this.elems.loader.setAttribute('class', 'chocolat-loader'); + this.elems.wrapper.appendChild(this.elems.loader); + this.elems.layout = document.createElement('div'); + this.elems.layout.setAttribute('class', 'chocolat-layout'); + this.elems.wrapper.appendChild(this.elems.layout); + this.elems.top = document.createElement('div'); + this.elems.top.setAttribute('class', 'chocolat-top'); + this.elems.layout.appendChild(this.elems.top); + this.elems.center = document.createElement('div'); + this.elems.center.setAttribute('class', 'chocolat-center'); + this.elems.layout.appendChild(this.elems.center); + this.elems.left = document.createElement('div'); + this.elems.left.setAttribute('class', 'chocolat-left'); + this.elems.center.appendChild(this.elems.left); + this.elems.imageCanvas = document.createElement('div'); + this.elems.imageCanvas.setAttribute('class', 'chocolat-image-canvas'); + this.elems.center.appendChild(this.elems.imageCanvas); + this.elems.imageWrapper = document.createElement('div'); + this.elems.imageWrapper.setAttribute('class', 'chocolat-image-wrapper'); + this.elems.imageCanvas.appendChild(this.elems.imageWrapper); + this.elems.img = document.createElement('img'); + this.elems.img.setAttribute('class', 'chocolat-img'); + this.elems.imageWrapper.appendChild(this.elems.img); + this.elems.right = document.createElement('div'); + this.elems.right.setAttribute('class', 'chocolat-right'); + this.elems.center.appendChild(this.elems.right); + this.elems.bottom = document.createElement('div'); + this.elems.bottom.setAttribute('class', 'chocolat-bottom'); + this.elems.layout.appendChild(this.elems.bottom); + this.elems.close = document.createElement('span'); + this.elems.close.setAttribute('class', 'chocolat-close'); + this.elems.top.appendChild(this.elems.close); + this.elems.description = document.createElement('span'); + this.elems.description.setAttribute('class', 'chocolat-description'); + this.elems.bottom.appendChild(this.elems.description); + this.elems.pagination = document.createElement('span'); + this.elems.pagination.setAttribute('class', 'chocolat-pagination'); + this.elems.bottom.appendChild(this.elems.pagination); + this.elems.setTitle = document.createElement('span'); + this.elems.setTitle.setAttribute('class', 'chocolat-set-title'); + this.elems.setTitle.textContent = this.settings.setTitle(); + this.elems.bottom.appendChild(this.elems.setTitle); + this.elems.fullscreen = document.createElement('span'); + this.elems.fullscreen.setAttribute('class', 'chocolat-fullscreen'); + this.elems.bottom.appendChild(this.elems.fullscreen); + this.settings.afterMarkup.call(this); + } + + attachListeners() { + this.off(document, 'keydown.chocolat'); + this.on(document, 'keydown.chocolat', e => { + if (this.state.initialized) { + if (e.keyCode == 37) { + this.change(-1); + } else if (e.keyCode == 39) { + this.change(1); + } else if (e.keyCode == 27) { + this.close(); + } + } + }); + const right = this.elems.wrapper.querySelector('.chocolat-right'); + this.off(right, 'click.chocolat'); + this.on(right, 'click.chocolat', () => { + this.change(+1); + }); + const left = this.elems.wrapper.querySelector('.chocolat-left'); + this.off(left, 'click.chocolat'); + this.on(left, 'click.chocolat', () => { + this.change(-1); + }); + this.off(this.elems.close, 'click.chocolat'); + this.on(this.elems.close, 'click.chocolat', this.close.bind(this)); + this.off(this.elems.fullscreen, 'click.chocolat'); + this.on(this.elems.fullscreen, 'click.chocolat', () => { + if (this.state.fullScreenOpen) { + exitFullScreen(); + return; + } + + openFullScreen(this.elems.wrapper); + }); + this.off(document, 'fullscreenchange.chocolat'); + this.on(document, 'fullscreenchange.chocolat', () => { + if (document.fullscreenElement || document.webkitCurrentFullScreenElement || document.webkitFullscreenElement) { + this.state.fullScreenOpen = true; + } else { + this.state.fullScreenOpen = false; + } + }); + this.off(document, 'webkitfullscreenchange.chocolat'); + this.on(document, 'webkitfullscreenchange.chocolat', () => { + if (document.fullscreenElement || document.webkitCurrentFullScreenElement || document.webkitFullscreenElement) { + this.state.fullScreenOpen = true; + } else { + this.state.fullScreenOpen = false; + } + }); + + if (this.settings.closeOnBackgroundClick) { + this.off(this.elems.overlay, 'click.chocolat'); + this.on(this.elems.overlay, 'click.chocolat', this.close.bind(this)); + } + + this.off(this.elems.wrapper, 'click.chocolat'); + this.on(this.elems.wrapper, 'click.chocolat', () => { + if (this.state.initialZoomState === null || !this.state.visible) { + return; + } + + this.elems.container.classList.add('chocolat-zooming-out'); + this.zoomOut().then(() => { + this.elems.container.classList.remove('chocolat-zoomed'); + this.elems.container.classList.remove('chocolat-zooming-out'); + }); + }); + this.off(this.elems.imageWrapper, 'click.chocolat'); + this.on(this.elems.imageWrapper, 'click.chocolat', e => { + if (this.state.initialZoomState === null && this.elems.container.classList.contains('chocolat-zoomable')) { + e.stopPropagation(); + this.elems.container.classList.add('chocolat-zooming-in'); + this.zoomIn(e).then(() => { + this.elems.container.classList.add('chocolat-zoomed'); + this.elems.container.classList.remove('chocolat-zooming-in'); + }); + } + }); + this.on(this.elems.wrapper, 'mousemove.chocolat', e => { + if (this.state.initialZoomState === null || !this.state.visible) { + return; + } + + const rect = this.elems.wrapper.getBoundingClientRect(); + const pos = { + top: rect.top + window.scrollY, + left: rect.left + window.scrollX + }; + const height = this.elems.wrapper.clientHeight; + const width = this.elems.wrapper.clientWidth; + const imgWidth = this.elems.img.width; + const imgHeight = this.elems.img.height; + const coord = [e.pageX - width / 2 - pos.left, e.pageY - height / 2 - pos.top]; + let mvtX = 0; + + if (imgWidth > width) { + const paddingX = this.settings.zoomedPaddingX(imgWidth, width); + mvtX = coord[0] / (width / 2); + mvtX = ((imgWidth - width) / 2 + paddingX) * mvtX; + } + + let mvtY = 0; + + if (imgHeight > height) { + const paddingY = this.settings.zoomedPaddingY(imgHeight, height); + mvtY = coord[1] / (height / 2); + mvtY = ((imgHeight - height) / 2 + paddingY) * mvtY; + } + + this.elems.img.style.marginLeft = -mvtX + 'px'; + this.elems.img.style.marginTop = -mvtY + 'px'; + }); + this.on(window, 'resize.chocolat', e => { + if (!this.state.initialized || !this.state.visible) { + return; + } + + debounce(50, () => { + const fitOptions = { + imgHeight: this.elems.img.naturalHeight, + imgWidth: this.elems.img.naturalWidth, + containerHeight: this.elems.wrapper.clientHeight, + containerWidth: this.elems.wrapper.clientWidth, + canvasWidth: this.elems.imageCanvas.clientWidth, + canvasHeight: this.elems.imageCanvas.clientHeight, + imageSize: this.settings.imageSize + }; + const { + width, + height + } = fit(fitOptions); + this.position(this.elems.img).then(() => { + this.elems.container.classList.toggle('chocolat-zoomable', this.zoomable(this.elems.img, this.elems.wrapper)); + }); + }); + }); + } + + zoomable(image, wrapper) { + const wrapperWidth = wrapper.clientWidth; + const wrapperHeight = wrapper.clientHeight; + const isImageZoomable = this.settings.allowZoom && (image.naturalWidth > wrapperWidth || image.naturalHeight > wrapperHeight) ? true : false; + const isImageStretched = image.clientWidth > image.naturalWidth || image.clientHeight > image.naturalHeight; + return isImageZoomable && !isImageStretched; + } + + zoomIn(e) { + this.state.initialZoomState = this.settings.imageSize; + this.settings.imageSize = 'native'; + return this.position(this.elems.img); + } + + zoomOut(e) { + this.settings.imageSize = this.state.initialZoomState || this.settings.imageSize; + this.state.initialZoomState = null; + this.elems.img.style.margin = 0; + return this.position(this.elems.img); + } + + on(element, eventName, cb) { + // const eventName = this.settings.setIndex + '-' + eventName + const length = this.events.push({ + element, + eventName, + cb + }); + element.addEventListener(eventName.split('.')[0], this.events[length - 1].cb); + } + + off(element, eventName) { + // const eventName = this.settings.setIndex + '-' + eventName + const index = this.events.findIndex(event => { + return event.element === element && event.eventName === eventName; + }); + + if (this.events[index]) { + element.removeEventListener(eventName.split('.')[0], this.events[index].cb); + this.events.splice(index, 1); + } + } + + } + + const instances = []; + + window.Chocolat = function (elements, options) { + const settings = Object.assign({}, defaults, { + images: [] + }, options, { + setIndex: instances.length + }); + const instance = new Chocolat(elements, settings); + instances.push(instance); + return instance; + }; + +}()); -- 2.25.1