Browse Source

Bugfixes

pull/88/head
Jānis Skarnelis 3 years ago
parent
commit
eb71267b2b
  1. 2
      dist/carousel.css
  2. 2
      dist/carousel.esm.js
  3. 2
      dist/carousel.umd.js
  4. 2
      dist/fancybox.css
  5. 2
      dist/fancybox.esm.js
  6. 2
      dist/fancybox.umd.js
  7. 2
      dist/panzoom.css
  8. 2
      dist/panzoom.esm.js
  9. 2
      dist/panzoom.umd.js
  10. 14
      package-lock.json
  11. 2
      package.json
  12. 63
      src/Carousel/Carousel.js
  13. 4
      src/Carousel/plugins/Sync/Sync.js
  14. 10
      src/Carousel/scss/base.scss
  15. 22
      src/Fancybox/Fancybox.js
  16. 2
      src/Fancybox/plugins/Html/Html.js
  17. 0
      src/Fancybox/plugins/Html/Html.scss
  18. 6
      src/Fancybox/plugins/Image/Image.js
  19. 4
      src/Fancybox/plugins/ScrollLock/ScrollLock.js
  20. 16
      src/Fancybox/plugins/Thumbs/Thumbs.js
  21. 36
      src/Fancybox/plugins/Toolbar/Toolbar.js
  22. 2
      src/Fancybox/plugins/index.js
  23. 18
      src/Fancybox/scss/cursor.scss
  24. 139
      src/Panzoom/Panzoom.js
  25. 16
      src/Panzoom/scss/base.scss
  26. 2
      src/shared/utils/isScrollable.js
  27. 6
      tests/2_panzoom_test.js
  28. 6
      tests/3_carousel_test.js

2
dist/carousel.css

@ -1 +1 @@
.not-selectable{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.carousel{position:relative;box-sizing:border-box}.carousel *,.carousel *:before,.carousel *:after{box-sizing:inherit}.carousel__viewport{position:relative;overflow:hidden;max-width:100%;max-height:100%}.carousel__track{display:flex}.carousel__slide{flex:0 0 auto;width:var(--carousel-slide-width, 60%);max-width:100%;padding:1rem;position:relative;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;touch-action:pan-y}.carousel.has-dots{margin-bottom:calc(0.5rem + 22px)}.carousel__dots{margin:0 auto;padding:0;position:absolute;top:calc(100% + 0.5rem);left:0;right:0;display:flex;justify-content:center;list-style:none;user-select:none}.carousel__dots .carousel__dot{margin:0;padding:0;display:block;position:relative;width:22px;height:22px;cursor:pointer}.carousel__dots .carousel__dot:after{content:"";width:8px;height:8px;border-radius:50%;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);background-color:currentColor;opacity:.25;transition:opacity .15s ease-in-out}.carousel__dots .carousel__dot.is-selected:after{opacity:1}.carousel__button{width:var(--carousel-button-width, 48px);height:var(--carousel-button-height, 48px);padding:0;border:0;display:flex;justify-content:center;align-items:center;pointer-events:all;cursor:pointer;color:var(--carousel-button-color, currentColor);background:var(--carousel-button-bg, transparent);border-radius:var(--carousel-button-border-radius, 50%);box-shadow:var(--carousel-button-shadow, none);transition:opacity .15s ease}.carousel__button.is-prev,.carousel__button.is-next{position:absolute;top:50%;transform:translateY(-50%)}.carousel__button.is-prev{left:10px}.carousel__button.is-next{right:10px}.carousel__button[disabled]{cursor:default;opacity:.3}.carousel__button svg{width:var(--carousel-button-svg-width, 50%);height:var(--carousel-button-svg-height, 50%);fill:none;stroke:currentColor;stroke-width:var(--carousel-button-svg-stroke-width, 1.5);stroke-linejoin:bevel;stroke-linecap:round;filter:var(--carousel-button-svg-filter, none);pointer-events:none}
.not-selectable{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}.carousel{position:relative;box-sizing:border-box}.carousel *,.carousel *:before,.carousel *:after{box-sizing:inherit}.carousel.is-draggable{cursor:move;cursor:grab}.carousel.is-dragging{cursor:move;cursor:grabbing}.carousel__viewport{position:relative;overflow:hidden;max-width:100%;max-height:100%}.carousel__track{display:flex}.carousel__slide{flex:0 0 auto;width:var(--carousel-slide-width, 60%);max-width:100%;padding:1rem;position:relative;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;touch-action:pan-y}.carousel.has-dots{margin-bottom:calc(0.5rem + 22px)}.carousel__dots{margin:0 auto;padding:0;position:absolute;top:calc(100% + 0.5rem);left:0;right:0;display:flex;justify-content:center;list-style:none;user-select:none}.carousel__dots .carousel__dot{margin:0;padding:0;display:block;position:relative;width:22px;height:22px;cursor:pointer}.carousel__dots .carousel__dot:after{content:"";width:8px;height:8px;border-radius:50%;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);background-color:currentColor;opacity:.25;transition:opacity .15s ease-in-out}.carousel__dots .carousel__dot.is-selected:after{opacity:1}.carousel__button{width:var(--carousel-button-width, 48px);height:var(--carousel-button-height, 48px);padding:0;border:0;display:flex;justify-content:center;align-items:center;pointer-events:all;cursor:pointer;color:var(--carousel-button-color, currentColor);background:var(--carousel-button-bg, transparent);border-radius:var(--carousel-button-border-radius, 50%);box-shadow:var(--carousel-button-shadow, none);transition:opacity .15s ease}.carousel__button.is-prev,.carousel__button.is-next{position:absolute;top:50%;transform:translateY(-50%)}.carousel__button.is-prev{left:10px}.carousel__button.is-next{right:10px}.carousel__button[disabled]{cursor:default;opacity:.3}.carousel__button svg{width:var(--carousel-button-svg-width, 50%);height:var(--carousel-button-svg-height, 50%);fill:none;stroke:currentColor;stroke-width:var(--carousel-button-svg-stroke-width, 1.5);stroke-linejoin:bevel;stroke-linecap:round;filter:var(--carousel-button-svg-filter, none);pointer-events:none}

2
dist/carousel.esm.js

File diff suppressed because one or more lines are too long

2
dist/carousel.umd.js

File diff suppressed because one or more lines are too long

2
dist/fancybox.css

File diff suppressed because one or more lines are too long

2
dist/fancybox.esm.js

File diff suppressed because one or more lines are too long

2
dist/fancybox.umd.js

File diff suppressed because one or more lines are too long

2
dist/panzoom.css

@ -1 +1 @@
.panzoom{position:relative;overflow:hidden}.panzoom__content{max-width:100%;max-height:100%;object-fit:contain;transform:translate3d(0, 0, 0) scale(1);transform-origin:0 0;transition:unset;touch-action:none;user-select:none}.is-draggable{cursor:move;cursor:grab}.is-dragging{cursor:grabbing}
.panzoom{position:relative;overflow:hidden;display:flex;flex-direction:column;align-items:center;justify-content:center}.panzoom__viewport{position:relative;width:100%;height:100%;min-height:1px;margin:auto}.panzoom__content{max-width:100%;max-height:100%;object-fit:contain;transform:translate3d(0, 0, 0) scale(1);transform-origin:0 0;transition:unset;touch-action:none;user-select:none}.is-draggable{cursor:move;cursor:grab}.is-dragging{cursor:grabbing}

2
dist/panzoom.esm.js

File diff suppressed because one or more lines are too long

2
dist/panzoom.umd.js

File diff suppressed because one or more lines are too long

14
package-lock.json

@ -32,7 +32,7 @@
"rollup-plugin-eslint": "^7.0.0",
"rollup-plugin-filesize": "^9.1.1",
"rollup-plugin-terser": "^7.0.2",
"sass": "1.37.5",
"sass": "1.38.0",
"sharp": "^0.28.3"
}
},
@ -7564,9 +7564,9 @@
"dev": true
},
"node_modules/sass": {
"version": "1.37.5",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.37.5.tgz",
"integrity": "sha512-Cx3ewxz9QB/ErnVIiWg2cH0kiYZ0FPvheDTVC6BsiEGBTZKKZJ1Gq5Kq6jy3PKtL6+EJ8NIoaBW/RSd2R6cZOA==",
"version": "1.38.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.38.0.tgz",
"integrity": "sha512-WBccZeMigAGKoI+NgD7Adh0ab1HUq+6BmyBUEaGxtErbUtWUevEbdgo5EZiJQofLUGcKtlNaO2IdN73AHEua5g==",
"dev": true,
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0"
@ -14785,9 +14785,9 @@
"dev": true
},
"sass": {
"version": "1.37.5",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.37.5.tgz",
"integrity": "sha512-Cx3ewxz9QB/ErnVIiWg2cH0kiYZ0FPvheDTVC6BsiEGBTZKKZJ1Gq5Kq6jy3PKtL6+EJ8NIoaBW/RSd2R6cZOA==",
"version": "1.38.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.38.0.tgz",
"integrity": "sha512-WBccZeMigAGKoI+NgD7Adh0ab1HUq+6BmyBUEaGxtErbUtWUevEbdgo5EZiJQofLUGcKtlNaO2IdN73AHEua5g==",
"dev": true,
"requires": {
"chokidar": ">=3.0.0 <4.0.0"

2
package.json

@ -80,7 +80,7 @@
"rollup-plugin-eslint": "^7.0.0",
"rollup-plugin-filesize": "^9.1.1",
"rollup-plugin-terser": "^7.0.2",
"sass": "1.37.5",
"sass": "1.38.0",
"sharp": "^0.28.3"
},
"browserslist": [

63
src/Carousel/Carousel.js

@ -102,9 +102,11 @@ export class Carousel extends Base {
this.updateMetrics();
this.initPanzoom();
this.$track.style.transform = `translate3d(${this.pages[this.page].left * -1}px, 0px, 0) scale(1)`;
this.slideTo(this.page, { friction: 0 });
this.manageSlideVisiblity();
this.initPanzoom();
this.state = "ready";
@ -167,7 +169,12 @@ export class Carousel extends Base {
}
}
/**
* Do all calculations related to slide size and paging
*/
updateMetrics() {
// Calculate content width, viewport width
// ===
let contentWidth = 0;
let indexes = [];
let lastSlideWidth;
@ -186,22 +193,19 @@ export class Carousel extends Base {
indexes.push(index);
});
let viewportWidth = this.$track.getBoundingClientRect().width;
let viewportStyles = window.getComputedStyle(this.$track);
let viewportWidth = Math.max(this.$track.offsetWidth, round(this.$track.getBoundingClientRect().width));
let viewportStyles = window.getComputedStyle(this.$track);
viewportWidth = viewportWidth - (parseFloat(viewportStyles.paddingLeft) + parseFloat(viewportStyles.paddingRight));
if (window.visualViewport) {
viewportWidth *= window.visualViewport.scale;
}
this.contentWidth = contentWidth;
this.viewportWidth = viewportWidth;
// Split slides into pages
// ===
const pages = [];
const slidesPerPage = this.option("slidesPerPage");
// Split slides into pages
if (Number.isInteger(slidesPerPage) && contentWidth > viewportWidth) {
// Fixed number of slides in the page
for (let i = 0; i < this.slides.length; i += slidesPerPage) {
@ -240,6 +244,7 @@ export class Carousel extends Base {
const shouldFill = this.option("fill");
// Calculate width and start position for each page
// ===
pages.forEach((page, index) => {
page.index = index;
page.width = page.slides.reduce((sum, slide) => sum + slide.width, 0);
@ -257,6 +262,7 @@ export class Carousel extends Base {
});
// Merge pages
// ===
const rez = [];
let prevPage;
@ -326,17 +332,12 @@ export class Carousel extends Base {
this.$track.prepend(node);
}
let width = round(node.getBoundingClientRect().width);
let width = Math.max(node.offsetWidth, round(node.getBoundingClientRect().width));
// Add left/right margin
const style = node.currentStyle || window.getComputedStyle(node);
width = width + (parseFloat(style.marginLeft) || 0) + (parseFloat(style.marginRight) || 0);
// Proportionally scale if viewport is scaled (mobile devices)
if (window.visualViewport) {
width *= window.visualViewport.scale;
}
if (node.dataset.isTestEl) {
node.remove();
}
@ -410,6 +411,7 @@ export class Carousel extends Base {
{
// Track element will be set as Panzoom $content
content: this.$track,
wrapInner: false,
resizeParent: false,
// Disable any user interaction
@ -418,9 +420,8 @@ export class Carousel extends Base {
// Right now, only horizontal navigation is supported
lockAxis: "x",
observe: "w",
//x: this.pages[this.page].left * -1,
x: this.pages[this.page].left * -1,
centerOnStart: false,
// Make `textSelection` option more easy to customize
@ -440,21 +441,21 @@ export class Carousel extends Base {
this.Panzoom.on({
// Bubble events
"*": (name, ...details) => this.trigger(`Panzoom.${name}`, ...details),
// The rest of events to be processed
afterUpdate: () => {
this.updatePage();
},
beforeTransform: this.onBeforeTransform.bind(this),
touchEnd: this.onTouchEnd.bind(this),
endAnimation: () => {
this.trigger("settle");
},
});
this.updatePanzoom();
// The contents of the slides may cause the page scroll bar to appear, so the carousel width may change
// and slides have to be repositioned
this.updateMetrics();
this.manageSlideVisiblity();
}
updatePanzoom() {
@ -492,7 +493,7 @@ export class Carousel extends Base {
const contentWidth = this.contentWidth;
const viewportWidth = this.viewportWidth;
let currentX = this.Panzoom.content.x * -1;
let currentX = this.Panzoom ? this.Panzoom.content.x * -1 : this.pages[this.page].left;
const preload = this.option("preload");
const infinite = this.option("infiniteX", this.option("infinite"));
@ -739,8 +740,8 @@ export class Carousel extends Base {
* Seamlessly flip position of infinite carousel, if needed; this way x position stays low
*/
manageInfiniteTrack() {
const contentWidth = this.Panzoom.content.width;
const viewportWidth = this.Panzoom.viewport.width;
const contentWidth = this.contentWidth;
const viewportWidth = this.viewportWidth;
if (!this.option("infiniteX", this.option("infinite")) || this.pages.length < 2 || contentWidth < viewportWidth) {
return;
@ -777,7 +778,7 @@ export class Carousel extends Base {
* Process `Panzoom.touchEnd` event; slide to next/prev page if needed
* @param {object} panzoom
*/
onTouchEnd(panzoom) {
onTouchEnd(panzoom, event) {
const dragFree = this.option("dragFree");
// If this is a quick horizontal flick, slide to next/prev slide
@ -821,14 +822,14 @@ export class Carousel extends Base {
const center = this.option("center");
if (center) {
xPos += this.Panzoom.viewport.width * 0.5;
xPos += this.viewportWidth * 0.5;
}
const interval = Math.floor(xPos / this.Panzoom.content.width);
const interval = Math.floor(xPos / this.contentWidth);
xPos -= interval * this.Panzoom.content.width;
xPos -= interval * this.contentWidth;
let slide = this.slides.find((slide) => slide.left < xPos && slide.left + slide.width > xPos);
let slide = this.slides.find((slide) => slide.left <= xPos && slide.left + slide.width > xPos);
if (slide) {
let pageIndex = this.findPageForSlide(slide.index);
@ -852,8 +853,8 @@ export class Carousel extends Base {
prevPageIndex = this.pageIndex,
pageCount = this.pages.length;
const contentWidth = this.Panzoom.content.width;
const viewportWidth = this.Panzoom.viewport.width;
const contentWidth = this.contentWidth;
const viewportWidth = this.viewportWidth;
page = ((pageIndex % pageCount) + pageCount) % pageCount;

4
src/Carousel/plugins/Sync/Sync.js

@ -45,11 +45,11 @@ export class Sync {
this.nav.options.initialSlide = this.target.options.initialPage;
this.nav.on("ready", this.onNavReady);
this.nav.on("Panzoom.click", this.onNavClick);
this.nav.on("createSlide", this.onNavCreateSlide);
this.nav.on("Panzoom.click", this.onNavClick);
this.target.on("Panzoom.afterUpdate", this.onTargetChange);
this.target.on("change", this.onTargetChange);
this.target.on("Panzoom.afterUpdate", this.onTargetChange);
}
/**

10
src/Carousel/scss/base.scss

@ -14,6 +14,16 @@
& *:after {
box-sizing: inherit;
}
&.is-draggable {
cursor: move;
cursor: grab;
}
&.is-dragging {
cursor: move;
cursor: grabbing;
}
}
.carousel__viewport {

22
src/Fancybox/Fancybox.js

@ -104,14 +104,15 @@ class Fancybox extends Base {
constructor(items, options = {}) {
super(extend(true, {}, defaults, options));
this.bindHandlers();
this.state = "init";
this.setItems(items);
this.bindHandlers();
this.attachPlugins(Fancybox.Plugins);
// "init" event marks the start of initialization and is available to plugins
this.trigger("init");
if (this.option("hideScrollbar") === true) {
@ -124,13 +125,18 @@ class Fancybox extends Base {
this.attachEvents();
// "prepare" event will trigger the creation of additional layout elements, such as thumbnails and toolbar
this.trigger("prepare");
this.state = "ready";
// "ready" event will trigger the content to load
this.trigger("ready");
// Reveal container
this.$container.setAttribute("aria-hidden", "false");
// Focus on the first focus element in this instance
this.focus();
}
@ -601,10 +607,10 @@ class Fancybox extends Base {
* @param {Event} [event] - Focus event
*/
focus(event) {
if (this.preventScrollSupported === undefined) {
if (Fancybox.preventScrollSupported === undefined) {
// Detect if .focus() method supports `preventScroll` option,
// see https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/focus
this.preventScrollSupported = (function () {
Fancybox.preventScrollSupported = (function () {
let rez = false;
document.createElement("div").focus({
@ -622,7 +628,7 @@ class Fancybox extends Base {
if (node.setActive) {
// IE/Edge
node.setActive();
} else if (this.preventScrollSupported) {
} else if (Fancybox.preventScrollSupported) {
// Modern browsers
node.focus({ preventScroll: true });
} else {
@ -745,7 +751,7 @@ class Fancybox extends Base {
return;
}
if (scrollbarWidth) {
if (scrollbarWidth > 0) {
$style = document.createElement("style");
$style.id = id;
@ -1104,7 +1110,7 @@ class Fancybox extends Base {
this.Carousel.slides.forEach((slide) => {
if (slide.$content && slide.index !== currentSlide.index) {
slide.$content.remove();
this.Carousel.trigger("removeSlide", slide);
}
});
@ -1152,7 +1158,7 @@ class Fancybox extends Base {
// `preventScroll` option is not yet supported by Safari
// https://bugs.webkit.org/show_bug.cgi?id=178583
if (this.preventScrollSupported) {
if (Fancybox.preventScrollSupported) {
$trigger.focus({ preventScroll: true });
} else {
const scrollTop = document.body.scrollTop; // Save position

2
src/Fancybox/plugins/Html/Html.js

@ -526,7 +526,7 @@ export class Html {
// This function will be repeatedly called to check
// if video iframe has been loaded to send message to start the video
const poller = () => {
if (slide.state !== "done" || !slide.$iframe.contentWindow) {
if (slide.state !== "done" || !slide.$iframe || !slide.$iframe.contentWindow) {
return;
}

0
src/Fancybox/plugins/Html/html.scss → src/Fancybox/plugins/Html/Html.scss

6
src/Fancybox/plugins/Image/Image.js

@ -154,7 +154,9 @@ export class Image {
slide.Panzoom = null;
}
delete slide.$el.dataset.imageFit;
if (slide.$el && slide.$el.dataset) {
delete slide.$el.dataset.imageFit;
}
}
/**
@ -284,6 +286,8 @@ export class Image {
viewport: slide.$wrap,
content: slide.$image,
wrapInner: false,
// Allow to select caption text
textSelection: true,

4
src/Fancybox/plugins/ScrollLock/ScrollLock.js

@ -48,7 +48,7 @@ export class ScrollLock {
updateViewport() {
const fancybox = this.fancybox,
viewport = this.viewport,
scale = viewport.scale,
scale = viewport.scale || 1,
$container = fancybox.$container;
if (!$container) {
@ -59,7 +59,7 @@ export class ScrollLock {
height = "",
transform = "";
if (Math.abs(scale - 1) > 0.1) {
if (scale - 1 > 0.1) {
width = `${viewport.width * scale}px`;
height = `${viewport.height * scale}px`;
transform = `translate3d(${viewport.offsetLeft}px, ${viewport.offsetTop}px, 0) scale(${1 / scale})`;

16
src/Fancybox/plugins/Thumbs/Thumbs.js

@ -22,21 +22,21 @@ export class Thumbs {
this.$container = null;
this.state = "init";
for (const methodName of ["onReady", "onClosing", "onKeydown"]) {
for (const methodName of ["onPrepare", "onClosing", "onKeydown"]) {
this[methodName] = this[methodName].bind(this);
}
this.events = {
ready: this.onReady,
prepare: this.onPrepare,
closing: this.onClosing,
keydown: this.onKeydown,
};
}
/**
* Process `ready` event to build the layout
* Process `prepare` event to build the layout
*/
onReady() {
onPrepare() {
// Get slides, skip if the total number is less than the minimum
const slides = this.getSlides();
@ -49,7 +49,7 @@ export class Thumbs {
this.fancybox.option("Thumbs.autoStart") === true &&
this.fancybox.Carousel.Panzoom.content.height >= this.fancybox.option("Thumbs.minScreenHeight")
) {
this.initLayout();
this.build();
}
}
@ -76,7 +76,7 @@ export class Thumbs {
/**
* Build layout and init thumbnail Carousel
*/
initLayout() {
build() {
if (this.$container) {
return;
}
@ -86,7 +86,7 @@ export class Thumbs {
$container.classList.add("fancybox__thumbs");
this.fancybox.$container.appendChild($container);
this.fancybox.$carousel.parentNode.insertBefore($container, this.fancybox.$carousel.nextSibling);
// Initialise thumbnail carousel with all slides
this.Carousel = new Carousel(
@ -173,7 +173,7 @@ export class Thumbs {
return;
}
this.initLayout();
this.build();
}
/**

36
src/Fancybox/plugins/Toolbar/Toolbar.js

@ -138,7 +138,7 @@ export class Toolbar {
for (const methodName of [
"onInit",
"onReady",
"onPrepare",
"onDone",
"onKeydown",
"onClosing",
@ -151,7 +151,7 @@ export class Toolbar {
this.events = {
init: this.onInit,
ready: this.onReady,
prepare: this.onPrepare,
done: this.onDone,
keydown: this.onKeydown,
closing: this.onClosing,
@ -200,7 +200,8 @@ export class Toolbar {
}
}
onReady() {
onPrepare() {
// Skip if disabled
if (this.state !== "init") {
return;
}
@ -211,8 +212,16 @@ export class Toolbar {
this.Slideshow = new Slideshow(this.fancybox);
if (this.fancybox.option("slideshow.autoStart") && !this.fancybox.Carousel.prevPage) {
this.Slideshow.activate();
if (!this.fancybox.Carousel.prevPage) {
if (this.fancybox.option("slideshow.autoStart")) {
this.Slideshow.activate();
}
if (this.fancybox.option("fullscreen.autoStart") && !Fullscreen.element()) {
try {
Fullscreen.activate(this.fancybox.$container);
} catch (error) {}
}
}
}
@ -359,7 +368,7 @@ export class Toolbar {
item = all_items[id];
}
if (["counter", "next", "prev", "slideshow"].includes(id) && this.fancybox.Carousel.slides.length < 2) {
if (["counter", "next", "prev", "slideshow"].includes(id) && this.fancybox.items.length < 2) {
continue;
}
@ -407,7 +416,7 @@ export class Toolbar {
}
// Add toolbar container to DOM
this.fancybox.$container.insertBefore($container, this.fancybox.$backdrop.nextSibling);
this.fancybox.$carousel.parentNode.insertBefore($container, this.fancybox.$carousel);
this.$container = $container;
}
@ -417,6 +426,8 @@ export class Toolbar {
*/
update() {
const slide = this.fancybox.getSlide();
const idx = slide.index;
const cnt = this.fancybox.items.length;
// Download links
// ====
@ -457,14 +468,11 @@ export class Toolbar {
}
for (const $el of this.fancybox.$container.querySelectorAll("[data-fancybox-count]")) {
$el.innerHTML = this.fancybox.Carousel.slides.length;
$el.innerHTML = cnt;
}
// Disable prev/next links if gallery is not infinite and reached start/end
if (!this.fancybox.option("infinite")) {
const cnt = this.fancybox.Carousel.slides.length;
const idx = slide.index;
for (const $el of this.fancybox.$container.querySelectorAll("[data-fancybox-prev]")) {
if (idx === 0) {
$el.setAttribute("disabled", "");
@ -488,12 +496,6 @@ export class Toolbar {
this.Slideshow.clearTimer();
}
if (this.$progress) {
this.$progress.remove();
}
this.$progress = null;
if (this.$container) {
this.$container.remove();
}

2
src/Fancybox/plugins/index.js

@ -9,7 +9,7 @@ export const Plugins = {
ScrollLock,
Thumbs,
Html,
Toolbar,
Image,
Hash,
Toolbar,
};

18
src/Fancybox/scss/cursor.scss

@ -1,15 +1,17 @@
.fancybox__carousel {
& .is-draggable {
&.is-draggable .fancybox__slide,
&.is-draggable .fancybox__slide .fancybox__content {
cursor: move;
cursor: grab;
}
& .is-dragging {
&.is-dragging .fancybox__slide,
&.is-dragging .fancybox__slide .fancybox__content {
cursor: move;
cursor: grabbing;
}
& .fancybox__slide:not(.has-image) .fancybox__content {
& .fancybox__slide .fancybox__content {
cursor: auto;
}
@ -20,4 +22,14 @@
& .fancybox__slide.can-zoom_out .fancybox__content {
cursor: zoom-out;
}
& .fancybox__slide.is-draggable .fancybox__content {
cursor: move;
cursor: grab;
}
& .fancybox__slide.is-dragging .fancybox__content {
cursor: move;
cursor: grabbing;
}
}

139
src/Panzoom/Panzoom.js

@ -85,10 +85,6 @@ const defaults = {
// this can also be a function which should return a number, for example:
// ratio: function() { return 1 / (window.devicePixelRatio || 1) }
ratio: 1,
// What dimension ResizeObserver should observe,
// possible values: "wh" | "w" | "h"
observe: "wh",
};
export class Panzoom extends Base {
@ -124,11 +120,12 @@ export class Panzoom extends Base {
this.trigger("ready");
if (this.option("centerOnStart") !== false) {
if (this.option("centerOnStart") === false) {
this.handleCursor();
this.state = "ready";
} else {
this.panTo({
x: 0,
y: 0,
scale: this.option("baseScale"),
friction: 0,
});
}
@ -154,19 +151,26 @@ export class Panzoom extends Base {
this.$content = $content;
const $viewport = this.option("viewport", $content.parentNode);
let $viewport = this.option("viewport") || $container.querySelector(".panzoom__viewport");
if (!$viewport && this.option("wrapInner") !== false) {
$viewport = document.createElement("div");
$viewport.classList.add("panzoom__viewport");
if (!$viewport) {
throw new Error("Panzoom: Viewport not found");
$viewport.append(...$container.childNodes);
$container.appendChild($viewport);
}
this.$viewport = $viewport;
this.$viewport = $viewport || $content.parentNode;
}
/**
* Restore instance variables to default values
*/
resetValues() {
this.updateRate = this.option("updateRate", /iPhone|iPad|iPod|Android/i.test(navigator.userAgent) ? 250 : 24);
this.container = {
width: 0,
height: 0,
@ -187,11 +191,11 @@ export class Panzoom extends Base {
height: 0,
// Current position; these values reflect CSS `transform` value
x: 0,
y: 0,
x: this.option("x", 0),
y: this.option("y", 0),
// Current scale; does not reflect CSS `transform` value
scale: 1,
scale: this.option("baseScale"),
};
// End values of current pan / zoom animation
@ -338,50 +342,7 @@ export class Panzoom extends Base {
this.$container.addEventListener("wheel", this.onWheel, { passive: false });
this.$container.addEventListener("click", this.onClick, { passive: false });
const updateRate = this.option("updateRate", /iPhone|iPad|iPod|Android/i.test(navigator.userAgent) ? 250 : 24);
this.resizeObserver = new ResizeObserver(() => {
if (!this.updateTimer) {
this.updateTimer = setTimeout(() => {
const rect = this.$container.getBoundingClientRect();
if (!rect.width && !rect.height) {
this.updateTimer = null;
return;
}
// Check to see if there are any changes
const observe = this.option("observe");
let doUpdate = false;
if (observe.includes("w") && Math.abs(rect.width - this.container.width) > 1) {
doUpdate = true;
}
if (observe.includes("h") && Math.abs(rect.height - this.container.height) > 1) {
doUpdate = true;
}
if (doUpdate) {
this.endAnimation();
this.updateMetrics();
this.panTo({
x: this.content.x,
y: this.content.y,
scale: this.option("baseScale"),
friction: 0,
});
}
this.updateTimer = null;
}, updateRate);
}
});
this.resizeObserver.observe(this.$container);
this.initObserver();
const pointerTracker = new PointerTracker(this.$container, {
start: (pointer, event) => {
@ -488,7 +449,7 @@ export class Panzoom extends Base {
this.dragOffset[this.lockAxis === "x" ? "y" : "x"] = 0;
}
this.$viewport.classList.add(this.option("draggingClass"));
this.$container.classList.add(this.option("draggingClass"));
if (!(this.transform.scale === this.option("baseScale") && this.lockAxis === "y")) {
this.dragPosition.x = this.dragStart.x + this.dragOffset.x;
@ -543,7 +504,7 @@ export class Panzoom extends Base {
this.recalculateTransform();
this.$viewport.classList.remove(this.option("draggingClass"));
this.$container.classList.remove(this.option("draggingClass"));
if (this.trigger("touchEnd", event) === false) {
return;
@ -585,6 +546,47 @@ export class Panzoom extends Base {
this.pointerTracker = pointerTracker;
}
initObserver() {
if (this.resizeObserver) {
return;
}
this.resizeObserver = new ResizeObserver(() => {
if (this.updateTimer) {
return;
}
this.updateTimer = setTimeout(() => {
const rect = this.$container.getBoundingClientRect();
if (!(rect.width && rect.height)) {
this.updateTimer = null;
return;
}
// Check to see if there are any changes
if (Math.abs(rect.width - this.container.width) > 1 || Math.abs(rect.height - this.container.height) > 1) {
if (this.isAnimating()) {
this.endAnimation();
}
this.updateMetrics();
this.panTo({
x: this.content.x,
y: this.content.y,
scale: this.option("baseScale"),
friction: 0,
});
}
this.updateTimer = null;
}, this.updateRate);
});
this.resizeObserver.observe(this.$container);
}
/**
* Restore drag related variables to default values
*/
@ -634,7 +636,9 @@ export class Panzoom extends Base {
const $content = this.$content;
const $viewport = this.$viewport;
const shouldResizeParent = this.option("resizeParent", $viewport !== $container);
const contentIsImage = this.$content instanceof HTMLImageElement;
const contentIsZoomable = this.option("zoom");
const shouldResizeParent = this.option("resizeParent", contentIsZoomable);
let origWidth = getFullWidth(this.$content);
let origHeight = getFullHeight(this.$content);
@ -650,9 +654,6 @@ export class Panzoom extends Base {
Object.assign($viewport.style, { width: "", height: "" });
}
const contentIsImage = this.$content instanceof HTMLImageElement;
const contentIsZoomable = this.option("zoom");
const ratio = this.option("ratio");
origWidth = round(origWidth * ratio);
@ -1157,13 +1158,13 @@ export class Panzoom extends Base {
}
if (
this.option("panOnlyZoomed") == true &&
this.content.width <= this.content.fitWidth &&
this.transform.scale <= this.option("baseScale") &&
this.option("panOnlyZoomed") == true
this.transform.scale <= this.option("baseScale")
) {
this.$viewport.classList.remove(draggableClass);
this.$container.classList.remove(draggableClass);
} else {
this.$viewport.classList.add(draggableClass);
this.$container.classList.add(draggableClass);
}
}

16
src/Panzoom/scss/base.scss

@ -1,6 +1,22 @@
.panzoom {
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.panzoom__viewport {
position: relative;
width: 100%;
height: 100%;
min-height: 1px;
margin: auto;
}
.panzoom__content {

2
src/shared/utils/isScrollable.js

@ -18,7 +18,7 @@ export const hasScrollbars = function (node) {
* @returns {Boolean}
*/
export const isScrollable = function (node) {
if (!node || node.classList.contains("carousel__track") || node === document.body) {
if (!node || node === document.body) {
return false;
}

6
tests/2_panzoom_test.js

@ -128,13 +128,13 @@ describe("Panzoom", function () {
await delay(300);
const contentRect = instance.$content.getBoundingClientRect();
const parentRect = instance.$content.parentNode.getBoundingClientRect();
const containerRect = instance.$container.getBoundingClientRect();
expect(contentRect.width).to.equal(180);
expect(contentRect.height).to.equal(120);
expect(contentRect.top - parentRect.top).to.equal(30);
expect(contentRect.left - parentRect.left).to.equal(0);
expect(contentRect.top - containerRect.top).to.equal(30);
expect(contentRect.left - containerRect.left).to.equal(0);
destroyInstance(instance);
});

6
tests/3_carousel_test.js

@ -234,9 +234,9 @@ describe("Carousel", function () {
});
it("flips slides when sliding infinite carousel backward from the end", async function () {
const instance = createInstance({
initialPage: 6,
});
const instance = createInstance();
instance.slideTo(6, { friction: 0 });
expect(instance.Panzoom.content.x).to.equal(160);

Loading…
Cancel
Save