viewerjs 1.10.4 → 1.11.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.10.4
2
+ * Viewer.js v1.11.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: 2022-02-13T08:40:00.127Z
8
+ * Date: 2022-10-16T06:41:28.706Z
9
9
  */
10
10
 
11
11
  (function (global, factory) {
@@ -16,17 +16,14 @@
16
16
 
17
17
  function ownKeys(object, enumerableOnly) {
18
18
  var keys = Object.keys(object);
19
-
20
19
  if (Object.getOwnPropertySymbols) {
21
20
  var symbols = Object.getOwnPropertySymbols(object);
22
21
  enumerableOnly && (symbols = symbols.filter(function (sym) {
23
22
  return Object.getOwnPropertyDescriptor(object, sym).enumerable;
24
23
  })), keys.push.apply(keys, symbols);
25
24
  }
26
-
27
25
  return keys;
28
26
  }
29
-
30
27
  function _objectSpread2(target) {
31
28
  for (var i = 1; i < arguments.length; i++) {
32
29
  var source = null != arguments[i] ? arguments[i] : {};
@@ -36,10 +33,8 @@
36
33
  Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
37
34
  });
38
35
  }
39
-
40
36
  return target;
41
37
  }
42
-
43
38
  function _typeof(obj) {
44
39
  "@babel/helpers - typeof";
45
40
 
@@ -49,13 +44,11 @@
49
44
  return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
50
45
  }, _typeof(obj);
51
46
  }
52
-
53
47
  function _classCallCheck(instance, Constructor) {
54
48
  if (!(instance instanceof Constructor)) {
55
49
  throw new TypeError("Cannot call a class as a function");
56
50
  }
57
51
  }
58
-
59
52
  function _defineProperties(target, props) {
60
53
  for (var i = 0; i < props.length; i++) {
61
54
  var descriptor = props[i];
@@ -65,7 +58,6 @@
65
58
  Object.defineProperty(target, descriptor.key, descriptor);
66
59
  }
67
60
  }
68
-
69
61
  function _createClass(Constructor, protoProps, staticProps) {
70
62
  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
71
63
  if (staticProps) _defineProperties(Constructor, staticProps);
@@ -74,7 +66,6 @@
74
66
  });
75
67
  return Constructor;
76
68
  }
77
-
78
69
  function _defineProperty(obj, key, value) {
79
70
  if (key in obj) {
80
71
  Object.defineProperty(obj, key, {
@@ -86,7 +77,6 @@
86
77
  } else {
87
78
  obj[key] = value;
88
79
  }
89
-
90
80
  return obj;
91
81
  }
92
82
 
@@ -97,213 +87,183 @@
97
87
  * @type {boolean}
98
88
  */
99
89
  backdrop: true,
100
-
101
90
  /**
102
91
  * Show the button on the top-right of the viewer.
103
92
  * @type {boolean}
104
93
  */
105
94
  button: true,
106
-
107
95
  /**
108
96
  * Show the navbar.
109
97
  * @type {boolean | number}
110
98
  */
111
99
  navbar: true,
112
-
113
100
  /**
114
101
  * Specify the visibility and the content of the title.
115
102
  * @type {boolean | number | Function | Array}
116
103
  */
117
104
  title: true,
118
-
119
105
  /**
120
106
  * Show the toolbar.
121
107
  * @type {boolean | number | Object}
122
108
  */
123
109
  toolbar: true,
124
-
125
110
  /**
126
111
  * Custom class name(s) to add to the viewer's root element.
127
112
  * @type {string}
128
113
  */
129
114
  className: '',
130
-
131
115
  /**
132
116
  * Define where to put the viewer in modal mode.
133
117
  * @type {string | Element}
134
118
  */
135
119
  container: 'body',
136
-
137
120
  /**
138
121
  * Filter the images for viewing. Return true if the image is viewable.
139
122
  * @type {Function}
140
123
  */
141
124
  filter: null,
142
-
143
125
  /**
144
126
  * Enable to request fullscreen when play.
145
127
  * {@link https://developer.mozilla.org/en-US/docs/Web/API/FullscreenOptions}
146
128
  * @type {boolean|FullscreenOptions}
147
129
  */
148
130
  fullscreen: true,
149
-
150
131
  /**
151
132
  * Define the extra attributes to inherit from the original image.
152
133
  * @type {Array}
153
134
  */
154
135
  inheritedAttributes: ['crossOrigin', 'decoding', 'isMap', 'loading', 'referrerPolicy', 'sizes', 'srcset', 'useMap'],
155
-
156
136
  /**
157
- * Define the initial index of image for viewing.
137
+ * Define the initial coverage of the viewing image.
138
+ * @type {number}
139
+ */
140
+ initialCoverage: 0.9,
141
+ /**
142
+ * Define the initial index of the image for viewing.
158
143
  * @type {number}
159
144
  */
160
145
  initialViewIndex: 0,
161
-
162
146
  /**
163
147
  * Enable inline mode.
164
148
  * @type {boolean}
165
149
  */
166
150
  inline: false,
167
-
168
151
  /**
169
152
  * The amount of time to delay between automatically cycling an image when playing.
170
153
  * @type {number}
171
154
  */
172
155
  interval: 5000,
173
-
174
156
  /**
175
157
  * Enable keyboard support.
176
158
  * @type {boolean}
177
159
  */
178
160
  keyboard: true,
179
-
180
161
  /**
181
162
  * Focus the viewer when initialized.
182
163
  * @type {boolean}
183
164
  */
184
165
  focus: true,
185
-
186
166
  /**
187
167
  * Indicate if show a loading spinner when load image or not.
188
168
  * @type {boolean}
189
169
  */
190
170
  loading: true,
191
-
192
171
  /**
193
172
  * Indicate if enable loop viewing or not.
194
173
  * @type {boolean}
195
174
  */
196
175
  loop: true,
197
-
198
176
  /**
199
177
  * Min width of the viewer in inline mode.
200
178
  * @type {number}
201
179
  */
202
180
  minWidth: 200,
203
-
204
181
  /**
205
182
  * Min height of the viewer in inline mode.
206
183
  * @type {number}
207
184
  */
208
185
  minHeight: 100,
209
-
210
186
  /**
211
187
  * Enable to move the image.
212
188
  * @type {boolean}
213
189
  */
214
190
  movable: true,
215
-
216
191
  /**
217
192
  * Enable to rotate the image.
218
193
  * @type {boolean}
219
194
  */
220
195
  rotatable: true,
221
-
222
196
  /**
223
197
  * Enable to scale the image.
224
198
  * @type {boolean}
225
199
  */
226
200
  scalable: true,
227
-
228
201
  /**
229
202
  * Enable to zoom the image.
230
203
  * @type {boolean}
231
204
  */
232
205
  zoomable: true,
233
-
234
206
  /**
235
207
  * Enable to zoom the current image by dragging on the touch screen.
236
208
  * @type {boolean}
237
209
  */
238
210
  zoomOnTouch: true,
239
-
240
211
  /**
241
212
  * Enable to zoom the image by wheeling mouse.
242
213
  * @type {boolean}
243
214
  */
244
215
  zoomOnWheel: true,
245
-
246
216
  /**
247
217
  * Enable to slide to the next or previous image by swiping on the touch screen.
248
218
  * @type {boolean}
249
219
  */
250
220
  slideOnTouch: true,
251
-
252
221
  /**
253
222
  * Indicate if toggle the image size between its natural size
254
223
  * and initial size when double click on the image or not.
255
224
  * @type {boolean}
256
225
  */
257
226
  toggleOnDblclick: true,
258
-
259
227
  /**
260
228
  * Show the tooltip with image ratio (percentage) when zoom in or zoom out.
261
229
  * @type {boolean}
262
230
  */
263
231
  tooltip: true,
264
-
265
232
  /**
266
233
  * Enable CSS3 Transition for some special elements.
267
234
  * @type {boolean}
268
235
  */
269
236
  transition: true,
270
-
271
237
  /**
272
238
  * Define the CSS `z-index` value of viewer in modal mode.
273
239
  * @type {number}
274
240
  */
275
241
  zIndex: 2015,
276
-
277
242
  /**
278
243
  * Define the CSS `z-index` value of viewer in inline mode.
279
244
  * @type {number}
280
245
  */
281
246
  zIndexInline: 0,
282
-
283
247
  /**
284
248
  * Define the ratio when zoom the image by wheeling mouse.
285
249
  * @type {number}
286
250
  */
287
251
  zoomRatio: 0.1,
288
-
289
252
  /**
290
253
  * Define the min ratio of the image when zoom out.
291
254
  * @type {number}
292
255
  */
293
256
  minZoomRatio: 0.01,
294
-
295
257
  /**
296
258
  * Define the max ratio of the image when zoom in.
297
259
  * @type {number}
298
260
  */
299
261
  maxZoomRatio: 100,
300
-
301
262
  /**
302
263
  * Define where to get the original image URL for viewing.
303
264
  * @type {string | Function}
304
265
  */
305
266
  url: 'src',
306
-
307
267
  /**
308
268
  * Event shortcuts.
309
269
  * @type {Function}
@@ -333,12 +293,14 @@
333
293
  var WINDOW = IS_BROWSER ? window : {};
334
294
  var IS_TOUCH_DEVICE = IS_BROWSER && WINDOW.document.documentElement ? 'ontouchstart' in WINDOW.document.documentElement : false;
335
295
  var HAS_POINTER_EVENT = IS_BROWSER ? 'PointerEvent' in WINDOW : false;
336
- var NAMESPACE = 'viewer'; // Actions
296
+ var NAMESPACE = 'viewer';
337
297
 
298
+ // Actions
338
299
  var ACTION_MOVE = 'move';
339
300
  var ACTION_SWITCH = 'switch';
340
- var ACTION_ZOOM = 'zoom'; // Classes
301
+ var ACTION_ZOOM = 'zoom';
341
302
 
303
+ // Classes
342
304
  var CLASS_ACTIVE = "".concat(NAMESPACE, "-active");
343
305
  var CLASS_CLOSE = "".concat(NAMESPACE, "-close");
344
306
  var CLASS_FADE = "".concat(NAMESPACE, "-fade");
@@ -355,8 +317,9 @@
355
317
  var CLASS_MOVE = "".concat(NAMESPACE, "-move");
356
318
  var CLASS_OPEN = "".concat(NAMESPACE, "-open");
357
319
  var CLASS_SHOW = "".concat(NAMESPACE, "-show");
358
- var CLASS_TRANSITION = "".concat(NAMESPACE, "-transition"); // Native events
320
+ var CLASS_TRANSITION = "".concat(NAMESPACE, "-transition");
359
321
 
322
+ // Native events
360
323
  var EVENT_CLICK = 'click';
361
324
  var EVENT_DBLCLICK = 'dblclick';
362
325
  var EVENT_DRAG_START = 'dragstart';
@@ -372,8 +335,9 @@
372
335
  var EVENT_POINTER_UP = HAS_POINTER_EVENT ? 'pointerup pointercancel' : EVENT_TOUCH_END;
373
336
  var EVENT_RESIZE = 'resize';
374
337
  var EVENT_TRANSITION_END = 'transitionend';
375
- var EVENT_WHEEL = 'wheel'; // Custom events
338
+ var EVENT_WHEEL = 'wheel';
376
339
 
340
+ // Custom events
377
341
  var EVENT_READY = 'ready';
378
342
  var EVENT_SHOW = 'show';
379
343
  var EVENT_SHOWN = 'shown';
@@ -390,12 +354,15 @@
390
354
  var EVENT_ZOOM = 'zoom';
391
355
  var EVENT_ZOOMED = 'zoomed';
392
356
  var EVENT_PLAY = 'play';
393
- var EVENT_STOP = 'stop'; // Data keys
357
+ var EVENT_STOP = 'stop';
394
358
 
395
- var DATA_ACTION = "".concat(NAMESPACE, "Action"); // RegExps
359
+ // Data keys
360
+ var DATA_ACTION = "".concat(NAMESPACE, "Action");
396
361
 
397
- var REGEXP_SPACES = /\s\s*/; // Misc
362
+ // RegExps
363
+ var REGEXP_SPACES = /\s\s*/;
398
364
 
365
+ // Misc
399
366
  var BUTTONS = ['zoom-in', 'zoom-out', 'one-to-one', 'reset', 'prev', 'play', 'next', 'rotate-left', 'rotate-right', 'flip-horizontal', 'flip-vertical'];
400
367
 
401
368
  /**
@@ -403,54 +370,52 @@
403
370
  * @param {*} value - The value to check.
404
371
  * @returns {boolean} Returns `true` if the given value is a string, else `false`.
405
372
  */
406
-
407
373
  function isString(value) {
408
374
  return typeof value === 'string';
409
375
  }
376
+
410
377
  /**
411
378
  * Check if the given value is not a number.
412
379
  */
413
-
414
380
  var isNaN = Number.isNaN || WINDOW.isNaN;
381
+
415
382
  /**
416
383
  * Check if the given value is a number.
417
384
  * @param {*} value - The value to check.
418
385
  * @returns {boolean} Returns `true` if the given value is a number, else `false`.
419
386
  */
420
-
421
387
  function isNumber(value) {
422
388
  return typeof value === 'number' && !isNaN(value);
423
389
  }
390
+
424
391
  /**
425
392
  * Check if the given value is undefined.
426
393
  * @param {*} value - The value to check.
427
394
  * @returns {boolean} Returns `true` if the given value is undefined, else `false`.
428
395
  */
429
-
430
396
  function isUndefined(value) {
431
397
  return typeof value === 'undefined';
432
398
  }
399
+
433
400
  /**
434
401
  * Check if the given value is an object.
435
402
  * @param {*} value - The value to check.
436
403
  * @returns {boolean} Returns `true` if the given value is an object, else `false`.
437
404
  */
438
-
439
405
  function isObject(value) {
440
406
  return _typeof(value) === 'object' && value !== null;
441
407
  }
442
408
  var hasOwnProperty = Object.prototype.hasOwnProperty;
409
+
443
410
  /**
444
411
  * Check if the given value is a plain object.
445
412
  * @param {*} value - The value to check.
446
413
  * @returns {boolean} Returns `true` if the given value is a plain object, else `false`.
447
414
  */
448
-
449
415
  function isPlainObject(value) {
450
416
  if (!isObject(value)) {
451
417
  return false;
452
418
  }
453
-
454
419
  try {
455
420
  var _constructor = value.constructor;
456
421
  var prototype = _constructor.prototype;
@@ -459,30 +424,27 @@
459
424
  return false;
460
425
  }
461
426
  }
427
+
462
428
  /**
463
429
  * Check if the given value is a function.
464
430
  * @param {*} value - The value to check.
465
431
  * @returns {boolean} Returns `true` if the given value is a function, else `false`.
466
432
  */
467
-
468
433
  function isFunction(value) {
469
434
  return typeof value === 'function';
470
435
  }
436
+
471
437
  /**
472
438
  * Iterate the given data.
473
439
  * @param {*} data - The data to iterate.
474
440
  * @param {Function} callback - The process function for each element.
475
441
  * @returns {*} The original data.
476
442
  */
477
-
478
443
  function forEach(data, callback) {
479
444
  if (data && isFunction(callback)) {
480
- if (Array.isArray(data) || isNumber(data.length)
481
- /* array-like */
482
- ) {
445
+ if (Array.isArray(data) || isNumber(data.length) /* array-like */) {
483
446
  var length = data.length;
484
447
  var i;
485
-
486
448
  for (i = 0; i < length; i += 1) {
487
449
  if (callback.call(data, data[i], i, data) === false) {
488
450
  break;
@@ -494,21 +456,19 @@
494
456
  });
495
457
  }
496
458
  }
497
-
498
459
  return data;
499
460
  }
461
+
500
462
  /**
501
463
  * Extend the given object.
502
464
  * @param {*} obj - The object to be extended.
503
465
  * @param {*} args - The rest objects which will be merged to the first object.
504
466
  * @returns {Object} The extended object.
505
467
  */
506
-
507
468
  var assign = Object.assign || function assign(obj) {
508
469
  for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
509
470
  args[_key - 1] = arguments[_key];
510
471
  }
511
-
512
472
  if (isObject(obj) && args.length > 0) {
513
473
  args.forEach(function (arg) {
514
474
  if (isObject(arg)) {
@@ -518,127 +478,116 @@
518
478
  }
519
479
  });
520
480
  }
521
-
522
481
  return obj;
523
482
  };
524
483
  var REGEXP_SUFFIX = /^(?:width|height|left|top|marginLeft|marginTop)$/;
484
+
525
485
  /**
526
486
  * Apply styles to the given element.
527
487
  * @param {Element} element - The target element.
528
488
  * @param {Object} styles - The styles for applying.
529
489
  */
530
-
531
490
  function setStyle(element, styles) {
532
491
  var style = element.style;
533
492
  forEach(styles, function (value, property) {
534
493
  if (REGEXP_SUFFIX.test(property) && isNumber(value)) {
535
494
  value += 'px';
536
495
  }
537
-
538
496
  style[property] = value;
539
497
  });
540
498
  }
499
+
541
500
  /**
542
501
  * Escape a string for using in HTML.
543
502
  * @param {String} value - The string to escape.
544
503
  * @returns {String} Returns the escaped string.
545
504
  */
546
-
547
505
  function escapeHTMLEntities(value) {
548
506
  return isString(value) ? value.replace(/&(?!amp;|quot;|#39;|lt;|gt;)/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g, '&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;') : value;
549
507
  }
508
+
550
509
  /**
551
510
  * Check if the given element has a special class.
552
511
  * @param {Element} element - The element to check.
553
512
  * @param {string} value - The class to search.
554
513
  * @returns {boolean} Returns `true` if the special class was found.
555
514
  */
556
-
557
515
  function hasClass(element, value) {
558
516
  if (!element || !value) {
559
517
  return false;
560
518
  }
561
-
562
519
  return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1;
563
520
  }
521
+
564
522
  /**
565
523
  * Add classes to the given element.
566
524
  * @param {Element} element - The target element.
567
525
  * @param {string} value - The classes to be added.
568
526
  */
569
-
570
527
  function addClass(element, value) {
571
528
  if (!element || !value) {
572
529
  return;
573
530
  }
574
-
575
531
  if (isNumber(element.length)) {
576
532
  forEach(element, function (elem) {
577
533
  addClass(elem, value);
578
534
  });
579
535
  return;
580
536
  }
581
-
582
537
  if (element.classList) {
583
538
  element.classList.add(value);
584
539
  return;
585
540
  }
586
-
587
541
  var className = element.className.trim();
588
-
589
542
  if (!className) {
590
543
  element.className = value;
591
544
  } else if (className.indexOf(value) < 0) {
592
545
  element.className = "".concat(className, " ").concat(value);
593
546
  }
594
547
  }
548
+
595
549
  /**
596
550
  * Remove classes from the given element.
597
551
  * @param {Element} element - The target element.
598
552
  * @param {string} value - The classes to be removed.
599
553
  */
600
-
601
554
  function removeClass(element, value) {
602
555
  if (!element || !value) {
603
556
  return;
604
557
  }
605
-
606
558
  if (isNumber(element.length)) {
607
559
  forEach(element, function (elem) {
608
560
  removeClass(elem, value);
609
561
  });
610
562
  return;
611
563
  }
612
-
613
564
  if (element.classList) {
614
565
  element.classList.remove(value);
615
566
  return;
616
567
  }
617
-
618
568
  if (element.className.indexOf(value) >= 0) {
619
569
  element.className = element.className.replace(value, '');
620
570
  }
621
571
  }
572
+
622
573
  /**
623
574
  * Add or remove classes from the given element.
624
575
  * @param {Element} element - The target element.
625
576
  * @param {string} value - The classes to be toggled.
626
577
  * @param {boolean} added - Add only.
627
578
  */
628
-
629
579
  function toggleClass(element, value, added) {
630
580
  if (!value) {
631
581
  return;
632
582
  }
633
-
634
583
  if (isNumber(element.length)) {
635
584
  forEach(element, function (elem) {
636
585
  toggleClass(elem, value, added);
637
586
  });
638
587
  return;
639
- } // IE10-11 doesn't support the second parameter of `classList.toggle`
640
-
588
+ }
641
589
 
590
+ // IE10-11 doesn't support the second parameter of `classList.toggle`
642
591
  if (added) {
643
592
  addClass(element, value);
644
593
  } else {
@@ -646,40 +595,38 @@
646
595
  }
647
596
  }
648
597
  var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g;
598
+
649
599
  /**
650
600
  * Transform the given string from camelCase to kebab-case
651
601
  * @param {string} value - The value to transform.
652
602
  * @returns {string} The transformed value.
653
603
  */
654
-
655
604
  function hyphenate(value) {
656
605
  return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase();
657
606
  }
607
+
658
608
  /**
659
609
  * Get data from the given element.
660
610
  * @param {Element} element - The target element.
661
611
  * @param {string} name - The data key to get.
662
612
  * @returns {string} The data value.
663
613
  */
664
-
665
614
  function getData(element, name) {
666
615
  if (isObject(element[name])) {
667
616
  return element[name];
668
617
  }
669
-
670
618
  if (element.dataset) {
671
619
  return element.dataset[name];
672
620
  }
673
-
674
621
  return element.getAttribute("data-".concat(hyphenate(name)));
675
622
  }
623
+
676
624
  /**
677
625
  * Set data to the given element.
678
626
  * @param {Element} element - The target element.
679
627
  * @param {string} name - The data key to set.
680
628
  * @param {string} data - The data value.
681
629
  */
682
-
683
630
  function setData(element, name, data) {
684
631
  if (isObject(data)) {
685
632
  element[name] = data;
@@ -689,36 +636,30 @@
689
636
  element.setAttribute("data-".concat(hyphenate(name)), data);
690
637
  }
691
638
  }
692
-
693
639
  var onceSupported = function () {
694
640
  var supported = false;
695
-
696
641
  if (IS_BROWSER) {
697
642
  var once = false;
698
-
699
643
  var listener = function listener() {};
700
-
701
644
  var options = Object.defineProperty({}, 'once', {
702
645
  get: function get() {
703
646
  supported = true;
704
647
  return once;
705
648
  },
706
-
707
649
  /**
708
650
  * This setter can fix a `TypeError` in strict mode
709
651
  * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only}
710
652
  * @param {boolean} value - The value to set
711
- */
712
- set: function set(value) {
653
+ */set: function set(value) {
713
654
  once = value;
714
655
  }
715
656
  });
716
657
  WINDOW.addEventListener('test', listener, options);
717
658
  WINDOW.removeEventListener('test', listener, options);
718
659
  }
719
-
720
660
  return supported;
721
661
  }();
662
+
722
663
  /**
723
664
  * Remove event listener from the target element.
724
665
  * @param {Element} element - The event target.
@@ -726,32 +667,27 @@
726
667
  * @param {Function} listener - The event listener.
727
668
  * @param {Object} options - The event options.
728
669
  */
729
-
730
-
731
670
  function removeListener(element, type, listener) {
732
671
  var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
733
672
  var handler = listener;
734
673
  type.trim().split(REGEXP_SPACES).forEach(function (event) {
735
674
  if (!onceSupported) {
736
675
  var listeners = element.listeners;
737
-
738
676
  if (listeners && listeners[event] && listeners[event][listener]) {
739
677
  handler = listeners[event][listener];
740
678
  delete listeners[event][listener];
741
-
742
679
  if (Object.keys(listeners[event]).length === 0) {
743
680
  delete listeners[event];
744
681
  }
745
-
746
682
  if (Object.keys(listeners).length === 0) {
747
683
  delete element.listeners;
748
684
  }
749
685
  }
750
686
  }
751
-
752
687
  element.removeEventListener(event, handler, options);
753
688
  });
754
689
  }
690
+
755
691
  /**
756
692
  * Add event listener to the target element.
757
693
  * @param {Element} element - The event target.
@@ -759,41 +695,34 @@
759
695
  * @param {Function} listener - The event listener.
760
696
  * @param {Object} options - The event options.
761
697
  */
762
-
763
698
  function addListener(element, type, listener) {
764
699
  var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
765
700
  var _handler = listener;
766
701
  type.trim().split(REGEXP_SPACES).forEach(function (event) {
767
702
  if (options.once && !onceSupported) {
768
703
  var _element$listeners = element.listeners,
769
- listeners = _element$listeners === void 0 ? {} : _element$listeners;
770
-
704
+ listeners = _element$listeners === void 0 ? {} : _element$listeners;
771
705
  _handler = function handler() {
772
706
  delete listeners[event][listener];
773
707
  element.removeEventListener(event, _handler, options);
774
-
775
708
  for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
776
709
  args[_key2] = arguments[_key2];
777
710
  }
778
-
779
711
  listener.apply(element, args);
780
712
  };
781
-
782
713
  if (!listeners[event]) {
783
714
  listeners[event] = {};
784
715
  }
785
-
786
716
  if (listeners[event][listener]) {
787
717
  element.removeEventListener(event, listeners[event][listener], options);
788
718
  }
789
-
790
719
  listeners[event][listener] = _handler;
791
720
  element.listeners = listeners;
792
721
  }
793
-
794
722
  element.addEventListener(event, _handler, options);
795
723
  });
796
724
  }
725
+
797
726
  /**
798
727
  * Dispatch event on the target element.
799
728
  * @param {Element} element - The event target.
@@ -802,10 +731,10 @@
802
731
  * @param {Object} options - The additional event options.
803
732
  * @returns {boolean} Indicate if the event is default prevented or not.
804
733
  */
805
-
806
734
  function dispatchEvent(element, type, data, options) {
807
- var event; // Event and CustomEvent on IE9-11 are global objects, not constructors
735
+ var event;
808
736
 
737
+ // Event and CustomEvent on IE9-11 are global objects, not constructors
809
738
  if (isFunction(Event) && isFunction(CustomEvent)) {
810
739
  event = new CustomEvent(type, _objectSpread2({
811
740
  bubbles: true,
@@ -816,15 +745,14 @@
816
745
  event = document.createEvent('CustomEvent');
817
746
  event.initCustomEvent(type, true, true, data);
818
747
  }
819
-
820
748
  return element.dispatchEvent(event);
821
749
  }
750
+
822
751
  /**
823
752
  * Get the offset base on the document.
824
753
  * @param {Element} element - The target element.
825
754
  * @returns {Object} The offset data.
826
755
  */
827
-
828
756
  function getOffset(element) {
829
757
  var box = element.getBoundingClientRect();
830
758
  return {
@@ -832,41 +760,36 @@
832
760
  top: box.top + (window.pageYOffset - document.documentElement.clientTop)
833
761
  };
834
762
  }
763
+
835
764
  /**
836
765
  * Get transforms base on the given object.
837
766
  * @param {Object} obj - The target object.
838
767
  * @returns {string} A string contains transform values.
839
768
  */
840
-
841
769
  function getTransforms(_ref) {
842
770
  var rotate = _ref.rotate,
843
- scaleX = _ref.scaleX,
844
- scaleY = _ref.scaleY,
845
- translateX = _ref.translateX,
846
- translateY = _ref.translateY;
771
+ scaleX = _ref.scaleX,
772
+ scaleY = _ref.scaleY,
773
+ translateX = _ref.translateX,
774
+ translateY = _ref.translateY;
847
775
  var values = [];
848
-
849
776
  if (isNumber(translateX) && translateX !== 0) {
850
777
  values.push("translateX(".concat(translateX, "px)"));
851
778
  }
852
-
853
779
  if (isNumber(translateY) && translateY !== 0) {
854
780
  values.push("translateY(".concat(translateY, "px)"));
855
- } // Rotate should come first before scale to match orientation transform
856
-
781
+ }
857
782
 
783
+ // Rotate should come first before scale to match orientation transform
858
784
  if (isNumber(rotate) && rotate !== 0) {
859
785
  values.push("rotate(".concat(rotate, "deg)"));
860
786
  }
861
-
862
787
  if (isNumber(scaleX) && scaleX !== 1) {
863
788
  values.push("scaleX(".concat(scaleX, ")"));
864
789
  }
865
-
866
790
  if (isNumber(scaleY) && scaleY !== 1) {
867
791
  values.push("scaleY(".concat(scaleY, ")"));
868
792
  }
869
-
870
793
  var transform = values.length ? values.join(' ') : 'none';
871
794
  return {
872
795
  WebkitTransform: transform,
@@ -874,6 +797,7 @@
874
797
  transform: transform
875
798
  };
876
799
  }
800
+
877
801
  /**
878
802
  * Get an image name from an image url.
879
803
  * @param {string} url - The target url.
@@ -882,11 +806,11 @@
882
806
  * getImageNameFromURL('https://domain.com/path/to/picture.jpg?size=1280×960')
883
807
  * @returns {string} A string contains the image name.
884
808
  */
885
-
886
809
  function getImageNameFromURL(url) {
887
810
  return isString(url) ? decodeURIComponent(url.replace(/^.*\//, '').replace(/[?&#].*$/, '')) : '';
888
811
  }
889
812
  var IS_SAFARI = WINDOW.navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(WINDOW.navigator.userAgent);
813
+
890
814
  /**
891
815
  * Get an image's natural sizes.
892
816
  * @param {string} image - The target image.
@@ -894,72 +818,63 @@
894
818
  * @param {Function} callback - The callback function.
895
819
  * @returns {HTMLImageElement} The new image.
896
820
  */
897
-
898
821
  function getImageNaturalSizes(image, options, callback) {
899
- var newImage = document.createElement('img'); // Modern browsers (except Safari)
822
+ var newImage = document.createElement('img');
900
823
 
824
+ // Modern browsers (except Safari)
901
825
  if (image.naturalWidth && !IS_SAFARI) {
902
826
  callback(image.naturalWidth, image.naturalHeight);
903
827
  return newImage;
904
828
  }
905
-
906
829
  var body = document.body || document.documentElement;
907
-
908
830
  newImage.onload = function () {
909
831
  callback(newImage.width, newImage.height);
910
-
911
832
  if (!IS_SAFARI) {
912
833
  body.removeChild(newImage);
913
834
  }
914
835
  };
915
-
916
836
  forEach(options.inheritedAttributes, function (name) {
917
837
  var value = image.getAttribute(name);
918
-
919
838
  if (value !== null) {
920
839
  newImage.setAttribute(name, value);
921
840
  }
922
841
  });
923
- newImage.src = image.src; // iOS Safari will convert the image automatically
924
- // with its orientation once append it into DOM
842
+ newImage.src = image.src;
925
843
 
844
+ // iOS Safari will convert the image automatically
845
+ // with its orientation once append it into DOM
926
846
  if (!IS_SAFARI) {
927
847
  newImage.style.cssText = 'left:0;' + 'max-height:none!important;' + 'max-width:none!important;' + 'min-height:0!important;' + 'min-width:0!important;' + 'opacity:0;' + 'position:absolute;' + 'top:0;' + 'z-index:-1;';
928
848
  body.appendChild(newImage);
929
849
  }
930
-
931
850
  return newImage;
932
851
  }
852
+
933
853
  /**
934
854
  * Get the related class name of a responsive type number.
935
855
  * @param {string} type - The responsive type.
936
856
  * @returns {string} The related class name.
937
857
  */
938
-
939
858
  function getResponsiveClass(type) {
940
859
  switch (type) {
941
860
  case 2:
942
861
  return CLASS_HIDE_XS_DOWN;
943
-
944
862
  case 3:
945
863
  return CLASS_HIDE_SM_DOWN;
946
-
947
864
  case 4:
948
865
  return CLASS_HIDE_MD_DOWN;
949
-
950
866
  default:
951
867
  return '';
952
868
  }
953
869
  }
870
+
954
871
  /**
955
872
  * Get the max ratio of a group of pointers.
956
873
  * @param {string} pointers - The target pointers.
957
874
  * @returns {number} The result ratio.
958
875
  */
959
-
960
876
  function getMaxZoomRatio(pointers) {
961
877
  var pointers2 = _objectSpread2({}, pointers);
962
-
963
878
  var ratios = [];
964
879
  forEach(pointers, function (pointer, pointerId) {
965
880
  delete pointers2[pointerId];
@@ -979,16 +894,16 @@
979
894
  });
980
895
  return ratios[0];
981
896
  }
897
+
982
898
  /**
983
899
  * Get a pointer from an event object.
984
900
  * @param {Object} event - The target event object.
985
901
  * @param {boolean} endOnly - Indicates if only returns the end point coordinate or not.
986
902
  * @returns {Object} The result pointer contains start and/or end point coordinates.
987
903
  */
988
-
989
904
  function getPointer(_ref2, endOnly) {
990
905
  var pageX = _ref2.pageX,
991
- pageY = _ref2.pageY;
906
+ pageY = _ref2.pageY;
992
907
  var end = {
993
908
  endX: pageX,
994
909
  endY: pageY
@@ -999,19 +914,19 @@
999
914
  startY: pageY
1000
915
  }, end);
1001
916
  }
917
+
1002
918
  /**
1003
919
  * Get the center point coordinate of a group of pointers.
1004
920
  * @param {Object} pointers - The target pointers.
1005
921
  * @returns {Object} The center point coordinate.
1006
922
  */
1007
-
1008
923
  function getPointersCenter(pointers) {
1009
924
  var pageX = 0;
1010
925
  var pageY = 0;
1011
926
  var count = 0;
1012
927
  forEach(pointers, function (_ref3) {
1013
928
  var startX = _ref3.startX,
1014
- startY = _ref3.startY;
929
+ startY = _ref3.startY;
1015
930
  pageX += startX;
1016
931
  pageY += startY;
1017
932
  count += 1;
@@ -1047,9 +962,8 @@
1047
962
  },
1048
963
  initViewer: function initViewer() {
1049
964
  var options = this.options,
1050
- parent = this.parent;
965
+ parent = this.parent;
1051
966
  var viewerData;
1052
-
1053
967
  if (options.inline) {
1054
968
  viewerData = {
1055
969
  width: Math.max(parent.offsetWidth, options.minWidth),
@@ -1057,11 +971,9 @@
1057
971
  };
1058
972
  this.parentData = viewerData;
1059
973
  }
1060
-
1061
974
  if (this.fulled || !viewerData) {
1062
975
  viewerData = this.containerData;
1063
976
  }
1064
-
1065
977
  this.viewerData = assign({}, viewerData);
1066
978
  },
1067
979
  renderViewer: function renderViewer() {
@@ -1071,40 +983,37 @@
1071
983
  },
1072
984
  initList: function initList() {
1073
985
  var _this = this;
1074
-
1075
986
  var element = this.element,
1076
- options = this.options,
1077
- list = this.list;
1078
- var items = []; // initList may be called in this.update, so should keep idempotent
987
+ options = this.options,
988
+ list = this.list;
989
+ var items = [];
1079
990
 
991
+ // initList may be called in this.update, so should keep idempotent
1080
992
  list.innerHTML = '';
1081
993
  forEach(this.images, function (image, index) {
1082
994
  var src = image.src;
1083
995
  var alt = image.alt || getImageNameFromURL(src);
1084
-
1085
996
  var url = _this.getImageURL(image);
1086
-
1087
997
  if (src || url) {
1088
998
  var item = document.createElement('li');
1089
999
  var img = document.createElement('img');
1090
1000
  forEach(options.inheritedAttributes, function (name) {
1091
1001
  var value = image.getAttribute(name);
1092
-
1093
1002
  if (value !== null) {
1094
1003
  img.setAttribute(name, value);
1095
1004
  }
1096
1005
  });
1097
- img.src = src || url;
1006
+ if (options.navbar) {
1007
+ img.src = src || url;
1008
+ }
1098
1009
  img.alt = alt;
1099
1010
  img.setAttribute('data-original-url', url || src);
1100
1011
  item.setAttribute('data-index', index);
1101
1012
  item.setAttribute('data-viewer-action', 'view');
1102
1013
  item.setAttribute('role', 'button');
1103
-
1104
1014
  if (options.keyboard) {
1105
1015
  item.setAttribute('tabindex', 0);
1106
1016
  }
1107
-
1108
1017
  item.appendChild(img);
1109
1018
  list.appendChild(item);
1110
1019
  items.push(item);
@@ -1116,25 +1025,20 @@
1116
1025
  var onLoad;
1117
1026
  var onError;
1118
1027
  setData(image, 'filled', true);
1119
-
1120
1028
  if (options.loading) {
1121
1029
  addClass(item, CLASS_LOADING);
1122
1030
  }
1123
-
1124
1031
  addListener(image, EVENT_LOAD, onLoad = function onLoad(event) {
1125
1032
  removeListener(image, EVENT_ERROR, onError);
1126
-
1127
1033
  if (options.loading) {
1128
1034
  removeClass(item, CLASS_LOADING);
1129
1035
  }
1130
-
1131
1036
  _this.loadImage(event);
1132
1037
  }, {
1133
1038
  once: true
1134
1039
  });
1135
1040
  addListener(image, EVENT_ERROR, onError = function onError() {
1136
1041
  removeListener(image, EVENT_LOAD, onLoad);
1137
-
1138
1042
  if (options.loading) {
1139
1043
  removeClass(item, CLASS_LOADING);
1140
1044
  }
@@ -1142,7 +1046,6 @@
1142
1046
  once: true
1143
1047
  });
1144
1048
  });
1145
-
1146
1049
  if (options.transition) {
1147
1050
  addListener(element, EVENT_VIEWED, function () {
1148
1051
  addClass(list, CLASS_TRANSITION);
@@ -1154,16 +1057,15 @@
1154
1057
  renderList: function renderList() {
1155
1058
  var index = this.index;
1156
1059
  var item = this.items[index];
1157
-
1158
1060
  if (!item) {
1159
1061
  return;
1160
1062
  }
1161
-
1162
1063
  var next = item.nextElementSibling;
1163
1064
  var gutter = parseInt(window.getComputedStyle(next || item).marginLeft, 10);
1164
1065
  var offsetWidth = item.offsetWidth;
1165
- var outerWidth = offsetWidth + gutter; // Place the active item in the center of the screen
1066
+ var outerWidth = offsetWidth + gutter;
1166
1067
 
1068
+ // Place the active item in the center of the screen
1167
1069
  setStyle(this.list, assign({
1168
1070
  width: outerWidth * this.length - gutter
1169
1071
  }, getTransforms({
@@ -1180,10 +1082,9 @@
1180
1082
  },
1181
1083
  initImage: function initImage(done) {
1182
1084
  var _this2 = this;
1183
-
1184
1085
  var options = this.options,
1185
- image = this.image,
1186
- viewerData = this.viewerData;
1086
+ image = this.image,
1087
+ viewerData = this.viewerData;
1187
1088
  var footerHeight = this.footer.offsetHeight;
1188
1089
  var viewerWidth = viewerData.width;
1189
1090
  var viewerHeight = Math.max(viewerData.height - footerHeight, footerHeight);
@@ -1196,18 +1097,18 @@
1196
1097
  };
1197
1098
  sizingImage = getImageNaturalSizes(image, options, function (naturalWidth, naturalHeight) {
1198
1099
  var aspectRatio = naturalWidth / naturalHeight;
1100
+ var initialCoverage = Math.max(0, Math.min(1, options.initialCoverage));
1199
1101
  var width = viewerWidth;
1200
1102
  var height = viewerHeight;
1201
1103
  _this2.imageInitializing = false;
1202
-
1203
1104
  if (viewerHeight * aspectRatio > viewerWidth) {
1204
1105
  height = viewerWidth / aspectRatio;
1205
1106
  } else {
1206
1107
  width = viewerHeight * aspectRatio;
1207
1108
  }
1208
-
1209
- width = Math.min(width * 0.9, naturalWidth);
1210
- height = Math.min(height * 0.9, naturalHeight);
1109
+ initialCoverage = isNumber(initialCoverage) ? initialCoverage : 0.9;
1110
+ width = Math.min(width * initialCoverage, naturalWidth);
1111
+ height = Math.min(height * initialCoverage, naturalHeight);
1211
1112
  var left = (viewerWidth - width) / 2;
1212
1113
  var top = (viewerHeight - height) / 2;
1213
1114
  var imageData = {
@@ -1224,22 +1125,18 @@
1224
1125
  naturalHeight: naturalHeight
1225
1126
  };
1226
1127
  var initialImageData = assign({}, imageData);
1227
-
1228
1128
  if (options.rotatable) {
1229
1129
  imageData.rotate = oldImageData.rotate || 0;
1230
1130
  initialImageData.rotate = 0;
1231
1131
  }
1232
-
1233
1132
  if (options.scalable) {
1234
1133
  imageData.scaleX = oldImageData.scaleX || 1;
1235
1134
  imageData.scaleY = oldImageData.scaleY || 1;
1236
1135
  initialImageData.scaleX = 1;
1237
1136
  initialImageData.scaleY = 1;
1238
1137
  }
1239
-
1240
1138
  _this2.imageData = imageData;
1241
1139
  _this2.initialImageData = initialImageData;
1242
-
1243
1140
  if (done) {
1244
1141
  done();
1245
1142
  }
@@ -1247,9 +1144,8 @@
1247
1144
  },
1248
1145
  renderImage: function renderImage(done) {
1249
1146
  var _this3 = this;
1250
-
1251
1147
  var image = this.image,
1252
- imageData = this.imageData;
1148
+ imageData = this.imageData;
1253
1149
  setStyle(image, assign({
1254
1150
  width: imageData.width,
1255
1151
  height: imageData.height,
@@ -1257,14 +1153,12 @@
1257
1153
  marginLeft: imageData.x,
1258
1154
  marginTop: imageData.y
1259
1155
  }, getTransforms(imageData)));
1260
-
1261
1156
  if (done) {
1262
1157
  if ((this.viewing || this.moving || this.rotating || this.scaling || this.zooming) && this.options.transition && hasClass(image, CLASS_TRANSITION)) {
1263
1158
  var onTransitionEnd = function onTransitionEnd() {
1264
1159
  _this3.imageRendering = false;
1265
1160
  done();
1266
1161
  };
1267
-
1268
1162
  this.imageRendering = {
1269
1163
  abort: function abort() {
1270
1164
  removeListener(image, EVENT_TRANSITION_END, onTransitionEnd);
@@ -1282,11 +1176,9 @@
1282
1176
  // this.image only defined after viewed
1283
1177
  if (this.viewing || this.viewed) {
1284
1178
  var image = this.image;
1285
-
1286
1179
  if (this.viewing) {
1287
1180
  this.viewing.abort();
1288
1181
  }
1289
-
1290
1182
  image.parentNode.removeChild(image);
1291
1183
  this.image = null;
1292
1184
  }
@@ -1296,8 +1188,8 @@
1296
1188
  var events = {
1297
1189
  bind: function bind() {
1298
1190
  var options = this.options,
1299
- viewer = this.viewer,
1300
- canvas = this.canvas;
1191
+ viewer = this.viewer,
1192
+ canvas = this.canvas;
1301
1193
  var document = this.element.ownerDocument;
1302
1194
  addListener(viewer, EVENT_CLICK, this.onClick = this.click.bind(this));
1303
1195
  addListener(viewer, EVENT_DRAG_START, this.onDragStart = this.dragstart.bind(this));
@@ -1306,22 +1198,20 @@
1306
1198
  addListener(document, EVENT_POINTER_UP, this.onPointerUp = this.pointerup.bind(this));
1307
1199
  addListener(document, EVENT_KEY_DOWN, this.onKeyDown = this.keydown.bind(this));
1308
1200
  addListener(window, EVENT_RESIZE, this.onResize = this.resize.bind(this));
1309
-
1310
1201
  if (options.zoomable && options.zoomOnWheel) {
1311
1202
  addListener(viewer, EVENT_WHEEL, this.onWheel = this.wheel.bind(this), {
1312
1203
  passive: false,
1313
1204
  capture: true
1314
1205
  });
1315
1206
  }
1316
-
1317
1207
  if (options.toggleOnDblclick) {
1318
1208
  addListener(canvas, EVENT_DBLCLICK, this.onDblclick = this.dblclick.bind(this));
1319
1209
  }
1320
1210
  },
1321
1211
  unbind: function unbind() {
1322
1212
  var options = this.options,
1323
- viewer = this.viewer,
1324
- canvas = this.canvas;
1213
+ viewer = this.viewer,
1214
+ canvas = this.canvas;
1325
1215
  var document = this.element.ownerDocument;
1326
1216
  removeListener(viewer, EVENT_CLICK, this.onClick);
1327
1217
  removeListener(viewer, EVENT_DRAG_START, this.onDragStart);
@@ -1330,14 +1220,12 @@
1330
1220
  removeListener(document, EVENT_POINTER_UP, this.onPointerUp);
1331
1221
  removeListener(document, EVENT_KEY_DOWN, this.onKeyDown);
1332
1222
  removeListener(window, EVENT_RESIZE, this.onResize);
1333
-
1334
1223
  if (options.zoomable && options.zoomOnWheel) {
1335
1224
  removeListener(viewer, EVENT_WHEEL, this.onWheel, {
1336
1225
  passive: false,
1337
1226
  capture: true
1338
1227
  });
1339
1228
  }
1340
-
1341
1229
  if (options.toggleOnDblclick) {
1342
1230
  removeListener(canvas, EVENT_DBLCLICK, this.onDblclick);
1343
1231
  }
@@ -1347,20 +1235,18 @@
1347
1235
  var handlers = {
1348
1236
  click: function click(event) {
1349
1237
  var options = this.options,
1350
- imageData = this.imageData;
1238
+ imageData = this.imageData;
1351
1239
  var target = event.target;
1352
1240
  var action = getData(target, DATA_ACTION);
1353
-
1354
1241
  if (!action && target.localName === 'img' && target.parentElement.localName === 'li') {
1355
1242
  target = target.parentElement;
1356
1243
  action = getData(target, DATA_ACTION);
1357
- } // Cancel the emulated click when the native click event was triggered.
1358
-
1244
+ }
1359
1245
 
1246
+ // Cancel the emulated click when the native click event was triggered.
1360
1247
  if (IS_TOUCH_DEVICE && event.isTrusted && target === this.canvas) {
1361
1248
  clearTimeout(this.clickCanvasTimeout);
1362
1249
  }
1363
-
1364
1250
  switch (action) {
1365
1251
  case 'mix':
1366
1252
  if (this.played) {
@@ -1374,115 +1260,91 @@
1374
1260
  } else {
1375
1261
  this.hide();
1376
1262
  }
1377
-
1378
1263
  break;
1379
-
1380
1264
  case 'hide':
1381
1265
  this.hide();
1382
1266
  break;
1383
-
1384
1267
  case 'view':
1385
1268
  this.view(getData(target, 'index'));
1386
1269
  break;
1387
-
1388
1270
  case 'zoom-in':
1389
1271
  this.zoom(0.1, true);
1390
1272
  break;
1391
-
1392
1273
  case 'zoom-out':
1393
1274
  this.zoom(-0.1, true);
1394
1275
  break;
1395
-
1396
1276
  case 'one-to-one':
1397
1277
  this.toggle();
1398
1278
  break;
1399
-
1400
1279
  case 'reset':
1401
1280
  this.reset();
1402
1281
  break;
1403
-
1404
1282
  case 'prev':
1405
1283
  this.prev(options.loop);
1406
1284
  break;
1407
-
1408
1285
  case 'play':
1409
1286
  this.play(options.fullscreen);
1410
1287
  break;
1411
-
1412
1288
  case 'next':
1413
1289
  this.next(options.loop);
1414
1290
  break;
1415
-
1416
1291
  case 'rotate-left':
1417
1292
  this.rotate(-90);
1418
1293
  break;
1419
-
1420
1294
  case 'rotate-right':
1421
1295
  this.rotate(90);
1422
1296
  break;
1423
-
1424
1297
  case 'flip-horizontal':
1425
1298
  this.scaleX(-imageData.scaleX || -1);
1426
1299
  break;
1427
-
1428
1300
  case 'flip-vertical':
1429
1301
  this.scaleY(-imageData.scaleY || -1);
1430
1302
  break;
1431
-
1432
1303
  default:
1433
1304
  if (this.played) {
1434
1305
  this.stop();
1435
1306
  }
1436
-
1437
1307
  }
1438
1308
  },
1439
1309
  dblclick: function dblclick(event) {
1440
1310
  event.preventDefault();
1441
-
1442
1311
  if (this.viewed && event.target === this.image) {
1443
1312
  // Cancel the emulated double click when the native dblclick event was triggered.
1444
1313
  if (IS_TOUCH_DEVICE && event.isTrusted) {
1445
1314
  clearTimeout(this.doubleClickImageTimeout);
1446
- } // XXX: No pageX/Y properties in custom event, fallback to the original event.
1447
-
1315
+ }
1448
1316
 
1317
+ // XXX: No pageX/Y properties in custom event, fallback to the original event.
1449
1318
  this.toggle(event.isTrusted ? event : event.detail && event.detail.originalEvent);
1450
1319
  }
1451
1320
  },
1452
1321
  load: function load() {
1453
1322
  var _this = this;
1454
-
1455
1323
  if (this.timeout) {
1456
1324
  clearTimeout(this.timeout);
1457
1325
  this.timeout = false;
1458
1326
  }
1459
-
1460
1327
  var element = this.element,
1461
- options = this.options,
1462
- image = this.image,
1463
- index = this.index,
1464
- viewerData = this.viewerData;
1328
+ options = this.options,
1329
+ image = this.image,
1330
+ index = this.index,
1331
+ viewerData = this.viewerData;
1465
1332
  removeClass(image, CLASS_INVISIBLE);
1466
-
1467
1333
  if (options.loading) {
1468
1334
  removeClass(this.canvas, CLASS_LOADING);
1469
1335
  }
1470
-
1471
1336
  image.style.cssText = 'height:0;' + "margin-left:".concat(viewerData.width / 2, "px;") + "margin-top:".concat(viewerData.height / 2, "px;") + 'max-width:none!important;' + 'position:relative;' + 'width:0;';
1472
1337
  this.initImage(function () {
1473
1338
  toggleClass(image, CLASS_MOVE, options.movable);
1474
1339
  toggleClass(image, CLASS_TRANSITION, options.transition);
1475
-
1476
1340
  _this.renderImage(function () {
1477
1341
  _this.viewed = true;
1478
1342
  _this.viewing = false;
1479
-
1480
1343
  if (isFunction(options.viewed)) {
1481
1344
  addListener(element, EVENT_VIEWED, options.viewed, {
1482
1345
  once: true
1483
1346
  });
1484
1347
  }
1485
-
1486
1348
  dispatchEvent(element, EVENT_VIEWED, {
1487
1349
  originalImage: _this.images[index],
1488
1350
  index: index,
@@ -1503,7 +1365,6 @@
1503
1365
  var aspectRatio = naturalWidth / naturalHeight;
1504
1366
  var width = parentWidth;
1505
1367
  var height = parentHeight;
1506
-
1507
1368
  if (parentHeight * aspectRatio > parentWidth) {
1508
1369
  if (filled) {
1509
1370
  width = parentHeight * aspectRatio;
@@ -1515,7 +1376,6 @@
1515
1376
  } else {
1516
1377
  width = parentHeight * aspectRatio;
1517
1378
  }
1518
-
1519
1379
  setStyle(image, assign({
1520
1380
  width: width,
1521
1381
  height: height
@@ -1527,27 +1387,21 @@
1527
1387
  },
1528
1388
  keydown: function keydown(event) {
1529
1389
  var options = this.options;
1530
-
1531
1390
  if (!options.keyboard) {
1532
1391
  return;
1533
1392
  }
1534
-
1535
1393
  var keyCode = event.keyCode || event.which || event.charCode;
1536
-
1537
1394
  switch (keyCode) {
1538
1395
  // Enter
1539
1396
  case 13:
1540
1397
  if (this.viewer.contains(event.target)) {
1541
1398
  this.click(event);
1542
1399
  }
1543
-
1544
1400
  break;
1545
1401
  }
1546
-
1547
1402
  if (!this.fulled) {
1548
1403
  return;
1549
1404
  }
1550
-
1551
1405
  switch (keyCode) {
1552
1406
  // Escape
1553
1407
  case 27:
@@ -1560,54 +1414,62 @@
1560
1414
  } else {
1561
1415
  this.hide();
1562
1416
  }
1563
-
1564
1417
  break;
1565
- // Space
1566
1418
 
1419
+ // Space
1567
1420
  case 32:
1568
1421
  if (this.played) {
1569
1422
  this.stop();
1570
1423
  }
1571
-
1572
1424
  break;
1573
- // ArrowLeft
1574
1425
 
1426
+ // ArrowLeft
1575
1427
  case 37:
1576
- this.prev(options.loop);
1428
+ if (this.played && this.playing) {
1429
+ this.playing.prev();
1430
+ } else {
1431
+ this.prev(options.loop);
1432
+ }
1577
1433
  break;
1578
- // ArrowUp
1579
1434
 
1435
+ // ArrowUp
1580
1436
  case 38:
1581
1437
  // Prevent scroll on Firefox
1582
- event.preventDefault(); // Zoom in
1438
+ event.preventDefault();
1583
1439
 
1440
+ // Zoom in
1584
1441
  this.zoom(options.zoomRatio, true);
1585
1442
  break;
1586
- // ArrowRight
1587
1443
 
1444
+ // ArrowRight
1588
1445
  case 39:
1589
- this.next(options.loop);
1446
+ if (this.played && this.playing) {
1447
+ this.playing.next();
1448
+ } else {
1449
+ this.next(options.loop);
1450
+ }
1590
1451
  break;
1591
- // ArrowDown
1592
1452
 
1453
+ // ArrowDown
1593
1454
  case 40:
1594
1455
  // Prevent scroll on Firefox
1595
- event.preventDefault(); // Zoom out
1456
+ event.preventDefault();
1596
1457
 
1458
+ // Zoom out
1597
1459
  this.zoom(-options.zoomRatio, true);
1598
1460
  break;
1461
+
1599
1462
  // Ctrl + 0
1463
+ case 48:
1464
+ // Fall through
1600
1465
 
1601
- case 48: // Fall through
1602
1466
  // Ctrl + 1
1603
1467
  // eslint-disable-next-line no-fallthrough
1604
-
1605
1468
  case 49:
1606
1469
  if (event.ctrlKey) {
1607
1470
  event.preventDefault();
1608
1471
  this.toggle();
1609
1472
  }
1610
-
1611
1473
  break;
1612
1474
  }
1613
1475
  },
@@ -1618,20 +1480,23 @@
1618
1480
  },
1619
1481
  pointerdown: function pointerdown(event) {
1620
1482
  var options = this.options,
1621
- pointers = this.pointers;
1483
+ pointers = this.pointers;
1622
1484
  var buttons = event.buttons,
1623
- button = event.button;
1485
+ button = event.button;
1486
+ if (!this.viewed || this.showing || this.viewing || this.hiding
1487
+
1488
+ // Handle mouse event and pointer event and ignore touch event
1489
+ || (event.type === 'mousedown' || event.type === 'pointerdown' && event.pointerType === 'mouse') && (
1490
+ // No primary button (Usually the left button)
1491
+ isNumber(buttons) && buttons !== 1 || isNumber(button) && button !== 0
1624
1492
 
1625
- if (!this.viewed || this.showing || this.viewing || this.hiding // Handle mouse event and pointer event and ignore touch event
1626
- || (event.type === 'mousedown' || event.type === 'pointerdown' && event.pointerType === 'mouse') && ( // No primary button (Usually the left button)
1627
- isNumber(buttons) && buttons !== 1 || isNumber(button) && button !== 0 // Open context menu
1493
+ // Open context menu
1628
1494
  || event.ctrlKey)) {
1629
1495
  return;
1630
- } // Prevent default behaviours as page zooming in touch devices.
1631
-
1496
+ }
1632
1497
 
1498
+ // Prevent default behaviours as page zooming in touch devices.
1633
1499
  event.preventDefault();
1634
-
1635
1500
  if (event.changedTouches) {
1636
1501
  forEach(event.changedTouches, function (touch) {
1637
1502
  pointers[touch.identifier] = getPointer(touch);
@@ -1639,31 +1504,24 @@
1639
1504
  } else {
1640
1505
  pointers[event.pointerId || 0] = getPointer(event);
1641
1506
  }
1642
-
1643
1507
  var action = options.movable ? ACTION_MOVE : false;
1644
-
1645
1508
  if (options.zoomOnTouch && options.zoomable && Object.keys(pointers).length > 1) {
1646
1509
  action = ACTION_ZOOM;
1647
1510
  } else if (options.slideOnTouch && (event.pointerType === 'touch' || event.type === 'touchstart') && this.isSwitchable()) {
1648
1511
  action = ACTION_SWITCH;
1649
1512
  }
1650
-
1651
1513
  if (options.transition && (action === ACTION_MOVE || action === ACTION_ZOOM)) {
1652
1514
  removeClass(this.image, CLASS_TRANSITION);
1653
1515
  }
1654
-
1655
1516
  this.action = action;
1656
1517
  },
1657
1518
  pointermove: function pointermove(event) {
1658
1519
  var pointers = this.pointers,
1659
- action = this.action;
1660
-
1520
+ action = this.action;
1661
1521
  if (!this.viewed || !action) {
1662
1522
  return;
1663
1523
  }
1664
-
1665
1524
  event.preventDefault();
1666
-
1667
1525
  if (event.changedTouches) {
1668
1526
  forEach(event.changedTouches, function (touch) {
1669
1527
  assign(pointers[touch.identifier] || {}, getPointer(touch, true));
@@ -1671,17 +1529,14 @@
1671
1529
  } else {
1672
1530
  assign(pointers[event.pointerId || 0] || {}, getPointer(event, true));
1673
1531
  }
1674
-
1675
1532
  this.change(event);
1676
1533
  },
1677
1534
  pointerup: function pointerup(event) {
1678
1535
  var _this2 = this;
1679
-
1680
1536
  var options = this.options,
1681
- action = this.action,
1682
- pointers = this.pointers;
1537
+ action = this.action,
1538
+ pointers = this.pointers;
1683
1539
  var pointer;
1684
-
1685
1540
  if (event.changedTouches) {
1686
1541
  forEach(event.changedTouches, function (touch) {
1687
1542
  pointer = pointers[touch.identifier];
@@ -1691,42 +1546,39 @@
1691
1546
  pointer = pointers[event.pointerId || 0];
1692
1547
  delete pointers[event.pointerId || 0];
1693
1548
  }
1694
-
1695
1549
  if (!action) {
1696
1550
  return;
1697
1551
  }
1698
-
1699
1552
  event.preventDefault();
1700
-
1701
1553
  if (options.transition && (action === ACTION_MOVE || action === ACTION_ZOOM)) {
1702
1554
  addClass(this.image, CLASS_TRANSITION);
1703
1555
  }
1556
+ this.action = false;
1704
1557
 
1705
- this.action = false; // Emulate click and double click in touch devices to support backdrop and image zooming (#210).
1706
-
1558
+ // Emulate click and double click in touch devices to support backdrop and image zooming (#210).
1707
1559
  if (IS_TOUCH_DEVICE && action !== ACTION_ZOOM && pointer && Date.now() - pointer.timeStamp < 500) {
1708
1560
  clearTimeout(this.clickCanvasTimeout);
1709
1561
  clearTimeout(this.doubleClickImageTimeout);
1710
-
1711
1562
  if (options.toggleOnDblclick && this.viewed && event.target === this.image) {
1712
1563
  if (this.imageClicked) {
1713
- this.imageClicked = false; // This timeout will be cleared later when a native dblclick event is triggering
1564
+ this.imageClicked = false;
1714
1565
 
1566
+ // This timeout will be cleared later when a native dblclick event is triggering
1715
1567
  this.doubleClickImageTimeout = setTimeout(function () {
1716
1568
  dispatchEvent(_this2.image, EVENT_DBLCLICK, {
1717
1569
  originalEvent: event
1718
1570
  });
1719
1571
  }, 50);
1720
1572
  } else {
1721
- this.imageClicked = true; // The default timing of a double click in Windows is 500 ms
1573
+ this.imageClicked = true;
1722
1574
 
1575
+ // The default timing of a double click in Windows is 500 ms
1723
1576
  this.doubleClickImageTimeout = setTimeout(function () {
1724
1577
  _this2.imageClicked = false;
1725
1578
  }, 500);
1726
1579
  }
1727
1580
  } else {
1728
1581
  this.imageClicked = false;
1729
-
1730
1582
  if (options.backdrop && options.backdrop !== 'static' && event.target === this.canvas) {
1731
1583
  // This timeout will be cleared later when a native click event is triggering
1732
1584
  this.clickCanvasTimeout = setTimeout(function () {
@@ -1740,34 +1592,28 @@
1740
1592
  },
1741
1593
  resize: function resize() {
1742
1594
  var _this3 = this;
1743
-
1744
1595
  if (!this.isShown || this.hiding) {
1745
1596
  return;
1746
1597
  }
1747
-
1748
1598
  if (this.fulled) {
1749
1599
  this.close();
1750
1600
  this.initBody();
1751
1601
  this.open();
1752
1602
  }
1753
-
1754
1603
  this.initContainer();
1755
1604
  this.initViewer();
1756
1605
  this.renderViewer();
1757
1606
  this.renderList();
1758
-
1759
1607
  if (this.viewed) {
1760
1608
  this.initImage(function () {
1761
1609
  _this3.renderImage();
1762
1610
  });
1763
1611
  }
1764
-
1765
1612
  if (this.played) {
1766
1613
  if (this.options.fullscreen && this.fulled && !(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) {
1767
1614
  this.stop();
1768
1615
  return;
1769
1616
  }
1770
-
1771
1617
  forEach(this.player.getElementsByTagName('img'), function (image) {
1772
1618
  addListener(image, EVENT_LOAD, _this3.loadImage.bind(_this3), {
1773
1619
  once: true
@@ -1778,24 +1624,21 @@
1778
1624
  },
1779
1625
  wheel: function wheel(event) {
1780
1626
  var _this4 = this;
1781
-
1782
1627
  if (!this.viewed) {
1783
1628
  return;
1784
1629
  }
1630
+ event.preventDefault();
1785
1631
 
1786
- event.preventDefault(); // Limit wheel speed to prevent zoom too fast
1787
-
1632
+ // Limit wheel speed to prevent zoom too fast
1788
1633
  if (this.wheeling) {
1789
1634
  return;
1790
1635
  }
1791
-
1792
1636
  this.wheeling = true;
1793
1637
  setTimeout(function () {
1794
1638
  _this4.wheeling = false;
1795
1639
  }, 50);
1796
1640
  var ratio = Number(this.options.zoomRatio) || 0.1;
1797
1641
  var delta = 1;
1798
-
1799
1642
  if (event.deltaY) {
1800
1643
  delta = event.deltaY > 0 ? 1 : -1;
1801
1644
  } else if (event.wheelDelta) {
@@ -1803,8 +1646,7 @@
1803
1646
  } else if (event.detail) {
1804
1647
  delta = event.detail > 0 ? 1 : -1;
1805
1648
  }
1806
-
1807
- this.zoom(-delta * ratio, true, event);
1649
+ this.zoom(-delta * ratio, true, null, event);
1808
1650
  }
1809
1651
  };
1810
1652
 
@@ -1812,40 +1654,31 @@
1812
1654
  /** Show the viewer (only available in modal mode)
1813
1655
  * @param {boolean} [immediate=false] - Indicates if show the viewer immediately or not.
1814
1656
  * @returns {Viewer} this
1815
- */
1816
- show: function show() {
1657
+ */show: function show() {
1817
1658
  var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
1818
1659
  var element = this.element,
1819
- options = this.options;
1820
-
1660
+ options = this.options;
1821
1661
  if (options.inline || this.showing || this.isShown || this.showing) {
1822
1662
  return this;
1823
1663
  }
1824
-
1825
1664
  if (!this.ready) {
1826
1665
  this.build();
1827
-
1828
1666
  if (this.ready) {
1829
1667
  this.show(immediate);
1830
1668
  }
1831
-
1832
1669
  return this;
1833
1670
  }
1834
-
1835
1671
  if (isFunction(options.show)) {
1836
1672
  addListener(element, EVENT_SHOW, options.show, {
1837
1673
  once: true
1838
1674
  });
1839
1675
  }
1840
-
1841
1676
  if (dispatchEvent(element, EVENT_SHOW) === false || !this.ready) {
1842
1677
  return this;
1843
1678
  }
1844
-
1845
1679
  if (this.hiding) {
1846
1680
  this.transitioning.abort();
1847
1681
  }
1848
-
1849
1682
  this.showing = true;
1850
1683
  this.open();
1851
1684
  var viewer = this.viewer;
@@ -1854,7 +1687,6 @@
1854
1687
  viewer.setAttribute('aria-labelledby', this.title.id);
1855
1688
  viewer.setAttribute('aria-modal', true);
1856
1689
  viewer.removeAttribute('aria-hidden');
1857
-
1858
1690
  if (options.transition && !immediate) {
1859
1691
  var shown = this.shown.bind(this);
1860
1692
  this.transitioning = {
@@ -1863,8 +1695,9 @@
1863
1695
  removeClass(viewer, CLASS_IN);
1864
1696
  }
1865
1697
  };
1866
- addClass(viewer, CLASS_TRANSITION); // Force reflow to enable CSS3 transition
1698
+ addClass(viewer, CLASS_TRANSITION);
1867
1699
 
1700
+ // Force reflow to enable CSS3 transition
1868
1701
  viewer.initialOffsetWidth = viewer.offsetWidth;
1869
1702
  addListener(viewer, EVENT_TRANSITION_END, shown, {
1870
1703
  once: true
@@ -1874,67 +1707,51 @@
1874
1707
  addClass(viewer, CLASS_IN);
1875
1708
  this.shown();
1876
1709
  }
1877
-
1878
1710
  return this;
1879
1711
  },
1880
-
1881
1712
  /**
1882
1713
  * Hide the viewer (only available in modal mode)
1883
1714
  * @param {boolean} [immediate=false] - Indicates if hide the viewer immediately or not.
1884
1715
  * @returns {Viewer} this
1885
- */
1886
- hide: function hide() {
1716
+ */hide: function hide() {
1887
1717
  var _this = this;
1888
-
1889
1718
  var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
1890
1719
  var element = this.element,
1891
- options = this.options;
1892
-
1720
+ options = this.options;
1893
1721
  if (options.inline || this.hiding || !(this.isShown || this.showing)) {
1894
1722
  return this;
1895
1723
  }
1896
-
1897
1724
  if (isFunction(options.hide)) {
1898
1725
  addListener(element, EVENT_HIDE, options.hide, {
1899
1726
  once: true
1900
1727
  });
1901
1728
  }
1902
-
1903
1729
  if (dispatchEvent(element, EVENT_HIDE) === false) {
1904
1730
  return this;
1905
1731
  }
1906
-
1907
1732
  if (this.showing) {
1908
1733
  this.transitioning.abort();
1909
1734
  }
1910
-
1911
1735
  this.hiding = true;
1912
-
1913
1736
  if (this.played) {
1914
1737
  this.stop();
1915
1738
  } else if (this.viewing) {
1916
1739
  this.viewing.abort();
1917
1740
  }
1918
-
1919
1741
  var viewer = this.viewer,
1920
- image = this.image;
1921
-
1742
+ image = this.image;
1922
1743
  var hideImmediately = function hideImmediately() {
1923
1744
  removeClass(viewer, CLASS_IN);
1924
-
1925
1745
  _this.hidden();
1926
1746
  };
1927
-
1928
1747
  if (options.transition && !immediate) {
1929
1748
  var onViewerTransitionEnd = function onViewerTransitionEnd(event) {
1930
1749
  // Ignore all propagating `transitionend` events (#275).
1931
1750
  if (event && event.target === viewer) {
1932
1751
  removeListener(viewer, EVENT_TRANSITION_END, onViewerTransitionEnd);
1933
-
1934
1752
  _this.hidden();
1935
1753
  }
1936
1754
  };
1937
-
1938
1755
  var onImageTransitionEnd = function onImageTransitionEnd() {
1939
1756
  // In case of show the viewer by `viewer.show(true)` previously (#407).
1940
1757
  if (hasClass(viewer, CLASS_TRANSITION)) {
@@ -1944,7 +1761,6 @@
1944
1761
  hideImmediately();
1945
1762
  }
1946
1763
  };
1947
-
1948
1764
  this.transitioning = {
1949
1765
  abort: function abort() {
1950
1766
  if (_this.viewed && hasClass(image, CLASS_TRANSITION)) {
@@ -1953,52 +1769,45 @@
1953
1769
  removeListener(viewer, EVENT_TRANSITION_END, onViewerTransitionEnd);
1954
1770
  }
1955
1771
  }
1956
- }; // In case of hiding the viewer when holding on the image (#255),
1957
- // note that the `CLASS_TRANSITION` class will be removed on pointer down.
1772
+ };
1958
1773
 
1774
+ // In case of hiding the viewer when holding on the image (#255),
1775
+ // note that the `CLASS_TRANSITION` class will be removed on pointer down.
1959
1776
  if (this.viewed && hasClass(image, CLASS_TRANSITION)) {
1960
1777
  addListener(image, EVENT_TRANSITION_END, onImageTransitionEnd, {
1961
1778
  once: true
1962
1779
  });
1963
- this.zoomTo(0, false, null, true);
1780
+ this.zoomTo(0, false, null, null, true);
1964
1781
  } else {
1965
1782
  onImageTransitionEnd();
1966
1783
  }
1967
1784
  } else {
1968
1785
  hideImmediately();
1969
1786
  }
1970
-
1971
1787
  return this;
1972
1788
  },
1973
-
1974
1789
  /**
1975
1790
  * View one of the images with image's index
1976
1791
  * @param {number} index - The index of the image to view.
1977
1792
  * @returns {Viewer} this
1978
- */
1979
- view: function view() {
1793
+ */view: function view() {
1980
1794
  var _this2 = this;
1981
-
1982
1795
  var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.initialViewIndex;
1983
1796
  index = Number(index) || 0;
1984
-
1985
1797
  if (this.hiding || this.played || index < 0 || index >= this.length || this.viewed && index === this.index) {
1986
1798
  return this;
1987
1799
  }
1988
-
1989
1800
  if (!this.isShown) {
1990
1801
  this.index = index;
1991
1802
  return this.show();
1992
1803
  }
1993
-
1994
1804
  if (this.viewing) {
1995
1805
  this.viewing.abort();
1996
1806
  }
1997
-
1998
1807
  var element = this.element,
1999
- options = this.options,
2000
- title = this.title,
2001
- canvas = this.canvas;
1808
+ options = this.options,
1809
+ title = this.title,
1810
+ canvas = this.canvas;
2002
1811
  var item = this.items[index];
2003
1812
  var img = item.querySelector('img');
2004
1813
  var url = getData(img, 'originalUrl');
@@ -2006,20 +1815,17 @@
2006
1815
  var image = document.createElement('img');
2007
1816
  forEach(options.inheritedAttributes, function (name) {
2008
1817
  var value = img.getAttribute(name);
2009
-
2010
1818
  if (value !== null) {
2011
1819
  image.setAttribute(name, value);
2012
1820
  }
2013
1821
  });
2014
1822
  image.src = url;
2015
1823
  image.alt = alt;
2016
-
2017
1824
  if (isFunction(options.view)) {
2018
1825
  addListener(element, EVENT_VIEW, options.view, {
2019
1826
  once: true
2020
1827
  });
2021
1828
  }
2022
-
2023
1829
  if (dispatchEvent(element, EVENT_VIEW, {
2024
1830
  originalImage: this.images[index],
2025
1831
  index: index,
@@ -2027,44 +1833,39 @@
2027
1833
  }) === false || !this.isShown || this.hiding || this.played) {
2028
1834
  return this;
2029
1835
  }
2030
-
2031
1836
  var activeItem = this.items[this.index];
2032
-
2033
1837
  if (activeItem) {
2034
1838
  removeClass(activeItem, CLASS_ACTIVE);
2035
1839
  activeItem.removeAttribute('aria-selected');
2036
1840
  }
2037
-
2038
1841
  addClass(item, CLASS_ACTIVE);
2039
1842
  item.setAttribute('aria-selected', true);
2040
-
2041
1843
  if (options.focus) {
2042
1844
  item.focus();
2043
1845
  }
2044
-
2045
1846
  this.image = image;
2046
1847
  this.viewed = false;
2047
1848
  this.index = index;
2048
1849
  this.imageData = {};
2049
1850
  addClass(image, CLASS_INVISIBLE);
2050
-
2051
1851
  if (options.loading) {
2052
1852
  addClass(canvas, CLASS_LOADING);
2053
1853
  }
2054
-
2055
1854
  canvas.innerHTML = '';
2056
- canvas.appendChild(image); // Center current item
1855
+ canvas.appendChild(image);
2057
1856
 
2058
- this.renderList(); // Clear title
1857
+ // Center current item
1858
+ this.renderList();
2059
1859
 
2060
- title.innerHTML = ''; // Generate title after viewed
1860
+ // Clear title
1861
+ title.innerHTML = '';
2061
1862
 
1863
+ // Generate title after viewed
2062
1864
  var onViewed = function onViewed() {
2063
1865
  var imageData = _this2.imageData;
2064
1866
  var render = Array.isArray(options.title) ? options.title[1] : options.title;
2065
1867
  title.innerHTML = escapeHTMLEntities(isFunction(render) ? render.call(_this2, image, imageData) : "".concat(alt, " (").concat(imageData.naturalWidth, " \xD7 ").concat(imageData.naturalHeight, ")"));
2066
1868
  };
2067
-
2068
1869
  var onLoad;
2069
1870
  var onError;
2070
1871
  addListener(element, EVENT_VIEWED, onViewed, {
@@ -2073,7 +1874,6 @@
2073
1874
  this.viewing = {
2074
1875
  abort: function abort() {
2075
1876
  removeListener(element, EVENT_VIEWED, onViewed);
2076
-
2077
1877
  if (image.complete) {
2078
1878
  if (_this2.imageRendering) {
2079
1879
  _this2.imageRendering.abort();
@@ -2084,149 +1884,121 @@
2084
1884
  // Cancel download to save bandwidth.
2085
1885
  image.src = '';
2086
1886
  removeListener(image, EVENT_LOAD, onLoad);
2087
-
2088
1887
  if (_this2.timeout) {
2089
1888
  clearTimeout(_this2.timeout);
2090
1889
  }
2091
1890
  }
2092
1891
  }
2093
1892
  };
2094
-
2095
1893
  if (image.complete) {
2096
1894
  this.load();
2097
1895
  } else {
2098
1896
  addListener(image, EVENT_LOAD, onLoad = function onLoad() {
2099
1897
  removeListener(image, EVENT_ERROR, onError);
2100
-
2101
1898
  _this2.load();
2102
1899
  }, {
2103
1900
  once: true
2104
1901
  });
2105
1902
  addListener(image, EVENT_ERROR, onError = function onError() {
2106
1903
  removeListener(image, EVENT_LOAD, onLoad);
2107
-
2108
1904
  if (_this2.timeout) {
2109
1905
  clearTimeout(_this2.timeout);
2110
1906
  _this2.timeout = false;
2111
1907
  }
2112
-
2113
1908
  removeClass(image, CLASS_INVISIBLE);
2114
-
2115
1909
  if (options.loading) {
2116
1910
  removeClass(_this2.canvas, CLASS_LOADING);
2117
1911
  }
2118
1912
  }, {
2119
1913
  once: true
2120
1914
  });
2121
-
2122
1915
  if (this.timeout) {
2123
1916
  clearTimeout(this.timeout);
2124
- } // Make the image visible if it fails to load within 1s
2125
-
1917
+ }
2126
1918
 
1919
+ // Make the image visible if it fails to load within 1s
2127
1920
  this.timeout = setTimeout(function () {
2128
1921
  removeClass(image, CLASS_INVISIBLE);
2129
1922
  _this2.timeout = false;
2130
1923
  }, 1000);
2131
1924
  }
2132
-
2133
1925
  return this;
2134
1926
  },
2135
-
2136
1927
  /**
2137
1928
  * View the previous image
2138
1929
  * @param {boolean} [loop=false] - Indicate if view the last one
2139
1930
  * when it is the first one at present.
2140
1931
  * @returns {Viewer} this
2141
- */
2142
- prev: function prev() {
1932
+ */prev: function prev() {
2143
1933
  var loop = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
2144
1934
  var index = this.index - 1;
2145
-
2146
1935
  if (index < 0) {
2147
1936
  index = loop ? this.length - 1 : 0;
2148
1937
  }
2149
-
2150
1938
  this.view(index);
2151
1939
  return this;
2152
1940
  },
2153
-
2154
1941
  /**
2155
1942
  * View the next image
2156
1943
  * @param {boolean} [loop=false] - Indicate if view the first one
2157
1944
  * when it is the last one at present.
2158
1945
  * @returns {Viewer} this
2159
- */
2160
- next: function next() {
1946
+ */next: function next() {
2161
1947
  var loop = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
2162
1948
  var maxIndex = this.length - 1;
2163
1949
  var index = this.index + 1;
2164
-
2165
1950
  if (index > maxIndex) {
2166
1951
  index = loop ? 0 : maxIndex;
2167
1952
  }
2168
-
2169
1953
  this.view(index);
2170
1954
  return this;
2171
1955
  },
2172
-
2173
1956
  /**
2174
1957
  * Move the image with relative offsets.
2175
1958
  * @param {number} x - The moving distance in the horizontal direction.
2176
1959
  * @param {number} [y=x] The moving distance in the vertical direction.
2177
1960
  * @returns {Viewer} this
2178
- */
2179
- move: function move(x) {
1961
+ */move: function move(x) {
2180
1962
  var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x;
2181
1963
  var imageData = this.imageData;
2182
1964
  this.moveTo(isUndefined(x) ? x : imageData.x + Number(x), isUndefined(y) ? y : imageData.y + Number(y));
2183
1965
  return this;
2184
1966
  },
2185
-
2186
1967
  /**
2187
1968
  * Move the image to an absolute point.
2188
1969
  * @param {number} x - The new position in the horizontal direction.
2189
1970
  * @param {number} [y=x] - The new position in the vertical direction.
2190
1971
  * @param {Event} [_originalEvent=null] - The original event if any.
2191
1972
  * @returns {Viewer} this
2192
- */
2193
- moveTo: function moveTo(x) {
1973
+ */moveTo: function moveTo(x) {
2194
1974
  var _this3 = this;
2195
-
2196
1975
  var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x;
2197
-
2198
1976
  var _originalEvent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
2199
-
2200
1977
  var element = this.element,
2201
- options = this.options,
2202
- imageData = this.imageData;
1978
+ options = this.options,
1979
+ imageData = this.imageData;
2203
1980
  x = Number(x);
2204
1981
  y = Number(y);
2205
-
2206
1982
  if (this.viewed && !this.played && options.movable) {
2207
1983
  var oldX = imageData.x;
2208
1984
  var oldY = imageData.y;
2209
1985
  var changed = false;
2210
-
2211
1986
  if (isNumber(x)) {
2212
1987
  changed = true;
2213
1988
  } else {
2214
1989
  x = oldX;
2215
1990
  }
2216
-
2217
1991
  if (isNumber(y)) {
2218
1992
  changed = true;
2219
1993
  } else {
2220
1994
  y = oldY;
2221
1995
  }
2222
-
2223
1996
  if (changed) {
2224
1997
  if (isFunction(options.move)) {
2225
1998
  addListener(element, EVENT_MOVE, options.move, {
2226
1999
  once: true
2227
2000
  });
2228
2001
  }
2229
-
2230
2002
  if (dispatchEvent(element, EVENT_MOVE, {
2231
2003
  x: x,
2232
2004
  y: y,
@@ -2236,7 +2008,6 @@
2236
2008
  }) === false) {
2237
2009
  return this;
2238
2010
  }
2239
-
2240
2011
  imageData.x = x;
2241
2012
  imageData.y = y;
2242
2013
  imageData.left = x;
@@ -2244,13 +2015,11 @@
2244
2015
  this.moving = true;
2245
2016
  this.renderImage(function () {
2246
2017
  _this3.moving = false;
2247
-
2248
2018
  if (isFunction(options.moved)) {
2249
2019
  addListener(element, EVENT_MOVED, options.moved, {
2250
2020
  once: true
2251
2021
  });
2252
2022
  }
2253
-
2254
2023
  dispatchEvent(element, EVENT_MOVED, {
2255
2024
  x: x,
2256
2025
  y: y,
@@ -2263,60 +2032,48 @@
2263
2032
  });
2264
2033
  }
2265
2034
  }
2266
-
2267
2035
  return this;
2268
2036
  },
2269
-
2270
2037
  /**
2271
2038
  * Rotate the image with a relative degree.
2272
2039
  * @param {number} degree - The rotate degree.
2273
2040
  * @returns {Viewer} this
2274
- */
2275
- rotate: function rotate(degree) {
2041
+ */rotate: function rotate(degree) {
2276
2042
  this.rotateTo((this.imageData.rotate || 0) + Number(degree));
2277
2043
  return this;
2278
2044
  },
2279
-
2280
2045
  /**
2281
2046
  * Rotate the image to an absolute degree.
2282
2047
  * @param {number} degree - The rotate degree.
2283
2048
  * @returns {Viewer} this
2284
- */
2285
- rotateTo: function rotateTo(degree) {
2049
+ */rotateTo: function rotateTo(degree) {
2286
2050
  var _this4 = this;
2287
-
2288
2051
  var element = this.element,
2289
- options = this.options,
2290
- imageData = this.imageData;
2052
+ options = this.options,
2053
+ imageData = this.imageData;
2291
2054
  degree = Number(degree);
2292
-
2293
2055
  if (isNumber(degree) && this.viewed && !this.played && options.rotatable) {
2294
2056
  var oldDegree = imageData.rotate;
2295
-
2296
2057
  if (isFunction(options.rotate)) {
2297
2058
  addListener(element, EVENT_ROTATE, options.rotate, {
2298
2059
  once: true
2299
2060
  });
2300
2061
  }
2301
-
2302
2062
  if (dispatchEvent(element, EVENT_ROTATE, {
2303
2063
  degree: degree,
2304
2064
  oldDegree: oldDegree
2305
2065
  }) === false) {
2306
2066
  return this;
2307
2067
  }
2308
-
2309
2068
  imageData.rotate = degree;
2310
2069
  this.rotating = true;
2311
2070
  this.renderImage(function () {
2312
2071
  _this4.rotating = false;
2313
-
2314
2072
  if (isFunction(options.rotated)) {
2315
2073
  addListener(element, EVENT_ROTATED, options.rotated, {
2316
2074
  once: true
2317
2075
  });
2318
2076
  }
2319
-
2320
2077
  dispatchEvent(element, EVENT_ROTATED, {
2321
2078
  degree: degree,
2322
2079
  oldDegree: oldDegree
@@ -2325,70 +2082,57 @@
2325
2082
  });
2326
2083
  });
2327
2084
  }
2328
-
2329
2085
  return this;
2330
2086
  },
2331
-
2332
2087
  /**
2333
2088
  * Scale the image on the x-axis.
2334
2089
  * @param {number} scaleX - The scale ratio on the x-axis.
2335
2090
  * @returns {Viewer} this
2336
- */
2337
- scaleX: function scaleX(_scaleX) {
2091
+ */scaleX: function scaleX(_scaleX) {
2338
2092
  this.scale(_scaleX, this.imageData.scaleY);
2339
2093
  return this;
2340
2094
  },
2341
-
2342
2095
  /**
2343
2096
  * Scale the image on the y-axis.
2344
2097
  * @param {number} scaleY - The scale ratio on the y-axis.
2345
2098
  * @returns {Viewer} this
2346
- */
2347
- scaleY: function scaleY(_scaleY) {
2099
+ */scaleY: function scaleY(_scaleY) {
2348
2100
  this.scale(this.imageData.scaleX, _scaleY);
2349
2101
  return this;
2350
2102
  },
2351
-
2352
2103
  /**
2353
2104
  * Scale the image.
2354
2105
  * @param {number} scaleX - The scale ratio on the x-axis.
2355
2106
  * @param {number} [scaleY=scaleX] - The scale ratio on the y-axis.
2356
2107
  * @returns {Viewer} this
2357
- */
2358
- scale: function scale(scaleX) {
2108
+ */scale: function scale(scaleX) {
2359
2109
  var _this5 = this;
2360
-
2361
2110
  var scaleY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : scaleX;
2362
2111
  var element = this.element,
2363
- options = this.options,
2364
- imageData = this.imageData;
2112
+ options = this.options,
2113
+ imageData = this.imageData;
2365
2114
  scaleX = Number(scaleX);
2366
2115
  scaleY = Number(scaleY);
2367
-
2368
2116
  if (this.viewed && !this.played && options.scalable) {
2369
2117
  var oldScaleX = imageData.scaleX;
2370
2118
  var oldScaleY = imageData.scaleY;
2371
2119
  var changed = false;
2372
-
2373
2120
  if (isNumber(scaleX)) {
2374
2121
  changed = true;
2375
2122
  } else {
2376
2123
  scaleX = oldScaleX;
2377
2124
  }
2378
-
2379
2125
  if (isNumber(scaleY)) {
2380
2126
  changed = true;
2381
2127
  } else {
2382
2128
  scaleY = oldScaleY;
2383
2129
  }
2384
-
2385
2130
  if (changed) {
2386
2131
  if (isFunction(options.scale)) {
2387
2132
  addListener(element, EVENT_SCALE, options.scale, {
2388
2133
  once: true
2389
2134
  });
2390
2135
  }
2391
-
2392
2136
  if (dispatchEvent(element, EVENT_SCALE, {
2393
2137
  scaleX: scaleX,
2394
2138
  scaleY: scaleY,
@@ -2397,19 +2141,16 @@
2397
2141
  }) === false) {
2398
2142
  return this;
2399
2143
  }
2400
-
2401
2144
  imageData.scaleX = scaleX;
2402
2145
  imageData.scaleY = scaleY;
2403
2146
  this.scaling = true;
2404
2147
  this.renderImage(function () {
2405
2148
  _this5.scaling = false;
2406
-
2407
2149
  if (isFunction(options.scaled)) {
2408
2150
  addListener(element, EVENT_SCALED, options.scaled, {
2409
2151
  once: true
2410
2152
  });
2411
2153
  }
2412
-
2413
2154
  dispatchEvent(element, EVENT_SCALED, {
2414
2155
  scaleX: scaleX,
2415
2156
  scaleY: scaleY,
@@ -2421,103 +2162,86 @@
2421
2162
  });
2422
2163
  }
2423
2164
  }
2424
-
2425
2165
  return this;
2426
2166
  },
2427
-
2428
2167
  /**
2429
2168
  * Zoom the image with a relative ratio.
2430
2169
  * @param {number} ratio - The target ratio.
2431
- * @param {boolean} [hasTooltip=false] - Indicates if it has a tooltip or not.
2170
+ * @param {boolean} [showTooltip=false] - Indicates whether to show the tooltip.
2171
+ * @param {Object} [pivot] - The pivot point coordinate for zooming.
2432
2172
  * @param {Event} [_originalEvent=null] - The original event if any.
2433
2173
  * @returns {Viewer} this
2434
- */
2435
- zoom: function zoom(ratio) {
2436
- var hasTooltip = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
2437
-
2438
- var _originalEvent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
2439
-
2174
+ */zoom: function zoom(ratio) {
2175
+ var showTooltip = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
2176
+ var pivot = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
2177
+ var _originalEvent = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
2440
2178
  var imageData = this.imageData;
2441
2179
  ratio = Number(ratio);
2442
-
2443
2180
  if (ratio < 0) {
2444
2181
  ratio = 1 / (1 - ratio);
2445
2182
  } else {
2446
2183
  ratio = 1 + ratio;
2447
2184
  }
2448
-
2449
- this.zoomTo(imageData.width * ratio / imageData.naturalWidth, hasTooltip, _originalEvent);
2185
+ this.zoomTo(imageData.width * ratio / imageData.naturalWidth, showTooltip, pivot, _originalEvent);
2450
2186
  return this;
2451
2187
  },
2452
-
2453
2188
  /**
2454
2189
  * Zoom the image to an absolute ratio.
2455
2190
  * @param {number} ratio - The target ratio.
2456
- * @param {boolean} [hasTooltip=false] - Indicates if it has a tooltip or not.
2191
+ * @param {boolean} [showTooltip] - Indicates whether to show the tooltip.
2192
+ * @param {Object} [pivot] - The pivot point coordinate for zooming.
2457
2193
  * @param {Event} [_originalEvent=null] - The original event if any.
2458
2194
  * @param {Event} [_zoomable=false] - Indicates if the current zoom is available or not.
2459
2195
  * @returns {Viewer} this
2460
- */
2461
- zoomTo: function zoomTo(ratio) {
2196
+ */zoomTo: function zoomTo(ratio) {
2462
2197
  var _this6 = this;
2463
-
2464
- var hasTooltip = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
2465
-
2466
- var _originalEvent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
2467
-
2468
- var _zoomable = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
2469
-
2198
+ var showTooltip = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
2199
+ var pivot = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
2200
+ var _originalEvent = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
2201
+ var _zoomable = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
2470
2202
  var element = this.element,
2471
- options = this.options,
2472
- pointers = this.pointers,
2473
- imageData = this.imageData;
2203
+ options = this.options,
2204
+ pointers = this.pointers,
2205
+ imageData = this.imageData;
2474
2206
  var x = imageData.x,
2475
- y = imageData.y,
2476
- width = imageData.width,
2477
- height = imageData.height,
2478
- naturalWidth = imageData.naturalWidth,
2479
- naturalHeight = imageData.naturalHeight;
2207
+ y = imageData.y,
2208
+ width = imageData.width,
2209
+ height = imageData.height,
2210
+ naturalWidth = imageData.naturalWidth,
2211
+ naturalHeight = imageData.naturalHeight;
2480
2212
  ratio = Math.max(0, ratio);
2481
-
2482
2213
  if (isNumber(ratio) && this.viewed && !this.played && (_zoomable || options.zoomable)) {
2483
2214
  if (!_zoomable) {
2484
2215
  var minZoomRatio = Math.max(0.01, options.minZoomRatio);
2485
2216
  var maxZoomRatio = Math.min(100, options.maxZoomRatio);
2486
2217
  ratio = Math.min(Math.max(ratio, minZoomRatio), maxZoomRatio);
2487
2218
  }
2488
-
2489
2219
  if (_originalEvent) {
2490
2220
  switch (_originalEvent.type) {
2491
2221
  case 'wheel':
2492
2222
  if (options.zoomRatio >= 0.055 && ratio > 0.95 && ratio < 1.05) {
2493
2223
  ratio = 1;
2494
2224
  }
2495
-
2496
2225
  break;
2497
-
2498
2226
  case 'pointermove':
2499
2227
  case 'touchmove':
2500
2228
  case 'mousemove':
2501
2229
  if (ratio > 0.99 && ratio < 1.01) {
2502
2230
  ratio = 1;
2503
2231
  }
2504
-
2505
2232
  break;
2506
2233
  }
2507
2234
  }
2508
-
2509
2235
  var newWidth = naturalWidth * ratio;
2510
2236
  var newHeight = naturalHeight * ratio;
2511
2237
  var offsetWidth = newWidth - width;
2512
2238
  var offsetHeight = newHeight - height;
2513
2239
  var oldRatio = imageData.ratio;
2514
-
2515
2240
  if (isFunction(options.zoom)) {
2516
2241
  addListener(element, EVENT_ZOOM, options.zoom, {
2517
2242
  once: true
2518
2243
  });
2519
2244
  }
2520
-
2521
2245
  if (dispatchEvent(element, EVENT_ZOOM, {
2522
2246
  ratio: ratio,
2523
2247
  oldRatio: oldRatio,
@@ -2525,24 +2249,25 @@
2525
2249
  }) === false) {
2526
2250
  return this;
2527
2251
  }
2528
-
2529
2252
  this.zooming = true;
2530
-
2531
2253
  if (_originalEvent) {
2532
2254
  var offset = getOffset(this.viewer);
2533
2255
  var center = pointers && Object.keys(pointers).length > 0 ? getPointersCenter(pointers) : {
2534
2256
  pageX: _originalEvent.pageX,
2535
2257
  pageY: _originalEvent.pageY
2536
- }; // Zoom from the triggering point of the event
2258
+ };
2537
2259
 
2260
+ // Zoom from the triggering point of the event
2538
2261
  imageData.x -= offsetWidth * ((center.pageX - offset.left - x) / width);
2539
2262
  imageData.y -= offsetHeight * ((center.pageY - offset.top - y) / height);
2263
+ } else if (isPlainObject(pivot) && isNumber(pivot.x) && isNumber(pivot.y)) {
2264
+ imageData.x -= offsetWidth * ((pivot.x - x) / width);
2265
+ imageData.y -= offsetHeight * ((pivot.y - y) / height);
2540
2266
  } else {
2541
2267
  // Zoom from the center of the image
2542
2268
  imageData.x -= offsetWidth / 2;
2543
2269
  imageData.y -= offsetHeight / 2;
2544
2270
  }
2545
-
2546
2271
  imageData.left = imageData.x;
2547
2272
  imageData.top = imageData.y;
2548
2273
  imageData.width = newWidth;
@@ -2551,13 +2276,11 @@
2551
2276
  imageData.ratio = ratio;
2552
2277
  this.renderImage(function () {
2553
2278
  _this6.zooming = false;
2554
-
2555
2279
  if (isFunction(options.zoomed)) {
2556
2280
  addListener(element, EVENT_ZOOMED, options.zoomed, {
2557
2281
  once: true
2558
2282
  });
2559
2283
  }
2560
-
2561
2284
  dispatchEvent(element, EVENT_ZOOMED, {
2562
2285
  ratio: ratio,
2563
2286
  oldRatio: oldRatio,
@@ -2566,42 +2289,32 @@
2566
2289
  cancelable: false
2567
2290
  });
2568
2291
  });
2569
-
2570
- if (hasTooltip) {
2292
+ if (showTooltip) {
2571
2293
  this.tooltip();
2572
2294
  }
2573
2295
  }
2574
-
2575
2296
  return this;
2576
2297
  },
2577
-
2578
2298
  /**
2579
2299
  * Play the images
2580
2300
  * @param {boolean|FullscreenOptions} [fullscreen=false] - Indicate if request fullscreen or not.
2581
2301
  * @returns {Viewer} this
2582
- */
2583
- play: function play() {
2302
+ */play: function play() {
2584
2303
  var _this7 = this;
2585
-
2586
2304
  var fullscreen = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
2587
-
2588
2305
  if (!this.isShown || this.played) {
2589
2306
  return this;
2590
2307
  }
2591
-
2592
2308
  var element = this.element,
2593
- options = this.options;
2594
-
2309
+ options = this.options;
2595
2310
  if (isFunction(options.play)) {
2596
2311
  addListener(element, EVENT_PLAY, options.play, {
2597
2312
  once: true
2598
2313
  });
2599
2314
  }
2600
-
2601
2315
  if (dispatchEvent(element, EVENT_PLAY) === false) {
2602
2316
  return this;
2603
2317
  }
2604
-
2605
2318
  var player = this.player;
2606
2319
  var onLoad = this.loadImage.bind(this);
2607
2320
  var list = [];
@@ -2609,11 +2322,9 @@
2609
2322
  var index = 0;
2610
2323
  this.played = true;
2611
2324
  this.onLoadWhenPlay = onLoad;
2612
-
2613
2325
  if (fullscreen) {
2614
2326
  this.requestFullscreen(fullscreen);
2615
2327
  }
2616
-
2617
2328
  addClass(player, CLASS_SHOW);
2618
2329
  forEach(this.items, function (item, i) {
2619
2330
  var img = item.querySelector('img');
@@ -2624,61 +2335,63 @@
2624
2335
  total += 1;
2625
2336
  addClass(image, CLASS_FADE);
2626
2337
  toggleClass(image, CLASS_TRANSITION, options.transition);
2627
-
2628
2338
  if (hasClass(item, CLASS_ACTIVE)) {
2629
2339
  addClass(image, CLASS_IN);
2630
2340
  index = i;
2631
2341
  }
2632
-
2633
2342
  list.push(image);
2634
2343
  addListener(image, EVENT_LOAD, onLoad, {
2635
2344
  once: true
2636
2345
  });
2637
2346
  player.appendChild(image);
2638
2347
  });
2639
-
2640
2348
  if (isNumber(options.interval) && options.interval > 0) {
2641
- var play = function play() {
2642
- _this7.playing = setTimeout(function () {
2643
- removeClass(list[index], CLASS_IN);
2644
- index += 1;
2645
- index = index < total ? index : 0;
2646
- addClass(list[index], CLASS_IN);
2647
- play();
2648
- }, options.interval);
2349
+ var prev = function prev() {
2350
+ clearTimeout(_this7.playing.timeout);
2351
+ removeClass(list[index], CLASS_IN);
2352
+ index -= 1;
2353
+ index = index >= 0 ? index : total - 1;
2354
+ addClass(list[index], CLASS_IN);
2355
+ _this7.playing.timeout = setTimeout(prev, options.interval);
2356
+ };
2357
+ var next = function next() {
2358
+ clearTimeout(_this7.playing.timeout);
2359
+ removeClass(list[index], CLASS_IN);
2360
+ index += 1;
2361
+ index = index < total ? index : 0;
2362
+ addClass(list[index], CLASS_IN);
2363
+ _this7.playing.timeout = setTimeout(next, options.interval);
2649
2364
  };
2650
-
2651
2365
  if (total > 1) {
2652
- play();
2366
+ this.playing = {
2367
+ prev: prev,
2368
+ next: next,
2369
+ timeout: setTimeout(next, options.interval)
2370
+ };
2653
2371
  }
2654
2372
  }
2655
-
2656
2373
  return this;
2657
2374
  },
2658
2375
  // Stop play
2659
2376
  stop: function stop() {
2660
2377
  var _this8 = this;
2661
-
2662
2378
  if (!this.played) {
2663
2379
  return this;
2664
2380
  }
2665
-
2666
2381
  var element = this.element,
2667
- options = this.options;
2668
-
2382
+ options = this.options;
2669
2383
  if (isFunction(options.stop)) {
2670
2384
  addListener(element, EVENT_STOP, options.stop, {
2671
2385
  once: true
2672
2386
  });
2673
2387
  }
2674
-
2675
2388
  if (dispatchEvent(element, EVENT_STOP) === false) {
2676
2389
  return this;
2677
2390
  }
2678
-
2679
2391
  var player = this.player;
2392
+ clearTimeout(this.playing.timeout);
2393
+ this.playing = false;
2680
2394
  this.played = false;
2681
- clearTimeout(this.playing);
2682
2395
  forEach(player.getElementsByTagName('img'), function (image) {
2683
2396
  removeListener(image, EVENT_LOAD, _this8.onLoadWhenPlay);
2684
2397
  });
@@ -2690,28 +2403,22 @@
2690
2403
  // Enter modal mode (only available in inline mode)
2691
2404
  full: function full() {
2692
2405
  var _this9 = this;
2693
-
2694
2406
  var options = this.options,
2695
- viewer = this.viewer,
2696
- image = this.image,
2697
- list = this.list;
2698
-
2407
+ viewer = this.viewer,
2408
+ image = this.image,
2409
+ list = this.list;
2699
2410
  if (!this.isShown || this.played || this.fulled || !options.inline) {
2700
2411
  return this;
2701
2412
  }
2702
-
2703
2413
  this.fulled = true;
2704
2414
  this.open();
2705
2415
  addClass(this.button, CLASS_FULLSCREEN_EXIT);
2706
-
2707
2416
  if (options.transition) {
2708
2417
  removeClass(list, CLASS_TRANSITION);
2709
-
2710
2418
  if (this.viewed) {
2711
2419
  removeClass(image, CLASS_TRANSITION);
2712
2420
  }
2713
2421
  }
2714
-
2715
2422
  addClass(viewer, CLASS_FIXED);
2716
2423
  viewer.setAttribute('role', 'dialog');
2717
2424
  viewer.setAttribute('aria-labelledby', this.title.id);
@@ -2720,15 +2427,12 @@
2720
2427
  setStyle(viewer, {
2721
2428
  zIndex: options.zIndex
2722
2429
  });
2723
-
2724
2430
  if (options.focus) {
2725
2431
  this.enforceFocus();
2726
2432
  }
2727
-
2728
2433
  this.initContainer();
2729
2434
  this.viewerData = assign({}, this.containerData);
2730
2435
  this.renderList();
2731
-
2732
2436
  if (this.viewed) {
2733
2437
  this.initImage(function () {
2734
2438
  _this9.renderImage(function () {
@@ -2741,38 +2445,30 @@
2741
2445
  });
2742
2446
  });
2743
2447
  }
2744
-
2745
2448
  return this;
2746
2449
  },
2747
2450
  // Exit modal mode (only available in inline mode)
2748
2451
  exit: function exit() {
2749
2452
  var _this10 = this;
2750
-
2751
2453
  var options = this.options,
2752
- viewer = this.viewer,
2753
- image = this.image,
2754
- list = this.list;
2755
-
2454
+ viewer = this.viewer,
2455
+ image = this.image,
2456
+ list = this.list;
2756
2457
  if (!this.isShown || this.played || !this.fulled || !options.inline) {
2757
2458
  return this;
2758
2459
  }
2759
-
2760
2460
  this.fulled = false;
2761
2461
  this.close();
2762
2462
  removeClass(this.button, CLASS_FULLSCREEN_EXIT);
2763
-
2764
2463
  if (options.transition) {
2765
2464
  removeClass(list, CLASS_TRANSITION);
2766
-
2767
2465
  if (this.viewed) {
2768
2466
  removeClass(image, CLASS_TRANSITION);
2769
2467
  }
2770
2468
  }
2771
-
2772
2469
  if (options.focus) {
2773
2470
  this.clearEnforceFocus();
2774
2471
  }
2775
-
2776
2472
  viewer.removeAttribute('role');
2777
2473
  viewer.removeAttribute('aria-labelledby');
2778
2474
  viewer.removeAttribute('aria-modal');
@@ -2783,7 +2479,6 @@
2783
2479
  this.viewerData = assign({}, this.parentData);
2784
2480
  this.renderViewer();
2785
2481
  this.renderList();
2786
-
2787
2482
  if (this.viewed) {
2788
2483
  this.initImage(function () {
2789
2484
  _this10.renderImage(function () {
@@ -2796,34 +2491,29 @@
2796
2491
  });
2797
2492
  });
2798
2493
  }
2799
-
2800
2494
  return this;
2801
2495
  },
2802
2496
  // Show the current ratio of the image with percentage
2803
2497
  tooltip: function tooltip() {
2804
2498
  var _this11 = this;
2805
-
2806
2499
  var options = this.options,
2807
- tooltipBox = this.tooltipBox,
2808
- imageData = this.imageData;
2809
-
2500
+ tooltipBox = this.tooltipBox,
2501
+ imageData = this.imageData;
2810
2502
  if (!this.viewed || this.played || !options.tooltip) {
2811
2503
  return this;
2812
2504
  }
2813
-
2814
2505
  tooltipBox.textContent = "".concat(Math.round(imageData.ratio * 100), "%");
2815
-
2816
2506
  if (!this.tooltipping) {
2817
2507
  if (options.transition) {
2818
2508
  if (this.fading) {
2819
2509
  dispatchEvent(tooltipBox, EVENT_TRANSITION_END);
2820
2510
  }
2821
-
2822
2511
  addClass(tooltipBox, CLASS_SHOW);
2823
2512
  addClass(tooltipBox, CLASS_FADE);
2824
2513
  addClass(tooltipBox, CLASS_TRANSITION);
2825
- tooltipBox.removeAttribute('aria-hidden'); // Force reflow to enable CSS3 transition
2514
+ tooltipBox.removeAttribute('aria-hidden');
2826
2515
 
2516
+ // Force reflow to enable CSS3 transition
2827
2517
  tooltipBox.initialOffsetWidth = tooltipBox.offsetWidth;
2828
2518
  addClass(tooltipBox, CLASS_IN);
2829
2519
  } else {
@@ -2833,7 +2523,6 @@
2833
2523
  } else {
2834
2524
  clearTimeout(this.tooltipping);
2835
2525
  }
2836
-
2837
2526
  this.tooltipping = setTimeout(function () {
2838
2527
  if (options.transition) {
2839
2528
  addListener(tooltipBox, EVENT_TRANSITION_END, function () {
@@ -2851,26 +2540,21 @@
2851
2540
  removeClass(tooltipBox, CLASS_SHOW);
2852
2541
  tooltipBox.setAttribute('aria-hidden', true);
2853
2542
  }
2854
-
2855
2543
  _this11.tooltipping = false;
2856
2544
  }, 1000);
2857
2545
  return this;
2858
2546
  },
2859
-
2860
2547
  /**
2861
2548
  * Toggle the image size between its current size and natural size
2862
2549
  * @param {Event} [_originalEvent=null] - The original event if any.
2863
2550
  * @returns {Viewer} this
2864
- */
2865
- toggle: function toggle() {
2551
+ */toggle: function toggle() {
2866
2552
  var _originalEvent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
2867
-
2868
2553
  if (this.imageData.ratio === 1) {
2869
- this.zoomTo(this.imageData.oldRatio, true, _originalEvent);
2554
+ this.zoomTo(this.imageData.oldRatio, true, null, _originalEvent);
2870
2555
  } else {
2871
- this.zoomTo(1, true, _originalEvent);
2556
+ this.zoomTo(1, true, null, _originalEvent);
2872
2557
  }
2873
-
2874
2558
  return this;
2875
2559
  },
2876
2560
  // Reset the image to its initial state
@@ -2879,21 +2563,19 @@
2879
2563
  this.imageData = assign({}, this.initialImageData);
2880
2564
  this.renderImage();
2881
2565
  }
2882
-
2883
2566
  return this;
2884
2567
  },
2885
2568
  // Update viewer when images changed
2886
2569
  update: function update() {
2887
2570
  var _this12 = this;
2888
-
2889
2571
  var element = this.element,
2890
- options = this.options,
2891
- isImg = this.isImg; // Destroy viewer if the target image was deleted
2572
+ options = this.options,
2573
+ isImg = this.isImg;
2892
2574
 
2575
+ // Destroy viewer if the target image was deleted
2893
2576
  if (isImg && !element.parentNode) {
2894
2577
  return this.destroy();
2895
2578
  }
2896
-
2897
2579
  var images = [];
2898
2580
  forEach(isImg ? [element] : element.querySelectorAll('img'), function (image) {
2899
2581
  if (isFunction(options.filter)) {
@@ -2904,22 +2586,20 @@
2904
2586
  images.push(image);
2905
2587
  }
2906
2588
  });
2907
-
2908
2589
  if (!images.length) {
2909
2590
  return this;
2910
2591
  }
2911
-
2912
2592
  this.images = images;
2913
2593
  this.length = images.length;
2914
-
2915
2594
  if (this.ready) {
2916
2595
  var changedIndexes = [];
2917
2596
  forEach(this.items, function (item, i) {
2918
2597
  var img = item.querySelector('img');
2919
2598
  var image = images[i];
2920
-
2921
2599
  if (image && img) {
2922
- if (image.src !== img.src // Title changed (#408)
2600
+ if (image.src !== img.src
2601
+
2602
+ // Title changed (#408)
2923
2603
  || image.alt !== img.alt) {
2924
2604
  changedIndexes.push(i);
2925
2605
  }
@@ -2931,18 +2611,17 @@
2931
2611
  width: 'auto'
2932
2612
  });
2933
2613
  this.initList();
2934
-
2935
2614
  if (this.isShown) {
2936
2615
  if (this.length) {
2937
2616
  if (this.viewed) {
2938
2617
  var changedIndex = changedIndexes.indexOf(this.index);
2939
-
2940
2618
  if (changedIndex >= 0) {
2941
2619
  this.viewed = false;
2942
2620
  this.view(Math.max(Math.min(this.index - changedIndex, this.length - 1), 0));
2943
2621
  } else {
2944
- var activeItem = this.items[this.index]; // Reactivate the current viewing item after reset the list.
2622
+ var activeItem = this.items[this.index];
2945
2623
 
2624
+ // Reactivate the current viewing item after reset the list.
2946
2625
  addClass(activeItem, CLASS_ACTIVE);
2947
2626
  activeItem.setAttribute('aria-selected', true);
2948
2627
  }
@@ -2959,30 +2638,24 @@
2959
2638
  } else {
2960
2639
  this.build();
2961
2640
  }
2962
-
2963
2641
  return this;
2964
2642
  },
2965
2643
  // Destroy the viewer
2966
2644
  destroy: function destroy() {
2967
2645
  var element = this.element,
2968
- options = this.options;
2969
-
2646
+ options = this.options;
2970
2647
  if (!element[NAMESPACE]) {
2971
2648
  return this;
2972
2649
  }
2973
-
2974
2650
  this.destroyed = true;
2975
-
2976
2651
  if (this.ready) {
2977
2652
  if (this.played) {
2978
2653
  this.stop();
2979
2654
  }
2980
-
2981
2655
  if (options.inline) {
2982
2656
  if (this.fulled) {
2983
2657
  this.exit();
2984
2658
  }
2985
-
2986
2659
  this.unbind();
2987
2660
  } else if (this.isShown) {
2988
2661
  if (this.viewing) {
@@ -2992,17 +2665,14 @@
2992
2665
  this.imageInitializing.abort();
2993
2666
  }
2994
2667
  }
2995
-
2996
2668
  if (this.hiding) {
2997
2669
  this.transitioning.abort();
2998
2670
  }
2999
-
3000
2671
  this.hidden();
3001
2672
  } else if (this.showing) {
3002
2673
  this.transitioning.abort();
3003
2674
  this.hidden();
3004
2675
  }
3005
-
3006
2676
  this.ready = false;
3007
2677
  this.viewer.parentNode.removeChild(this.viewer);
3008
2678
  } else if (options.inline) {
@@ -3012,11 +2682,9 @@
3012
2682
  this.initializing.abort();
3013
2683
  }
3014
2684
  }
3015
-
3016
2685
  if (!options.inline) {
3017
2686
  removeListener(element, EVENT_CLICK, this.onStart);
3018
2687
  }
3019
-
3020
2688
  element[NAMESPACE] = undefined;
3021
2689
  return this;
3022
2690
  }
@@ -3025,7 +2693,6 @@
3025
2693
  var others = {
3026
2694
  getImageURL: function getImageURL(image) {
3027
2695
  var url = this.options.url;
3028
-
3029
2696
  if (isString(url)) {
3030
2697
  url = image.getAttribute(url);
3031
2698
  } else if (isFunction(url)) {
@@ -3033,21 +2700,25 @@
3033
2700
  } else {
3034
2701
  url = '';
3035
2702
  }
3036
-
3037
2703
  return url;
3038
2704
  },
3039
2705
  enforceFocus: function enforceFocus() {
3040
2706
  var _this = this;
3041
-
3042
2707
  this.clearEnforceFocus();
3043
2708
  addListener(document, EVENT_FOCUSIN, this.onFocusin = function (event) {
3044
2709
  var viewer = _this.viewer;
3045
2710
  var target = event.target;
3046
-
3047
- if (target !== document && target !== viewer && !viewer.contains(target) // Avoid conflicts with other modals (#474)
3048
- && (target.getAttribute('tabindex') === null || target.getAttribute('aria-modal') !== 'true')) {
3049
- viewer.focus();
2711
+ if (target === document || target === viewer || viewer.contains(target)) {
2712
+ return;
2713
+ }
2714
+ while (target) {
2715
+ // Avoid conflicts with other modals (#474, #540)
2716
+ if (target.getAttribute('tabindex') !== null || target.getAttribute('aria-modal') === 'true') {
2717
+ return;
2718
+ }
2719
+ target = target.parentElement;
3050
2720
  }
2721
+ viewer.focus();
3051
2722
  });
3052
2723
  },
3053
2724
  clearEnforceFocus: function clearEnforceFocus() {
@@ -3059,51 +2730,49 @@
3059
2730
  open: function open() {
3060
2731
  var body = this.body;
3061
2732
  addClass(body, CLASS_OPEN);
3062
- body.style.paddingRight = "".concat(this.scrollbarWidth + (parseFloat(this.initialBodyComputedPaddingRight) || 0), "px");
2733
+ if (this.scrollbarWidth > 0) {
2734
+ body.style.paddingRight = "".concat(this.scrollbarWidth + (parseFloat(this.initialBodyComputedPaddingRight) || 0), "px");
2735
+ }
3063
2736
  },
3064
2737
  close: function close() {
3065
2738
  var body = this.body;
3066
2739
  removeClass(body, CLASS_OPEN);
3067
- body.style.paddingRight = this.initialBodyPaddingRight;
2740
+ if (this.scrollbarWidth > 0) {
2741
+ body.style.paddingRight = this.initialBodyPaddingRight;
2742
+ }
3068
2743
  },
3069
2744
  shown: function shown() {
3070
2745
  var element = this.element,
3071
- options = this.options,
3072
- viewer = this.viewer;
2746
+ options = this.options,
2747
+ viewer = this.viewer;
3073
2748
  this.fulled = true;
3074
2749
  this.isShown = true;
3075
2750
  this.render();
3076
2751
  this.bind();
3077
2752
  this.showing = false;
3078
-
3079
2753
  if (options.focus) {
3080
2754
  viewer.focus();
3081
2755
  this.enforceFocus();
3082
2756
  }
3083
-
3084
2757
  if (isFunction(options.shown)) {
3085
2758
  addListener(element, EVENT_SHOWN, options.shown, {
3086
2759
  once: true
3087
2760
  });
3088
2761
  }
3089
-
3090
2762
  if (dispatchEvent(element, EVENT_SHOWN) === false) {
3091
2763
  return;
3092
2764
  }
3093
-
3094
2765
  if (this.ready && this.isShown && !this.hiding) {
3095
2766
  this.view(this.index);
3096
2767
  }
3097
2768
  },
3098
2769
  hidden: function hidden() {
3099
2770
  var element = this.element,
3100
- options = this.options,
3101
- viewer = this.viewer;
3102
-
2771
+ options = this.options,
2772
+ viewer = this.viewer;
3103
2773
  if (options.fucus) {
3104
2774
  this.clearEnforceFocus();
3105
2775
  }
3106
-
3107
2776
  this.fulled = false;
3108
2777
  this.viewed = false;
3109
2778
  this.isShown = false;
@@ -3117,14 +2786,12 @@
3117
2786
  this.resetList();
3118
2787
  this.resetImage();
3119
2788
  this.hiding = false;
3120
-
3121
2789
  if (!this.destroyed) {
3122
2790
  if (isFunction(options.hidden)) {
3123
2791
  addListener(element, EVENT_HIDDEN, options.hidden, {
3124
2792
  once: true
3125
2793
  });
3126
2794
  }
3127
-
3128
2795
  dispatchEvent(element, EVENT_HIDDEN, null, {
3129
2796
  cancelable: false
3130
2797
  });
@@ -3132,10 +2799,10 @@
3132
2799
  },
3133
2800
  requestFullscreen: function requestFullscreen(options) {
3134
2801
  var document = this.element.ownerDocument;
3135
-
3136
2802
  if (this.fulled && !(document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) {
3137
- var documentElement = document.documentElement; // Element.requestFullscreen()
2803
+ var documentElement = document.documentElement;
3138
2804
 
2805
+ // Element.requestFullscreen()
3139
2806
  if (documentElement.requestFullscreen) {
3140
2807
  // Avoid TypeError when convert `options` to dictionary
3141
2808
  if (isPlainObject(options)) {
@@ -3154,7 +2821,6 @@
3154
2821
  },
3155
2822
  exitFullscreen: function exitFullscreen() {
3156
2823
  var document = this.element.ownerDocument;
3157
-
3158
2824
  if (this.fulled && (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement)) {
3159
2825
  // Document.exitFullscreen()
3160
2826
  if (document.exitFullscreen) {
@@ -3170,48 +2836,43 @@
3170
2836
  },
3171
2837
  change: function change(event) {
3172
2838
  var options = this.options,
3173
- pointers = this.pointers;
3174
- var pointer = pointers[Object.keys(pointers)[0]]; // In the case of the `pointers` object is empty (#421)
2839
+ pointers = this.pointers;
2840
+ var pointer = pointers[Object.keys(pointers)[0]];
3175
2841
 
2842
+ // In the case of the `pointers` object is empty (#421)
3176
2843
  if (!pointer) {
3177
2844
  return;
3178
2845
  }
3179
-
3180
2846
  var offsetX = pointer.endX - pointer.startX;
3181
2847
  var offsetY = pointer.endY - pointer.startY;
3182
-
3183
2848
  switch (this.action) {
3184
2849
  // Move the current image
3185
2850
  case ACTION_MOVE:
3186
2851
  this.move(offsetX, offsetY, event);
3187
2852
  break;
3188
- // Zoom the current image
3189
2853
 
2854
+ // Zoom the current image
3190
2855
  case ACTION_ZOOM:
3191
- this.zoom(getMaxZoomRatio(pointers), false, event);
2856
+ this.zoom(getMaxZoomRatio(pointers), false, null, event);
3192
2857
  break;
3193
-
3194
2858
  case ACTION_SWITCH:
3195
2859
  {
3196
2860
  this.action = 'switched';
3197
2861
  var absoluteOffsetX = Math.abs(offsetX);
3198
-
3199
2862
  if (absoluteOffsetX > 1 && absoluteOffsetX > Math.abs(offsetY)) {
3200
2863
  // Empty `pointers` as `touchend` event will not be fired after swiped in iOS browsers.
3201
2864
  this.pointers = {};
3202
-
3203
2865
  if (offsetX > 1) {
3204
2866
  this.prev(options.loop);
3205
2867
  } else if (offsetX < -1) {
3206
2868
  this.next(options.loop);
3207
2869
  }
3208
2870
  }
3209
-
3210
2871
  break;
3211
2872
  }
3212
- } // Override
3213
-
2873
+ }
3214
2874
 
2875
+ // Override
3215
2876
  forEach(pointers, function (p) {
3216
2877
  p.startX = p.endX;
3217
2878
  p.startY = p.endY;
@@ -3219,20 +2880,18 @@
3219
2880
  },
3220
2881
  isSwitchable: function isSwitchable() {
3221
2882
  var imageData = this.imageData,
3222
- viewerData = this.viewerData;
2883
+ viewerData = this.viewerData;
3223
2884
  return this.length > 1 && imageData.x >= 0 && imageData.y >= 0 && imageData.width <= viewerData.width && imageData.height <= viewerData.height;
3224
2885
  }
3225
2886
  };
3226
2887
 
3227
2888
  var AnotherViewer = WINDOW.Viewer;
3228
-
3229
2889
  var getUniqueID = function (id) {
3230
2890
  return function () {
3231
2891
  id += 1;
3232
2892
  return id;
3233
2893
  };
3234
2894
  }(-1);
3235
-
3236
2895
  var Viewer = /*#__PURE__*/function () {
3237
2896
  /**
3238
2897
  * Create a new Viewer.
@@ -3241,13 +2900,10 @@
3241
2900
  */
3242
2901
  function Viewer(element) {
3243
2902
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
3244
-
3245
2903
  _classCallCheck(this, Viewer);
3246
-
3247
2904
  if (!element || element.nodeType !== 1) {
3248
2905
  throw new Error('The first argument is required and must be an element.');
3249
2906
  }
3250
-
3251
2907
  this.element = element;
3252
2908
  this.options = assign({}, DEFAULTS, isPlainObject(options) && options);
3253
2909
  this.action = false;
@@ -3277,25 +2933,21 @@
3277
2933
  this.id = getUniqueID();
3278
2934
  this.init();
3279
2935
  }
3280
-
3281
2936
  _createClass(Viewer, [{
3282
2937
  key: "init",
3283
2938
  value: function init() {
3284
2939
  var _this = this;
3285
-
3286
2940
  var element = this.element,
3287
- options = this.options;
3288
-
2941
+ options = this.options;
3289
2942
  if (element[NAMESPACE]) {
3290
2943
  return;
3291
2944
  }
2945
+ element[NAMESPACE] = this;
3292
2946
 
3293
- element[NAMESPACE] = this; // The `focus` option requires the `keyboard` option set to `true`.
3294
-
2947
+ // The `focus` option requires the `keyboard` option set to `true`.
3295
2948
  if (options.focus && !options.keyboard) {
3296
2949
  options.focus = false;
3297
2950
  }
3298
-
3299
2951
  var isImg = element.localName === 'img';
3300
2952
  var images = [];
3301
2953
  forEach(isImg ? [element] : element.querySelectorAll('img'), function (image) {
@@ -3310,18 +2962,16 @@
3310
2962
  this.isImg = isImg;
3311
2963
  this.length = images.length;
3312
2964
  this.images = images;
3313
- this.initBody(); // Override `transition` option if it is not supported
2965
+ this.initBody();
3314
2966
 
2967
+ // Override `transition` option if it is not supported
3315
2968
  if (isUndefined(document.createElement(NAMESPACE).style.transition)) {
3316
2969
  options.transition = false;
3317
2970
  }
3318
-
3319
2971
  if (options.inline) {
3320
2972
  var count = 0;
3321
-
3322
2973
  var progress = function progress() {
3323
2974
  count += 1;
3324
-
3325
2975
  if (count === _this.length) {
3326
2976
  var timeout;
3327
2977
  _this.initializing = false;
@@ -3329,21 +2979,21 @@
3329
2979
  abort: function abort() {
3330
2980
  clearTimeout(timeout);
3331
2981
  }
3332
- }; // build asynchronously to keep `this.viewer` is accessible in `ready` event handler.
2982
+ };
3333
2983
 
2984
+ // build asynchronously to keep `this.viewer` is accessible in `ready` event handler.
3334
2985
  timeout = setTimeout(function () {
3335
2986
  _this.delaying = false;
3336
-
3337
2987
  _this.build();
3338
2988
  }, 0);
3339
2989
  }
3340
2990
  };
3341
-
3342
2991
  this.initializing = {
3343
2992
  abort: function abort() {
3344
2993
  forEach(images, function (image) {
3345
2994
  if (!image.complete) {
3346
2995
  removeListener(image, EVENT_LOAD, progress);
2996
+ removeListener(image, EVENT_ERROR, progress);
3347
2997
  }
3348
2998
  });
3349
2999
  }
@@ -3352,7 +3002,18 @@
3352
3002
  if (image.complete) {
3353
3003
  progress();
3354
3004
  } else {
3355
- addListener(image, EVENT_LOAD, progress, {
3005
+ var onLoad;
3006
+ var onError;
3007
+ addListener(image, EVENT_LOAD, onLoad = function onLoad() {
3008
+ removeListener(image, EVENT_ERROR, onError);
3009
+ progress();
3010
+ }, {
3011
+ once: true
3012
+ });
3013
+ addListener(image, EVENT_ERROR, onError = function onError() {
3014
+ removeListener(image, EVENT_LOAD, onLoad);
3015
+ progress();
3016
+ }, {
3356
3017
  once: true
3357
3018
  });
3358
3019
  }
@@ -3360,7 +3021,6 @@
3360
3021
  } else {
3361
3022
  addListener(element, EVENT_CLICK, this.onStart = function (_ref) {
3362
3023
  var target = _ref.target;
3363
-
3364
3024
  if (target.localName === 'img' && (!isFunction(options.filter) || options.filter.call(_this, target))) {
3365
3025
  _this.view(_this.images.indexOf(target));
3366
3026
  }
@@ -3373,9 +3033,8 @@
3373
3033
  if (this.ready) {
3374
3034
  return;
3375
3035
  }
3376
-
3377
3036
  var element = this.element,
3378
- options = this.options;
3037
+ options = this.options;
3379
3038
  var parent = element.parentNode;
3380
3039
  var template = document.createElement('div');
3381
3040
  template.innerHTML = TEMPLATE;
@@ -3401,82 +3060,65 @@
3401
3060
  addClass(title, !options.title ? CLASS_HIDE : getResponsiveClass(Array.isArray(options.title) ? options.title[0] : options.title));
3402
3061
  addClass(navbar, !options.navbar ? CLASS_HIDE : getResponsiveClass(options.navbar));
3403
3062
  toggleClass(button, CLASS_HIDE, !options.button);
3404
-
3405
3063
  if (options.keyboard) {
3406
3064
  button.setAttribute('tabindex', 0);
3407
3065
  }
3408
-
3409
3066
  if (options.backdrop) {
3410
3067
  addClass(viewer, "".concat(NAMESPACE, "-backdrop"));
3411
-
3412
3068
  if (!options.inline && options.backdrop !== 'static') {
3413
3069
  setData(canvas, DATA_ACTION, 'hide');
3414
3070
  }
3415
3071
  }
3416
-
3417
3072
  if (isString(options.className) && options.className) {
3418
3073
  // In case there are multiple class names
3419
3074
  options.className.split(REGEXP_SPACES).forEach(function (className) {
3420
3075
  addClass(viewer, className);
3421
3076
  });
3422
3077
  }
3423
-
3424
3078
  if (options.toolbar) {
3425
3079
  var list = document.createElement('ul');
3426
3080
  var custom = isPlainObject(options.toolbar);
3427
3081
  var zoomButtons = BUTTONS.slice(0, 3);
3428
3082
  var rotateButtons = BUTTONS.slice(7, 9);
3429
3083
  var scaleButtons = BUTTONS.slice(9);
3430
-
3431
3084
  if (!custom) {
3432
3085
  addClass(toolbar, getResponsiveClass(options.toolbar));
3433
3086
  }
3434
-
3435
3087
  forEach(custom ? options.toolbar : BUTTONS, function (value, index) {
3436
3088
  var deep = custom && isPlainObject(value);
3437
3089
  var name = custom ? hyphenate(index) : value;
3438
3090
  var show = deep && !isUndefined(value.show) ? value.show : value;
3439
-
3440
3091
  if (!show || !options.zoomable && zoomButtons.indexOf(name) !== -1 || !options.rotatable && rotateButtons.indexOf(name) !== -1 || !options.scalable && scaleButtons.indexOf(name) !== -1) {
3441
3092
  return;
3442
3093
  }
3443
-
3444
3094
  var size = deep && !isUndefined(value.size) ? value.size : value;
3445
3095
  var click = deep && !isUndefined(value.click) ? value.click : value;
3446
3096
  var item = document.createElement('li');
3447
-
3448
3097
  if (options.keyboard) {
3449
3098
  item.setAttribute('tabindex', 0);
3450
3099
  }
3451
-
3452
3100
  item.setAttribute('role', 'button');
3453
3101
  addClass(item, "".concat(NAMESPACE, "-").concat(name));
3454
-
3455
3102
  if (!isFunction(click)) {
3456
3103
  setData(item, DATA_ACTION, name);
3457
3104
  }
3458
-
3459
3105
  if (isNumber(show)) {
3460
3106
  addClass(item, getResponsiveClass(show));
3461
3107
  }
3462
-
3463
3108
  if (['small', 'large'].indexOf(size) !== -1) {
3464
3109
  addClass(item, "".concat(NAMESPACE, "-").concat(size));
3465
3110
  } else if (name === 'play') {
3466
3111
  addClass(item, "".concat(NAMESPACE, "-large"));
3467
3112
  }
3468
-
3469
3113
  if (isFunction(click)) {
3470
3114
  addListener(item, EVENT_CLICK, click);
3471
3115
  }
3472
-
3473
3116
  list.appendChild(item);
3474
3117
  });
3475
3118
  toolbar.appendChild(list);
3476
3119
  } else {
3477
3120
  addClass(toolbar, CLASS_HIDE);
3478
3121
  }
3479
-
3480
3122
  if (!options.rotatable) {
3481
3123
  var rotates = toolbar.querySelectorAll('li[class*="rotate"]');
3482
3124
  addClass(rotates, CLASS_INVISIBLE);
@@ -3484,19 +3126,16 @@
3484
3126
  toolbar.appendChild(rotate);
3485
3127
  });
3486
3128
  }
3487
-
3488
3129
  if (options.inline) {
3489
3130
  addClass(button, CLASS_FULLSCREEN);
3490
3131
  setStyle(viewer, {
3491
3132
  zIndex: options.zIndexInline
3492
3133
  });
3493
-
3494
3134
  if (window.getComputedStyle(parent).position === 'static') {
3495
3135
  setStyle(parent, {
3496
3136
  position: 'relative'
3497
3137
  });
3498
3138
  }
3499
-
3500
3139
  parent.insertBefore(viewer, element.nextSibling);
3501
3140
  } else {
3502
3141
  addClass(button, CLASS_CLOSE);
@@ -3507,67 +3146,57 @@
3507
3146
  zIndex: options.zIndex
3508
3147
  });
3509
3148
  var container = options.container;
3510
-
3511
3149
  if (isString(container)) {
3512
3150
  container = element.ownerDocument.querySelector(container);
3513
3151
  }
3514
-
3515
3152
  if (!container) {
3516
3153
  container = this.body;
3517
3154
  }
3518
-
3519
3155
  container.appendChild(viewer);
3520
3156
  }
3521
-
3522
3157
  if (options.inline) {
3523
3158
  this.render();
3524
3159
  this.bind();
3525
3160
  this.isShown = true;
3526
3161
  }
3527
-
3528
3162
  this.ready = true;
3529
-
3530
3163
  if (isFunction(options.ready)) {
3531
3164
  addListener(element, EVENT_READY, options.ready, {
3532
3165
  once: true
3533
3166
  });
3534
3167
  }
3535
-
3536
3168
  if (dispatchEvent(element, EVENT_READY) === false) {
3537
3169
  this.ready = false;
3538
3170
  return;
3539
3171
  }
3540
-
3541
3172
  if (this.ready && options.inline) {
3542
3173
  this.view(this.index);
3543
3174
  }
3544
3175
  }
3176
+
3545
3177
  /**
3546
3178
  * Get the no conflict viewer class.
3547
3179
  * @returns {Viewer} The viewer class.
3548
3180
  */
3549
-
3550
3181
  }], [{
3551
3182
  key: "noConflict",
3552
3183
  value: function noConflict() {
3553
3184
  window.Viewer = AnotherViewer;
3554
3185
  return Viewer;
3555
3186
  }
3187
+
3556
3188
  /**
3557
3189
  * Change the default options.
3558
3190
  * @param {Object} options - The new default options.
3559
3191
  */
3560
-
3561
3192
  }, {
3562
3193
  key: "setDefaults",
3563
3194
  value: function setDefaults(options) {
3564
3195
  assign(DEFAULTS, isPlainObject(options) && options);
3565
3196
  }
3566
3197
  }]);
3567
-
3568
3198
  return Viewer;
3569
3199
  }();
3570
-
3571
3200
  assign(Viewer.prototype, render, events, handlers, methods, others);
3572
3201
 
3573
3202
  return Viewer;