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