viewerjs 1.13.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/viewer.js CHANGED
@@ -1,11 +1,11 @@
1
1
  /*!
2
- * Viewer.js v1.13.0
2
+ * Viewer.js v1.14.0
3
3
  * https://fengyuanchen.github.io/viewerjs
4
4
  *
5
5
  * Copyright 2015-present Chen Fengyuan
6
6
  * Released under the MIT license
7
7
  *
8
- * Date: 2026-09-06T10:39:44.170Z
8
+ * Date: 2026-09-12T12:12:29.730Z
9
9
  */
10
10
 
11
11
  (function (global, factory) {
@@ -246,7 +246,10 @@
246
246
  zoomOnGesture: true,
247
247
  /**
248
248
  * Enable to zoom the image by wheeling mouse.
249
- * @type {boolean}
249
+ * Set to a modifier key name (`ctrl`, `shift`, `alt`, `meta`), or a
250
+ * combination joined with `+` (e.g. `ctrl+shift`), to only zoom when
251
+ * the given modifier key(s) are held down while wheeling.
252
+ * @type {boolean | string}
250
253
  */
251
254
  zoomOnWheel: true,
252
255
  /**
@@ -254,6 +257,16 @@
254
257
  * @type {boolean}
255
258
  */
256
259
  slideOnTouch: true,
260
+ /**
261
+ * Enable to slide to the next or previous image by wheeling mouse.
262
+ * Set to a modifier key name (`ctrl`, `shift`, `alt`, `meta`), or a
263
+ * combination joined with `+` (e.g. `ctrl+shift`), to only slide when
264
+ * the given modifier key(s) are held down while wheeling.
265
+ * Takes effect over the navbar, and also over the rest of the viewer
266
+ * when `zoomOnWheel` doesn't take effect for the wheel event.
267
+ * @type {boolean | string}
268
+ */
269
+ slideOnWheel: true,
257
270
  /**
258
271
  * Indicate if toggle the image size between its natural size
259
272
  * and initial size when double click on the image or not.
@@ -320,10 +333,11 @@
320
333
  zoom: null,
321
334
  zoomed: null,
322
335
  play: null,
336
+ playing: null,
323
337
  stop: null
324
338
  };
325
339
 
326
- var TEMPLATE = '<div class="viewer-container" tabindex="-1" touch-action="none">' + '<div class="viewer-canvas"></div>' + '<div class="viewer-magnifier" aria-hidden="true">' + '<img class="viewer-magnifier-image" alt="">' + '</div>' + '<div class="viewer-navigation">' + '<div class="viewer-prev" data-viewer-action="prev" role="button" aria-label="Previous"></div>' + '<div class="viewer-next" data-viewer-action="next" role="button" aria-label="Next"></div>' + '</div>' + '<div class="viewer-footer">' + '<div class="viewer-title"></div>' + '<div class="viewer-toolbar"></div>' + '<div class="viewer-navbar">' + '<ul class="viewer-list" role="navigation"></ul>' + '</div>' + '</div>' + '<div class="viewer-tooltip" role="alert" aria-hidden="true"></div>' + '<div class="viewer-button" data-viewer-action="mix" role="button"></div>' + '<div class="viewer-player"></div>' + '</div>';
340
+ var TEMPLATE = '<div class="viewer-container" tabindex="-1" touch-action="none">' + '<div class="viewer-canvas"></div>' + '<div class="viewer-magnifier" aria-hidden="true">' + '<img class="viewer-magnifier-image" alt="">' + '</div>' + '<div class="viewer-navigation" aria-hidden="true">' + '<div class="viewer-prev" data-viewer-action="prev" role="button" aria-label="Previous"></div>' + '<div class="viewer-next" data-viewer-action="next" role="button" aria-label="Next"></div>' + '</div>' + '<div class="viewer-footer" aria-hidden="true">' + '<div class="viewer-title" aria-hidden="true"></div>' + '<div class="viewer-toolbar" aria-hidden="true"></div>' + '<div class="viewer-navbar" aria-hidden="true">' + '<ul class="viewer-list" role="navigation"></ul>' + '</div>' + '</div>' + '<div class="viewer-tooltip" role="alert" aria-hidden="true"></div>' + '<div class="viewer-button" data-viewer-action="mix" role="button" aria-hidden="true"></div>' + '<div class="viewer-player" aria-hidden="true"></div>' + '</div>';
327
341
 
328
342
  var IS_BROWSER = typeof window !== 'undefined' && typeof window.document !== 'undefined';
329
343
  var WINDOW = IS_BROWSER ? window : {};
@@ -395,6 +409,7 @@
395
409
  var EVENT_ZOOM = 'zoom';
396
410
  var EVENT_ZOOMED = 'zoomed';
397
411
  var EVENT_PLAY = 'play';
412
+ var EVENT_PLAYING = 'playing';
398
413
  var EVENT_STOP = 'stop';
399
414
 
400
415
  // Data keys
@@ -414,6 +429,30 @@
414
429
  function isString(value) {
415
430
  return typeof value === 'string';
416
431
  }
432
+ var MODIFIER_KEY_PROPERTIES = {
433
+ ctrl: 'ctrlKey',
434
+ shift: 'shiftKey',
435
+ alt: 'altKey',
436
+ meta: 'metaKey'
437
+ };
438
+
439
+ /**
440
+ * Check if a wheel option (`zoomOnWheel` or `slideOnWheel`) takes effect for the given wheel event.
441
+ * @param {boolean | string} option - The option value.
442
+ * @param {WheelEvent} event - The wheel event.
443
+ * @returns {boolean} Returns `true` if the option takes effect for the event, else `false`.
444
+ */
445
+ function isWheelActionEnabled(option, event) {
446
+ if (!option) {
447
+ return false;
448
+ }
449
+ if (option === true) {
450
+ return true;
451
+ }
452
+ return isString(option) && option.split('+').every(function (key) {
453
+ return event[MODIFIER_KEY_PROPERTIES[key.trim().toLowerCase()]];
454
+ });
455
+ }
417
456
 
418
457
  /**
419
458
  * Check if the given value is not a number.
@@ -1082,6 +1121,9 @@
1082
1121
  var items = [];
1083
1122
  var navbarOptions = isPlainObject(options.navbar) ? options.navbar : {};
1084
1123
  var probe = document.createElement('li');
1124
+ if (!this.containerData) {
1125
+ this.initContainer();
1126
+ }
1085
1127
  list.appendChild(probe);
1086
1128
  var itemWidth = probe.offsetWidth + parseInt(window.getComputedStyle(probe).marginLeft, 10);
1087
1129
  list.removeChild(probe);
@@ -1336,7 +1378,7 @@
1336
1378
  addListener(document, EVENT_POINTER_UP, this.onPointerUp = this.pointerup.bind(this));
1337
1379
  addListener(document, EVENT_KEY_DOWN, this.onKeyDown = this.keydown.bind(this));
1338
1380
  addListener(window, EVENT_RESIZE, this.onResize = this.resize.bind(this));
1339
- if (options.zoomable && options.zoomOnWheel) {
1381
+ if (options.zoomable && options.zoomOnWheel || options.slideOnWheel) {
1340
1382
  addListener(viewer, EVENT_WHEEL, this.onWheel = this.wheel.bind(this), {
1341
1383
  passive: false,
1342
1384
  capture: true
@@ -1366,7 +1408,7 @@
1366
1408
  removeListener(document, EVENT_POINTER_UP, this.onPointerUp);
1367
1409
  removeListener(document, EVENT_KEY_DOWN, this.onKeyDown);
1368
1410
  removeListener(window, EVENT_RESIZE, this.onResize);
1369
- if (options.zoomable && options.zoomOnWheel) {
1411
+ if (options.zoomable && options.zoomOnWheel || options.slideOnWheel) {
1370
1412
  removeListener(viewer, EVENT_WHEEL, this.onWheel, {
1371
1413
  passive: false,
1372
1414
  capture: true
@@ -1398,6 +1440,7 @@
1398
1440
  if (IS_TOUCH_DEVICE && event.isTrusted && target === this.canvas) {
1399
1441
  clearTimeout(this.clickCanvasTimeout);
1400
1442
  }
1443
+ this.actionEvent = event;
1401
1444
  switch (action) {
1402
1445
  case 'mix':
1403
1446
  if (this.played) {
@@ -1468,7 +1511,8 @@
1468
1511
  }
1469
1512
 
1470
1513
  // XXX: No pageX/Y properties in custom event, fallback to the original event.
1471
- this.toggle(event.isTrusted ? event : event.detail && event.detail.originalEvent);
1514
+ this.actionEvent = event.isTrusted ? event : event.detail && event.detail.originalEvent;
1515
+ this.toggle();
1472
1516
  }
1473
1517
  },
1474
1518
  load: function load() {
@@ -1504,10 +1548,12 @@
1504
1548
  dispatchEvent(element, EVENT_VIEWED, {
1505
1549
  originalImage: _this.images[index],
1506
1550
  index: index,
1507
- image: image
1551
+ image: image,
1552
+ originalEvent: _this.viewOriginalEvent || null
1508
1553
  }, {
1509
1554
  cancelable: false
1510
1555
  });
1556
+ _this.viewOriginalEvent = null;
1511
1557
  });
1512
1558
  });
1513
1559
  },
@@ -1547,6 +1593,7 @@
1547
1593
  return;
1548
1594
  }
1549
1595
  var keyCode = event.keyCode || event.which || event.charCode;
1596
+ this.actionEvent = event;
1550
1597
  switch (keyCode) {
1551
1598
  // Enter
1552
1599
  case 13:
@@ -1872,6 +1919,8 @@
1872
1919
  },
1873
1920
  wheel: function wheel(event) {
1874
1921
  var _this4 = this;
1922
+ var options = this.options,
1923
+ navbar = this.navbar;
1875
1924
  if (!this.viewed) {
1876
1925
  return;
1877
1926
  }
@@ -1880,7 +1929,7 @@
1880
1929
  return;
1881
1930
  }
1882
1931
 
1883
- // Limit wheel speed to prevent zoom too fast
1932
+ // Limit wheel speed to prevent zoom or slide too fast
1884
1933
  if (this.wheeling) {
1885
1934
  return;
1886
1935
  }
@@ -1888,7 +1937,6 @@
1888
1937
  setTimeout(function () {
1889
1938
  _this4.wheeling = false;
1890
1939
  }, 50);
1891
- var ratio = Number(this.options.zoomRatio) || 0.1;
1892
1940
  var delta = 1;
1893
1941
  if (event.deltaY) {
1894
1942
  delta = event.deltaY > 0 ? 1 : -1;
@@ -1897,7 +1945,24 @@
1897
1945
  } else if (event.detail) {
1898
1946
  delta = event.detail > 0 ? 1 : -1;
1899
1947
  }
1900
- this.zoom(-delta * ratio, true, null, event);
1948
+
1949
+ // Wheeling over the navbar never zooms, only slides
1950
+ var overNavbar = navbar && navbar.contains(event.target);
1951
+ var zoomable = !overNavbar && options.zoomable && isWheelActionEnabled(options.zoomOnWheel, event);
1952
+ if (zoomable) {
1953
+ var ratio = Number(options.zoomRatio) || 0.1;
1954
+ this.actionEvent = event;
1955
+ this.zoom(-delta * ratio, true);
1956
+ return;
1957
+ }
1958
+ if (isWheelActionEnabled(options.slideOnWheel, event)) {
1959
+ this.actionEvent = event;
1960
+ if (delta > 0) {
1961
+ this.next(options.loop);
1962
+ } else if (delta < 0) {
1963
+ this.prev(options.loop);
1964
+ }
1965
+ }
1901
1966
  },
1902
1967
  gesture: function gesture(event) {
1903
1968
  var options = this.options;
@@ -1919,11 +1984,13 @@
1919
1984
  var degree = rotation - (this.gestureRotation || 0);
1920
1985
  this.gestureScale = scale;
1921
1986
  if (options.zoomable && options.zoomOnGesture && ratio !== 1) {
1922
- this.zoom(ratio >= 1 ? ratio - 1 : 1 - 1 / ratio, false, null, event);
1987
+ this.actionEvent = event;
1988
+ this.zoom(ratio >= 1 ? ratio - 1 : 1 - 1 / ratio);
1923
1989
  }
1924
1990
  if (options.rotatable && options.rotateOnGesture && isNumber(rotation)) {
1925
1991
  this.gestureRotation = rotation;
1926
1992
  if (degree !== 0) {
1993
+ this.actionEvent = event;
1927
1994
  this.rotate(degree);
1928
1995
  }
1929
1996
  }
@@ -1957,12 +2024,17 @@
1957
2024
  }
1958
2025
  return this;
1959
2026
  }
2027
+ var originalEvent = this.actionEvent || this.showOriginalEvent || this.viewOriginalEvent || null;
2028
+ this.actionEvent = null;
2029
+ this.showOriginalEvent = originalEvent;
1960
2030
  if (isFunction(options.show)) {
1961
2031
  addListener(element, EVENT_SHOW, options.show, {
1962
2032
  once: true
1963
2033
  });
1964
2034
  }
1965
- if (dispatchEvent(element, EVENT_SHOW) === false || !this.ready) {
2035
+ if (dispatchEvent(element, EVENT_SHOW, {
2036
+ originalEvent: originalEvent
2037
+ }) === false || !this.ready) {
1966
2038
  return this;
1967
2039
  }
1968
2040
  if (this.hiding) {
@@ -2011,12 +2083,17 @@
2011
2083
  if (options.inline || this.hiding || !(this.isShown || this.showing)) {
2012
2084
  return this;
2013
2085
  }
2086
+ var originalEvent = this.actionEvent || this.hideOriginalEvent || null;
2087
+ this.actionEvent = null;
2088
+ this.hideOriginalEvent = originalEvent;
2014
2089
  if (isFunction(options.hide)) {
2015
2090
  addListener(element, EVENT_HIDE, options.hide, {
2016
2091
  once: true
2017
2092
  });
2018
2093
  }
2019
- if (dispatchEvent(element, EVENT_HIDE) === false || this.destroyed) {
2094
+ if (dispatchEvent(element, EVENT_HIDE, {
2095
+ originalEvent: originalEvent
2096
+ }) === false || this.destroyed) {
2020
2097
  return this;
2021
2098
  }
2022
2099
  if (this.showing) {
@@ -2067,7 +2144,7 @@
2067
2144
  addListener(image, EVENT_TRANSITION_END, onImageTransitionEnd, {
2068
2145
  once: true
2069
2146
  });
2070
- this.zoomTo(0, false, null, null, true);
2147
+ this.zoomTo(0, false, null, true);
2071
2148
  } else {
2072
2149
  onImageTransitionEnd();
2073
2150
  }
@@ -2089,6 +2166,9 @@
2089
2166
  if (this.hiding || this.played || index < 0 || index >= this.length || this.viewed && index === previousIndex) {
2090
2167
  return this;
2091
2168
  }
2169
+ var originalEvent = this.actionEvent || this.viewOriginalEvent || null;
2170
+ this.actionEvent = null;
2171
+ this.viewOriginalEvent = originalEvent;
2092
2172
  if (!this.isShown) {
2093
2173
  this.index = index;
2094
2174
  return this.show();
@@ -2120,7 +2200,8 @@
2120
2200
  if (dispatchEvent(element, EVENT_VIEW, {
2121
2201
  originalImage: this.images[index],
2122
2202
  index: index,
2123
- image: image
2203
+ image: image,
2204
+ originalEvent: originalEvent
2124
2205
  }) === false || !this.isShown || this.hiding || this.played) {
2125
2206
  return this;
2126
2207
  }
@@ -2177,62 +2258,75 @@
2177
2258
  }
2178
2259
  }
2179
2260
  };
2180
- var onLoad;
2181
- var onError;
2182
2261
  addListener(element, EVENT_VIEWED, onViewed, {
2183
2262
  once: true
2184
2263
  });
2185
- this.viewing = {
2186
- abort: function abort() {
2187
- removeListener(element, EVENT_VIEWED, onViewed);
2188
- if (image.complete) {
2189
- if (_this2.imageRendering) {
2190
- _this2.imageRendering.abort();
2191
- } else if (_this2.imageInitializing) {
2192
- _this2.imageInitializing.abort();
2193
- }
2194
- } else {
2195
- // Cancel download to save bandwidth.
2196
- image.src = '';
2197
- removeListener(image, EVENT_LOAD, onLoad);
2198
- if (_this2.timeout) {
2199
- clearTimeout(_this2.timeout);
2200
- }
2201
- }
2202
- }
2203
- };
2204
- if (image.complete) {
2205
- this.load();
2206
- } else {
2207
- addListener(image, EVENT_LOAD, onLoad = function onLoad() {
2208
- removeListener(image, EVENT_ERROR, onError);
2209
- _this2.load();
2210
- }, {
2211
- once: true
2212
- });
2213
- addListener(image, EVENT_ERROR, onError = function onError() {
2264
+ var _loadImage = function loadImage() {
2265
+ var isFallback = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
2266
+ var onLoad;
2267
+ var onError;
2268
+ var clean = function clean() {
2214
2269
  removeListener(image, EVENT_LOAD, onLoad);
2270
+ removeListener(image, EVENT_ERROR, onError);
2215
2271
  if (_this2.timeout) {
2216
2272
  clearTimeout(_this2.timeout);
2217
2273
  _this2.timeout = false;
2218
2274
  }
2219
- removeClass(image, CLASS_INVISIBLE);
2220
- if (options.loading) {
2221
- removeClass(_this2.canvas, CLASS_LOADING);
2275
+ };
2276
+ _this2.viewing = {
2277
+ abort: function abort() {
2278
+ removeListener(element, EVENT_VIEWED, onViewed);
2279
+ if (image.complete) {
2280
+ if (_this2.imageRendering) {
2281
+ _this2.imageRendering.abort();
2282
+ } else if (_this2.imageInitializing) {
2283
+ _this2.imageInitializing.abort();
2284
+ }
2285
+ } else {
2286
+ // Cancel download to save bandwidth.
2287
+ image.src = '';
2288
+ clean();
2289
+ }
2290
+ }
2291
+ };
2292
+ if (image.complete) {
2293
+ _this2.load();
2294
+ } else {
2295
+ addListener(image, EVENT_LOAD, onLoad = function onLoad() {
2296
+ clean();
2297
+ _this2.load();
2298
+ }, {
2299
+ once: true
2300
+ });
2301
+ addListener(image, EVENT_ERROR, onError = function onError() {
2302
+ clean();
2303
+ if (!isFallback) {
2304
+ var fallbackSrc = img.src;
2305
+ if (fallbackSrc && fallbackSrc !== image.src) {
2306
+ image.src = fallbackSrc;
2307
+ _loadImage(true);
2308
+ return;
2309
+ }
2310
+ }
2311
+ removeClass(image, CLASS_INVISIBLE);
2312
+ if (options.loading) {
2313
+ removeClass(_this2.canvas, CLASS_LOADING);
2314
+ }
2315
+ }, {
2316
+ once: true
2317
+ });
2318
+ if (_this2.timeout) {
2319
+ clearTimeout(_this2.timeout);
2222
2320
  }
2223
- }, {
2224
- once: true
2225
- });
2226
- if (this.timeout) {
2227
- clearTimeout(this.timeout);
2228
- }
2229
2321
 
2230
- // Make the image visible if it fails to load within 1s
2231
- this.timeout = setTimeout(function () {
2232
- removeClass(image, CLASS_INVISIBLE);
2233
- _this2.timeout = false;
2234
- }, 1000);
2235
- }
2322
+ // Make the image visible if it fails to load within 1s
2323
+ _this2.timeout = setTimeout(function () {
2324
+ removeClass(image, CLASS_INVISIBLE);
2325
+ _this2.timeout = false;
2326
+ }, 1000);
2327
+ }
2328
+ };
2329
+ _loadImage();
2236
2330
  return this;
2237
2331
  },
2238
2332
  /**
@@ -2282,13 +2376,11 @@
2282
2376
  * Move the image to an absolute point.
2283
2377
  * @param {number} x - The new position in the horizontal direction.
2284
2378
  * @param {number} [y=x] - The new position in the vertical direction.
2285
- * @param {Event} [_originalEvent=null] - The original event if any.
2286
2379
  * @returns {Viewer} this
2287
2380
  */
2288
2381
  moveTo: function moveTo(x) {
2289
2382
  var _this3 = this;
2290
2383
  var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x;
2291
- var _originalEvent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
2292
2384
  var element = this.element,
2293
2385
  options = this.options,
2294
2386
  imageData = this.imageData;
@@ -2309,6 +2401,8 @@
2309
2401
  y = oldY;
2310
2402
  }
2311
2403
  if (changed) {
2404
+ var originalEvent = this.actionEvent || null;
2405
+ this.actionEvent = null;
2312
2406
  if (isFunction(options.move)) {
2313
2407
  addListener(element, EVENT_MOVE, options.move, {
2314
2408
  once: true
@@ -2319,7 +2413,7 @@
2319
2413
  y: y,
2320
2414
  oldX: oldX,
2321
2415
  oldY: oldY,
2322
- originalEvent: _originalEvent
2416
+ originalEvent: originalEvent
2323
2417
  }) === false) {
2324
2418
  return this;
2325
2419
  }
@@ -2341,7 +2435,7 @@
2341
2435
  y: y,
2342
2436
  oldX: oldX,
2343
2437
  oldY: oldY,
2344
- originalEvent: _originalEvent
2438
+ originalEvent: originalEvent
2345
2439
  }, {
2346
2440
  cancelable: false
2347
2441
  });
@@ -2372,6 +2466,8 @@
2372
2466
  degree = Number(degree);
2373
2467
  if (isNumber(degree) && this.viewed && !this.played && options.rotatable) {
2374
2468
  var oldDegree = imageData.rotate;
2469
+ var originalEvent = this.actionEvent || null;
2470
+ this.actionEvent = null;
2375
2471
  if (isFunction(options.rotate)) {
2376
2472
  addListener(element, EVENT_ROTATE, options.rotate, {
2377
2473
  once: true
@@ -2379,7 +2475,8 @@
2379
2475
  }
2380
2476
  if (dispatchEvent(element, EVENT_ROTATE, {
2381
2477
  degree: degree,
2382
- oldDegree: oldDegree
2478
+ oldDegree: oldDegree,
2479
+ originalEvent: originalEvent
2383
2480
  }) === false) {
2384
2481
  return this;
2385
2482
  }
@@ -2395,7 +2492,8 @@
2395
2492
  }
2396
2493
  dispatchEvent(element, EVENT_ROTATED, {
2397
2494
  degree: degree,
2398
- oldDegree: oldDegree
2495
+ oldDegree: oldDegree,
2496
+ originalEvent: originalEvent
2399
2497
  }, {
2400
2498
  cancelable: false
2401
2499
  });
@@ -2450,6 +2548,8 @@
2450
2548
  scaleY = oldScaleY;
2451
2549
  }
2452
2550
  if (changed) {
2551
+ var originalEvent = this.actionEvent || null;
2552
+ this.actionEvent = null;
2453
2553
  if (isFunction(options.scale)) {
2454
2554
  addListener(element, EVENT_SCALE, options.scale, {
2455
2555
  once: true
@@ -2459,7 +2559,8 @@
2459
2559
  scaleX: scaleX,
2460
2560
  scaleY: scaleY,
2461
2561
  oldScaleX: oldScaleX,
2462
- oldScaleY: oldScaleY
2562
+ oldScaleY: oldScaleY,
2563
+ originalEvent: originalEvent
2463
2564
  }) === false) {
2464
2565
  return this;
2465
2566
  }
@@ -2478,7 +2579,8 @@
2478
2579
  scaleX: scaleX,
2479
2580
  scaleY: scaleY,
2480
2581
  oldScaleX: oldScaleX,
2481
- oldScaleY: oldScaleY
2582
+ oldScaleY: oldScaleY,
2583
+ originalEvent: originalEvent
2482
2584
  }, {
2483
2585
  cancelable: false
2484
2586
  });
@@ -2492,13 +2594,11 @@
2492
2594
  * @param {number} ratio - The target ratio.
2493
2595
  * @param {boolean} [showTooltip=false] - Indicates whether to show the tooltip.
2494
2596
  * @param {Object} [pivot] - The pivot point coordinate for zooming.
2495
- * @param {Event} [_originalEvent=null] - The original event if any.
2496
2597
  * @returns {Viewer} this
2497
2598
  */
2498
2599
  zoom: function zoom(ratio) {
2499
2600
  var showTooltip = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
2500
2601
  var pivot = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
2501
- var _originalEvent = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
2502
2602
  var imageData = this.imageData;
2503
2603
  ratio = Number(ratio);
2504
2604
  if (ratio < 0) {
@@ -2506,7 +2606,7 @@
2506
2606
  } else {
2507
2607
  ratio = 1 + ratio;
2508
2608
  }
2509
- this.zoomTo(imageData.width * ratio / imageData.naturalWidth, showTooltip, pivot, _originalEvent);
2609
+ this.zoomTo(imageData.width * ratio / imageData.naturalWidth, showTooltip, pivot);
2510
2610
  return this;
2511
2611
  },
2512
2612
  /**
@@ -2514,16 +2614,14 @@
2514
2614
  * @param {number} ratio - The target ratio.
2515
2615
  * @param {boolean} [showTooltip] - Indicates whether to show the tooltip.
2516
2616
  * @param {Object} [pivot] - The pivot point coordinate for zooming.
2517
- * @param {Event} [_originalEvent=null] - The original event if any.
2518
- * @param {Event} [_zoomable=false] - Indicates if the current zoom is available or not.
2617
+ * @param {boolean} [_zoomable=false] - Indicates if the current zoom is available or not.
2519
2618
  * @returns {Viewer} this
2520
2619
  */
2521
2620
  zoomTo: function zoomTo(ratio) {
2522
2621
  var _this6 = this;
2523
2622
  var showTooltip = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
2524
2623
  var pivot = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
2525
- var _originalEvent = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
2526
- var _zoomable = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
2624
+ var _zoomable = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
2527
2625
  var element = this.element,
2528
2626
  options = this.options,
2529
2627
  pointers = this.pointers,
@@ -2541,8 +2639,10 @@
2541
2639
  var maxZoomRatio = Math.min(100, isFunction(options.maxZoomRatio) ? options.maxZoomRatio.call(this, this.image, imageData) : options.maxZoomRatio);
2542
2640
  ratio = Math.min(Math.max(ratio, minZoomRatio), maxZoomRatio);
2543
2641
  }
2544
- if (_originalEvent) {
2545
- switch (_originalEvent.type) {
2642
+ var originalEvent = this.actionEvent || null;
2643
+ this.actionEvent = null;
2644
+ if (originalEvent && originalEvent.type !== EVENT_CLICK) {
2645
+ switch (originalEvent.type) {
2546
2646
  case 'wheel':
2547
2647
  if (options.zoomRatio >= 0.055 && ratio > 0.95 && ratio < 1.05) {
2548
2648
  ratio = 1;
@@ -2570,16 +2670,16 @@
2570
2670
  if (dispatchEvent(element, EVENT_ZOOM, {
2571
2671
  ratio: ratio,
2572
2672
  oldRatio: oldRatio,
2573
- originalEvent: _originalEvent
2673
+ originalEvent: originalEvent
2574
2674
  }) === false) {
2575
2675
  return this;
2576
2676
  }
2577
2677
  this.zooming = true;
2578
- if (_originalEvent) {
2678
+ if (originalEvent && originalEvent.type !== EVENT_CLICK) {
2579
2679
  var offset = getOffset(this.viewer);
2580
2680
  var center = pointers && Object.keys(pointers).length > 0 ? getPointersCenter(pointers) : {
2581
- pageX: _originalEvent.pageX,
2582
- pageY: _originalEvent.pageY
2681
+ pageX: originalEvent.pageX,
2682
+ pageY: originalEvent.pageY
2583
2683
  };
2584
2684
 
2585
2685
  // Zoom from the triggering point of the event
@@ -2610,7 +2710,7 @@
2610
2710
  dispatchEvent(element, EVENT_ZOOMED, {
2611
2711
  ratio: ratio,
2612
2712
  oldRatio: oldRatio,
2613
- originalEvent: _originalEvent
2713
+ originalEvent: originalEvent
2614
2714
  }, {
2615
2715
  cancelable: false
2616
2716
  });
@@ -2634,12 +2734,16 @@
2634
2734
  }
2635
2735
  var element = this.element,
2636
2736
  options = this.options;
2737
+ var originalEvent = this.actionEvent || null;
2738
+ this.actionEvent = null;
2637
2739
  if (isFunction(options.play)) {
2638
2740
  addListener(element, EVENT_PLAY, options.play, {
2639
2741
  once: true
2640
2742
  });
2641
2743
  }
2642
- if (dispatchEvent(element, EVENT_PLAY) === false) {
2744
+ if (dispatchEvent(element, EVENT_PLAY, {
2745
+ originalEvent: originalEvent
2746
+ }) === false) {
2643
2747
  return this;
2644
2748
  }
2645
2749
  var player = this.player;
@@ -2653,6 +2757,7 @@
2653
2757
  this.requestFullscreen(fullscreen);
2654
2758
  }
2655
2759
  addClass(player, CLASS_SHOW);
2760
+ player.removeAttribute('aria-hidden');
2656
2761
  forEach(this.images, function (originalImage, i) {
2657
2762
  var image = document.createElement('img');
2658
2763
  image.src = _this7.getImageURL(originalImage) || originalImage.src;
@@ -2674,17 +2779,51 @@
2674
2779
  if (isNumber(options.interval) && options.interval > 0) {
2675
2780
  var _prev = function prev() {
2676
2781
  clearTimeout(_this7.playing.timeout);
2782
+ var currentOriginalEvent = _this7.actionEvent || null;
2783
+ _this7.actionEvent = null;
2784
+ var prevIndex = index - 1;
2785
+ prevIndex = prevIndex >= 0 ? prevIndex : total - 1;
2786
+ if (isFunction(options.playing)) {
2787
+ addListener(element, EVENT_PLAYING, options.playing, {
2788
+ once: true
2789
+ });
2790
+ }
2791
+ if (dispatchEvent(element, EVENT_PLAYING, {
2792
+ originalImage: _this7.images[prevIndex],
2793
+ index: prevIndex,
2794
+ image: list[prevIndex],
2795
+ originalEvent: currentOriginalEvent
2796
+ }) === false) {
2797
+ _this7.playing.timeout = options.autoplay ? setTimeout(_prev, options.interval) : null;
2798
+ return;
2799
+ }
2677
2800
  removeClass(list[index], CLASS_IN);
2678
- index -= 1;
2679
- index = index >= 0 ? index : total - 1;
2801
+ index = prevIndex;
2680
2802
  addClass(list[index], CLASS_IN);
2681
2803
  _this7.playing.timeout = options.autoplay ? setTimeout(_prev, options.interval) : null;
2682
2804
  };
2683
2805
  var _next = function next() {
2684
2806
  clearTimeout(_this7.playing.timeout);
2807
+ var currentOriginalEvent = _this7.actionEvent || null;
2808
+ _this7.actionEvent = null;
2809
+ var nextIndex = index + 1;
2810
+ nextIndex = nextIndex < total ? nextIndex : 0;
2811
+ if (isFunction(options.playing)) {
2812
+ addListener(element, EVENT_PLAYING, options.playing, {
2813
+ once: true
2814
+ });
2815
+ }
2816
+ if (dispatchEvent(element, EVENT_PLAYING, {
2817
+ originalImage: _this7.images[nextIndex],
2818
+ index: nextIndex,
2819
+ image: list[nextIndex],
2820
+ originalEvent: currentOriginalEvent
2821
+ }) === false) {
2822
+ _this7.playing.timeout = options.autoplay ? setTimeout(_next, options.interval) : null;
2823
+ return;
2824
+ }
2685
2825
  removeClass(list[index], CLASS_IN);
2686
- index += 1;
2687
- index = index < total ? index : 0;
2826
+ index = nextIndex;
2688
2827
  addClass(list[index], CLASS_IN);
2689
2828
  _this7.playing.timeout = options.autoplay ? setTimeout(_next, options.interval) : null;
2690
2829
  };
@@ -2698,7 +2837,10 @@
2698
2837
  }
2699
2838
  return this;
2700
2839
  },
2701
- // Stop play
2840
+ /**
2841
+ * Stop play
2842
+ * @returns {Viewer} this
2843
+ */
2702
2844
  stop: function stop() {
2703
2845
  var _this8 = this;
2704
2846
  if (!this.played) {
@@ -2706,12 +2848,16 @@
2706
2848
  }
2707
2849
  var element = this.element,
2708
2850
  options = this.options;
2851
+ var originalEvent = this.actionEvent || null;
2852
+ this.actionEvent = null;
2709
2853
  if (isFunction(options.stop)) {
2710
2854
  addListener(element, EVENT_STOP, options.stop, {
2711
2855
  once: true
2712
2856
  });
2713
2857
  }
2714
- if (dispatchEvent(element, EVENT_STOP) === false) {
2858
+ if (dispatchEvent(element, EVENT_STOP, {
2859
+ originalEvent: originalEvent
2860
+ }) === false) {
2715
2861
  return this;
2716
2862
  }
2717
2863
  var player = this.player;
@@ -2722,6 +2868,7 @@
2722
2868
  removeListener(image, EVENT_LOAD, _this8.onLoadWhenPlay);
2723
2869
  });
2724
2870
  removeClass(player, CLASS_SHOW);
2871
+ player.setAttribute('aria-hidden', true);
2725
2872
  player.innerHTML = '';
2726
2873
  this.exitFullscreen();
2727
2874
  return this;
@@ -2854,15 +3001,13 @@
2854
3001
  },
2855
3002
  /**
2856
3003
  * Toggle the image size between its current size and natural size
2857
- * @param {Event} [_originalEvent=null] - The original event if any.
2858
3004
  * @returns {Viewer} this
2859
3005
  */
2860
3006
  toggle: function toggle() {
2861
- var _originalEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
2862
3007
  if (this.imageData.ratio === 1) {
2863
- this.zoomTo(this.imageData.oldRatio, true, null, _originalEvent);
3008
+ this.zoomTo(this.imageData.oldRatio, true);
2864
3009
  } else {
2865
- this.zoomTo(1, true, null, _originalEvent);
3010
+ this.zoomTo(1, true);
2866
3011
  }
2867
3012
  return this;
2868
3013
  },
@@ -3077,9 +3222,12 @@
3077
3222
  once: true
3078
3223
  });
3079
3224
  }
3080
- if (dispatchEvent(element, EVENT_SHOWN) === false) {
3225
+ if (dispatchEvent(element, EVENT_SHOWN, {
3226
+ originalEvent: this.showOriginalEvent || null
3227
+ }) === false) {
3081
3228
  return;
3082
3229
  }
3230
+ this.showOriginalEvent = null;
3083
3231
  if (this.ready && this.isShown && !this.hiding) {
3084
3232
  this.view(this.index);
3085
3233
  }
@@ -3116,9 +3264,12 @@
3116
3264
  once: true
3117
3265
  });
3118
3266
  }
3119
- dispatchEvent(element, EVENT_HIDDEN, null, {
3267
+ dispatchEvent(element, EVENT_HIDDEN, {
3268
+ originalEvent: this.hideOriginalEvent || null
3269
+ }, {
3120
3270
  cancelable: false
3121
3271
  });
3272
+ this.hideOriginalEvent = null;
3122
3273
  }
3123
3274
  },
3124
3275
  requestFullscreen: function requestFullscreen(options) {
@@ -3174,7 +3325,8 @@
3174
3325
  case ACTION_MOVE:
3175
3326
  if (offsetX !== 0 || offsetY !== 0) {
3176
3327
  this.pointerMoved = true;
3177
- this.move(offsetX, offsetY, event);
3328
+ this.actionEvent = event;
3329
+ this.move(offsetX, offsetY);
3178
3330
  }
3179
3331
  break;
3180
3332
 
@@ -3183,7 +3335,8 @@
3183
3335
  if (options.zoomable && options.zoomOnTouch) {
3184
3336
  var zoomRatio = getMaxZoomRatio(pointers);
3185
3337
  if (zoomRatio !== 0) {
3186
- this.zoom(zoomRatio, false, null, event);
3338
+ this.actionEvent = event;
3339
+ this.zoom(zoomRatio);
3187
3340
  }
3188
3341
  }
3189
3342
  break;
@@ -3193,7 +3346,8 @@
3193
3346
  if (options.rotatable && options.rotateOnTouch) {
3194
3347
  var rotateDegree = getMaxRotateDegree(pointers);
3195
3348
  if (rotateDegree !== 0) {
3196
- this.rotate(rotateDegree, event);
3349
+ this.actionEvent = event;
3350
+ this.rotate(rotateDegree);
3197
3351
  }
3198
3352
  }
3199
3353
  break;
@@ -3203,13 +3357,15 @@
3203
3357
  if (options.zoomable && options.zoomOnTouch) {
3204
3358
  var _zoomRatio = getMaxZoomRatio(pointers);
3205
3359
  if (_zoomRatio !== 0) {
3206
- this.zoom(_zoomRatio, false, null, event);
3360
+ this.actionEvent = event;
3361
+ this.zoom(_zoomRatio);
3207
3362
  }
3208
3363
  }
3209
3364
  if (options.rotatable && options.rotateOnTouch) {
3210
3365
  var _rotateDegree = getMaxRotateDegree(pointers);
3211
3366
  if (_rotateDegree !== 0) {
3212
- this.rotate(_rotateDegree, event);
3367
+ this.actionEvent = event;
3368
+ this.rotate(_rotateDegree);
3213
3369
  }
3214
3370
  }
3215
3371
  break;
@@ -3220,6 +3376,7 @@
3220
3376
  if (absoluteOffsetX > 1 && absoluteOffsetX > Math.abs(offsetY)) {
3221
3377
  // Empty `pointers` as `touchend` event will not be fired after swiped in iOS browsers.
3222
3378
  this.pointers = {};
3379
+ this.actionEvent = event;
3223
3380
  if (offsetX > 1) {
3224
3381
  this.prev(options.loop);
3225
3382
  } else if (offsetX < -1) {
@@ -3266,6 +3423,7 @@
3266
3423
  this.ownerDocument = element.ownerDocument || element.host.ownerDocument;
3267
3424
  this.options = assign({}, DEFAULTS, isPlainObject(options) && options);
3268
3425
  this.action = false;
3426
+ this.actionEvent = null;
3269
3427
  this.fading = false;
3270
3428
  this.fulled = false;
3271
3429
  this.hiding = false;
@@ -3379,9 +3537,10 @@
3379
3537
  }
3380
3538
  });
3381
3539
  } else {
3382
- addListener(element, EVENT_CLICK, this.onElementClick = function (_ref) {
3383
- var target = _ref.target;
3540
+ addListener(element, EVENT_CLICK, this.onElementClick = function (event) {
3541
+ var target = event.target;
3384
3542
  if (target.localName === 'img' && (!isFunction(options.filter) || options.filter.call(_this, target))) {
3543
+ _this.actionEvent = event;
3385
3544
  _this.view(_this.images.indexOf(target));
3386
3545
  }
3387
3546
  });
@@ -3391,6 +3550,7 @@
3391
3550
  if (target.localName === 'img' && (key === 'Enter' || key === ' ')) {
3392
3551
  event.preventDefault();
3393
3552
  if (!isFunction(options.filter) || options.filter.call(_this, target)) {
3553
+ _this.actionEvent = event;
3394
3554
  _this.view(_this.images.indexOf(target));
3395
3555
  }
3396
3556
  }
@@ -3432,6 +3592,9 @@
3432
3592
  viewer.id = "".concat(NAMESPACE).concat(this.id);
3433
3593
  title.id = "".concat(NAMESPACE, "Title").concat(this.id);
3434
3594
  addClass(title, !options.title ? CLASS_HIDE : getResponsiveClass(Array.isArray(options.title) ? options.title[0] : options.title));
3595
+ if (options.title) {
3596
+ title.removeAttribute('aria-hidden');
3597
+ }
3435
3598
  var navbarOptions = isPlainObject(options.navbar) ? options.navbar : {};
3436
3599
  var navbarShow = options.navbar;
3437
3600
  var navbarSize = !isUndefined(navbarOptions.size) ? navbarOptions.size : options.navbar;
@@ -3439,6 +3602,9 @@
3439
3602
  navbarShow = !isUndefined(navbarOptions.show) ? navbarOptions.show : true;
3440
3603
  }
3441
3604
  addClass(navbar, !navbarShow ? CLASS_HIDE : getResponsiveClass(navbarShow));
3605
+ if (navbarShow) {
3606
+ navbar.removeAttribute('aria-hidden');
3607
+ }
3442
3608
  if (['small', 'medium', 'large'].indexOf(navbarSize) !== -1) {
3443
3609
  addClass(navbar, "".concat(NAMESPACE, "-").concat(navbarSize));
3444
3610
  }
@@ -3460,7 +3626,13 @@
3460
3626
  } else {
3461
3627
  addClass(navigation, !options.navigation ? CLASS_HIDE : getResponsiveClass(options.navigation));
3462
3628
  }
3629
+ if (options.navigation) {
3630
+ navigation.removeAttribute('aria-hidden');
3631
+ }
3463
3632
  toggleClass(button, CLASS_HIDE, !options.button);
3633
+ if (options.button) {
3634
+ button.removeAttribute('aria-hidden');
3635
+ }
3464
3636
  if (options.keyboard) {
3465
3637
  button.setAttribute('tabindex', 0);
3466
3638
  forEach(navigation.querySelectorAll('[role="button"]'), function (item) {
@@ -3488,6 +3660,7 @@
3488
3660
  if (!custom) {
3489
3661
  addClass(toolbar, getResponsiveClass(options.toolbar));
3490
3662
  }
3663
+ toolbar.removeAttribute('aria-hidden');
3491
3664
  forEach(custom ? options.toolbar : BUTTONS, function (value, index) {
3492
3665
  var deep = custom && isPlainObject(value);
3493
3666
  var name = custom ? hyphenate(index) : value;
@@ -3523,6 +3696,11 @@
3523
3696
  } else {
3524
3697
  addClass(toolbar, CLASS_HIDE);
3525
3698
  }
3699
+ if (options.title || navbarShow || options.toolbar) {
3700
+ this.footer.removeAttribute('aria-hidden');
3701
+ } else {
3702
+ addClass(this.footer, CLASS_HIDE);
3703
+ }
3526
3704
  if (!options.rotatable) {
3527
3705
  var rotates = toolbar.querySelectorAll('li[class*="rotate"]');
3528
3706
  addClass(rotates, CLASS_INVISIBLE);