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