viewerjs 1.3.3 → 1.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.3.7 (Oct 2, 2019)
4
+
5
+ - Do nothing if the `index` value is invalid when call the `view` method (#312).
6
+ - Ignore invalid `element` parameter on the class utility functions (#317).
7
+ - Improve event type determining for iOS 13+ (#321).
8
+
9
+ ## 1.3.6 (Jul 4, 2019)
10
+
11
+ - Avoid using the `innerHTML` property for security (#269).
12
+ - Avoid escaping URLs (#298, #301).
13
+
14
+ ## 1.3.5 (Jun 29, 2019)
15
+
16
+ - Improve the escaping function to avoid to escape HTML entities repeatedly.
17
+
18
+ ## 1.3.4 (Jun 1, 2019)
19
+
20
+ - Escape all strings that use in HTML for better security (#269).
21
+ - Fix the missing fade out transition when hiding the viewer (#275).
22
+ - Decode image name when it comes from URL (#282).
23
+
3
24
  ## 1.3.3 (Apr 6, 2019)
4
25
 
5
26
  - Fix unexpected modal exiting behavior when the mouse is pressed (#255).
@@ -37,14 +58,14 @@
37
58
 
38
59
  ## 1.0.1 (May 20, 2018)
39
60
 
40
- - Add namespace to data attribute names (from `data-*` to `data-viewer-*`) to avoid side effect.
61
+ - Add a namespace to data attribute names (from `data-*` to `data-viewer-*`) to avoid side effect.
41
62
  - Make sure the image data is a non-null object to avoid unexpected errors.
42
63
  - Fix broken zoom feature in iOS browsers (#167).
43
64
 
44
65
  ## 1.0.0 (Apr 1, 2018)
45
66
 
46
67
  - Add in browser checking to support to import in Node.js.
47
- - Cancel update when there are no images when call the `update` method.
68
+ - Cancel update when there are no images when calling the `update` method.
48
69
 
49
70
  ## 1.0.0-rc.1 (Mar 13, 2018)
50
71
 
@@ -57,7 +78,7 @@
57
78
  - Add a new option: `loading`.
58
79
  - Add type definitions file for TypeScript.
59
80
  - Enhance the `show`, `hide` and `play` methods.
60
- - Change the default value of `loop` option from `false` to `true`.
81
+ - Change the default value of the `loop` option from `false` to `true`.
61
82
 
62
83
  ## 1.0.0-beta.2 (Feb 13, 2018)
63
84
 
@@ -83,7 +104,7 @@
83
104
 
84
105
  - Add a new option: `filter`.
85
106
  - Enhance the `prev` and `next` methods (#47).
86
- - Support to customize the layout of toolbar (#79).
107
+ - Support to customize the layout of the toolbar (#79).
87
108
  - Disallow to show again if it had shown.
88
109
 
89
110
  ## 0.8.0 (Oct 8, 2017)
@@ -94,8 +115,8 @@
94
115
 
95
116
  ## 0.7.2 (Aug 19, 2017)
96
117
 
97
- - Ignore mouse down event when the viewer is hiding (#70).
98
- - Fixed multiple active items in navbar (#75).
118
+ - Ignore the mouse down event when the viewer is hiding (#70).
119
+ - Fixed multiple active items in the navbar (#75).
99
120
 
100
121
  ## 0.7.1 (May 14, 2017)
101
122
 
@@ -113,7 +134,7 @@
113
134
 
114
135
  ## 0.6.1 (Feb 18, 2017)
115
136
 
116
- - Prevented the default behaviour of drag action (#63).
137
+ - Prevented the default behavior of drag action (#63).
117
138
 
118
139
  ## 0.6.0 (Jan 24, 2017)
119
140
 
@@ -122,12 +143,12 @@
122
143
 
123
144
  ## 0.5.1 (Jan 2, 2017)
124
145
 
125
- - Improved event handler for Pointer Events.
146
+ - Improve event handler for Pointer Events.
126
147
 
127
148
  ## 0.5.0 (July 22, 2016)
128
149
 
129
150
  - Improve modal opening and closing.
130
- - Remove `build` event.
151
+ - Remove the `build` event.
131
152
  - Rename `built` event to `ready`.
132
153
  - Fixed a bug of `data-*` attributes setting and getting (#33).
133
154
 
@@ -137,22 +158,22 @@
137
158
 
138
159
  ## 0.3.3 (Mar 19, 2016)
139
160
 
140
- - Fix the issue of hiding wrong element in the "view" method (#19).
161
+ - Fix the issue of hiding the wrong element in the "view" method (#19).
141
162
 
142
163
  ## 0.3.2 (Mar 11, 2016)
143
164
 
144
- - Fix the parameters error on the "url" option when it is a function.
165
+ - Fix the error of the parameters on the "url" option when it is a function.
145
166
 
146
167
  ## 0.3.1 (Feb 2, 2016)
147
168
 
148
169
  - Added tests.
149
- - Ignored invalid class name.
170
+ - Ignored the invalid class name.
150
171
  - Re-render image only when viewed.
151
172
 
152
173
  ## 0.3.0 (Jan 21, 2016)
153
174
 
154
175
  - Add more available values to the "title", "toolbar" and "navbar" options.
155
- - Support to toggle the visibility of title, toolbar and navbar between different screen widths.
176
+ - Support to toggle the visibility of title, toolbar, and navbar between different screen widths.
156
177
  - Exit fullscreen when stop playing.
157
178
  - Fixed title not generated bug.
158
179
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Viewer.js
2
2
 
3
- [![Build Status](https://img.shields.io/travis/fengyuanchen/viewerjs.svg)](https://travis-ci.org/fengyuanchen/viewerjs) [![Downloads](https://img.shields.io/npm/dm/viewerjs.svg)](https://www.npmjs.com/package/viewerjs) [![Version](https://img.shields.io/npm/v/viewerjs.svg)](https://www.npmjs.com/package/viewerjs) [![Donate on Patreon](https://img.shields.io/badge/donate-on%20patreon-fa7664.svg)](https://www.patreon.com/chenfengyuan)
3
+ [![Build Status](https://img.shields.io/travis/fengyuanchen/viewerjs.svg)](https://travis-ci.org/fengyuanchen/viewerjs) [![Downloads](https://img.shields.io/npm/dm/viewerjs.svg)](https://www.npmjs.com/package/viewerjs) [![Version](https://img.shields.io/npm/v/viewerjs.svg)](https://www.npmjs.com/package/viewerjs)
4
4
 
5
5
  > JavaScript image viewer.
6
6
 
@@ -1,11 +1,11 @@
1
1
  /*!
2
- * Viewer.js v1.3.3
2
+ * Viewer.js v1.3.7
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: 2019-04-06T14:06:28.301Z
8
+ * Date: 2019-10-02T09:29:13.426Z
9
9
  */
10
10
 
11
11
  'use strict';
@@ -46,6 +46,55 @@ function _createClass(Constructor, protoProps, staticProps) {
46
46
  return Constructor;
47
47
  }
48
48
 
49
+ function _defineProperty(obj, key, value) {
50
+ if (key in obj) {
51
+ Object.defineProperty(obj, key, {
52
+ value: value,
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true
56
+ });
57
+ } else {
58
+ obj[key] = value;
59
+ }
60
+
61
+ return obj;
62
+ }
63
+
64
+ function ownKeys(object, enumerableOnly) {
65
+ var keys = Object.keys(object);
66
+
67
+ if (Object.getOwnPropertySymbols) {
68
+ var symbols = Object.getOwnPropertySymbols(object);
69
+ if (enumerableOnly) symbols = symbols.filter(function (sym) {
70
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
71
+ });
72
+ keys.push.apply(keys, symbols);
73
+ }
74
+
75
+ return keys;
76
+ }
77
+
78
+ function _objectSpread2(target) {
79
+ for (var i = 1; i < arguments.length; i++) {
80
+ var source = arguments[i] != null ? arguments[i] : {};
81
+
82
+ if (i % 2) {
83
+ ownKeys(source, true).forEach(function (key) {
84
+ _defineProperty(target, key, source[key]);
85
+ });
86
+ } else if (Object.getOwnPropertyDescriptors) {
87
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
88
+ } else {
89
+ ownKeys(source).forEach(function (key) {
90
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
91
+ });
92
+ }
93
+ }
94
+
95
+ return target;
96
+ }
97
+
49
98
  var DEFAULTS = {
50
99
  /**
51
100
  * Enable a modal backdrop, specify `static` for a backdrop
@@ -246,7 +295,7 @@ var DEFAULTS = {
246
295
 
247
296
  var TEMPLATE = '<div class="viewer-container" touch-action="none">' + '<div class="viewer-canvas"></div>' + '<div class="viewer-footer">' + '<div class="viewer-title"></div>' + '<div class="viewer-toolbar"></div>' + '<div class="viewer-navbar">' + '<ul class="viewer-list"></ul>' + '</div>' + '</div>' + '<div class="viewer-tooltip"></div>' + '<div role="button" class="viewer-button" data-viewer-action="mix"></div>' + '<div class="viewer-player"></div>' + '</div>';
248
297
 
249
- var IS_BROWSER = typeof window !== 'undefined';
298
+ var IS_BROWSER = typeof window !== 'undefined' && typeof window.document !== 'undefined';
250
299
  var WINDOW = IS_BROWSER ? window : {};
251
300
  var IS_TOUCH_DEVICE = IS_BROWSER ? 'ontouchstart' in WINDOW.document.documentElement : false;
252
301
  var HAS_POINTER_EVENT = IS_BROWSER ? 'PointerEvent' in WINDOW : false;
@@ -444,6 +493,15 @@ function setStyle(element, styles) {
444
493
  style[property] = value;
445
494
  });
446
495
  }
496
+ /**
497
+ * Escape a string for using in HTML.
498
+ * @param {String} value - The string to escape.
499
+ * @returns {String} Returns the escaped string.
500
+ */
501
+
502
+ function escapeHTMLEntities(value) {
503
+ 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;
504
+ }
447
505
  /**
448
506
  * Check if the given element has a special class.
449
507
  * @param {Element} element - The element to check.
@@ -452,6 +510,10 @@ function setStyle(element, styles) {
452
510
  */
453
511
 
454
512
  function hasClass(element, value) {
513
+ if (!element || !value) {
514
+ return false;
515
+ }
516
+
455
517
  return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1;
456
518
  }
457
519
  /**
@@ -461,7 +523,7 @@ function hasClass(element, value) {
461
523
  */
462
524
 
463
525
  function addClass(element, value) {
464
- if (!value) {
526
+ if (!element || !value) {
465
527
  return;
466
528
  }
467
529
 
@@ -492,7 +554,7 @@ function addClass(element, value) {
492
554
  */
493
555
 
494
556
  function removeClass(element, value) {
495
- if (!value) {
557
+ if (!element || !value) {
496
558
  return;
497
559
  }
498
560
 
@@ -776,7 +838,7 @@ function getTransforms(_ref) {
776
838
  */
777
839
 
778
840
  function getImageNameFromURL(url) {
779
- return isString(url) ? url.replace(/^.*\//, '').replace(/[?&#].*$/, '') : '';
841
+ return isString(url) ? decodeURIComponent(url.replace(/^.*\//, '').replace(/[?&#].*$/, '')) : '';
780
842
  }
781
843
  var IS_SAFARI = WINDOW.navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(WINDOW.navigator.userAgent);
782
844
  /**
@@ -842,7 +904,8 @@ function getResponsiveClass(type) {
842
904
  */
843
905
 
844
906
  function getMaxZoomRatio(pointers) {
845
- var pointers2 = assign({}, pointers);
907
+ var pointers2 = _objectSpread2({}, pointers);
908
+
846
909
  var ratios = [];
847
910
  forEach(pointers, function (pointer, pointerId) {
848
911
  delete pointers2[pointerId];
@@ -876,7 +939,7 @@ function getPointer(_ref2, endOnly) {
876
939
  endX: pageX,
877
940
  endY: pageY
878
941
  };
879
- return endOnly ? end : assign({
942
+ return endOnly ? end : _objectSpread2({
880
943
  timeStamp: Date.now(),
881
944
  startX: pageX,
882
945
  startY: pageY
@@ -950,8 +1013,10 @@ var render = {
950
1013
  var element = this.element,
951
1014
  options = this.options,
952
1015
  list = this.list;
953
- var items = [];
954
- forEach(this.images, function (image, i) {
1016
+ var items = []; // initList may be called in this.update, so should keep idempotent
1017
+
1018
+ list.innerHTML = '';
1019
+ forEach(this.images, function (image, index) {
955
1020
  var src = image.src;
956
1021
  var alt = image.alt || getImageNameFromURL(src);
957
1022
  var url = options.url;
@@ -963,12 +1028,21 @@ var render = {
963
1028
  }
964
1029
 
965
1030
  if (src || url) {
966
- items.push('<li>' + '<img' + " src=\"".concat(src || url, "\"") + ' role="button"' + ' data-viewer-action="view"' + " data-index=\"".concat(i, "\"") + " data-original-url=\"".concat(url || src, "\"") + " alt=\"".concat(alt, "\"") + '>' + '</li>');
1031
+ var item = document.createElement('li');
1032
+ var img = document.createElement('img');
1033
+ img.src = src || url;
1034
+ img.alt = alt;
1035
+ img.setAttribute('data-index', index);
1036
+ img.setAttribute('data-original-url', url || src);
1037
+ img.setAttribute('data-viewer-action', 'view');
1038
+ img.setAttribute('role', 'button');
1039
+ item.appendChild(img);
1040
+ list.appendChild(item);
1041
+ items.push(item);
967
1042
  }
968
1043
  });
969
- list.innerHTML = items.join('');
970
- this.items = list.getElementsByTagName('li');
971
- forEach(this.items, function (item) {
1044
+ this.items = items;
1045
+ forEach(items, function (item) {
972
1046
  var image = item.firstElementChild;
973
1047
  setData(image, 'filled', true);
974
1048
 
@@ -1425,10 +1499,10 @@ var handlers = {
1425
1499
  var buttons = event.buttons,
1426
1500
  button = event.button;
1427
1501
 
1428
- if (!this.viewed || this.showing || this.viewing || this.hiding // No primary button (Usually the left button)
1429
- // Note that touch events have no `buttons` or `button` property
1430
- || isNumber(buttons) && buttons !== 1 || isNumber(button) && button !== 0 // Open context menu
1431
- || event.ctrlKey) {
1502
+ if (!this.viewed || this.showing || this.viewing || this.hiding // Handle mouse event and pointer event and ignore touch event
1503
+ || (event.type === 'mousedown' || event.type === 'pointerdown' && event.pointerType === 'mouse') && ( // No primary button (Usually the left button)
1504
+ isNumber(buttons) && buttons !== 1 || isNumber(button) && button !== 0 // Open context menu
1505
+ || event.ctrlKey)) {
1432
1506
  return;
1433
1507
  } // Prevent default behaviours as page zooming in touch devices.
1434
1508
 
@@ -1710,10 +1784,13 @@ var methods = {
1710
1784
  var hidden = this.hidden.bind(this);
1711
1785
 
1712
1786
  var hide = function hide() {
1713
- addListener(viewer, EVENT_TRANSITION_END, hidden, {
1714
- once: true
1715
- });
1716
- removeClass(viewer, CLASS_IN);
1787
+ // XXX: It seems the `event.stopPropagation()` method does not work here
1788
+ setTimeout(function () {
1789
+ addListener(viewer, EVENT_TRANSITION_END, hidden, {
1790
+ once: true
1791
+ });
1792
+ removeClass(viewer, CLASS_IN);
1793
+ }, 0);
1717
1794
  };
1718
1795
 
1719
1796
  this.transitioning = {
@@ -1753,15 +1830,15 @@ var methods = {
1753
1830
  var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.initialViewIndex;
1754
1831
  index = Number(index) || 0;
1755
1832
 
1833
+ if (this.hiding || this.played || index < 0 || index >= this.length || this.viewed && index === this.index) {
1834
+ return this;
1835
+ }
1836
+
1756
1837
  if (!this.isShown) {
1757
1838
  this.index = index;
1758
1839
  return this.show();
1759
1840
  }
1760
1841
 
1761
- if (this.hiding || this.played || index < 0 || index >= this.length || this.viewed && index === this.index) {
1762
- return this;
1763
- }
1764
-
1765
1842
  if (this.viewing) {
1766
1843
  this.viewing.abort();
1767
1844
  }
@@ -1814,7 +1891,7 @@ var methods = {
1814
1891
  var onViewed = function onViewed() {
1815
1892
  var imageData = _this.imageData;
1816
1893
  var render = Array.isArray(options.title) ? options.title[1] : options.title;
1817
- title.innerHTML = isFunction(render) ? render.call(_this, image, imageData) : "".concat(alt, " (").concat(imageData.naturalWidth, " \xD7 ").concat(imageData.naturalHeight, ")");
1894
+ title.innerHTML = escapeHTMLEntities(isFunction(render) ? render.call(_this, image, imageData) : "".concat(alt, " (").concat(imageData.naturalWidth, " \xD7 ").concat(imageData.naturalHeight, ")"));
1818
1895
  };
1819
1896
 
1820
1897
  var onLoad;
package/dist/viewer.css CHANGED
@@ -1,11 +1,11 @@
1
1
  /*!
2
- * Viewer.js v1.3.3
2
+ * Viewer.js v1.3.7
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: 2019-04-06T14:06:24.626Z
8
+ * Date: 2019-10-02T09:29:07.561Z
9
9
  */
10
10
 
11
11
  .viewer-zoom-in::before,
@@ -123,6 +123,11 @@
123
123
  user-select: none;
124
124
  }
125
125
 
126
+ .viewer-container::-moz-selection,
127
+ .viewer-container *::-moz-selection {
128
+ background-color: transparent;
129
+ }
130
+
126
131
  .viewer-container::selection,
127
132
  .viewer-container *::selection {
128
133
  background-color: transparent;
@@ -1,11 +1,11 @@
1
1
  /*!
2
- * Viewer.js v1.3.3
2
+ * Viewer.js v1.3.7
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: 2019-04-06T14:06:28.301Z
8
+ * Date: 2019-10-02T09:29:13.426Z
9
9
  */
10
10
 
11
11
  function _typeof(obj) {
@@ -44,6 +44,55 @@ function _createClass(Constructor, protoProps, staticProps) {
44
44
  return Constructor;
45
45
  }
46
46
 
47
+ function _defineProperty(obj, key, value) {
48
+ if (key in obj) {
49
+ Object.defineProperty(obj, key, {
50
+ value: value,
51
+ enumerable: true,
52
+ configurable: true,
53
+ writable: true
54
+ });
55
+ } else {
56
+ obj[key] = value;
57
+ }
58
+
59
+ return obj;
60
+ }
61
+
62
+ function ownKeys(object, enumerableOnly) {
63
+ var keys = Object.keys(object);
64
+
65
+ if (Object.getOwnPropertySymbols) {
66
+ var symbols = Object.getOwnPropertySymbols(object);
67
+ if (enumerableOnly) symbols = symbols.filter(function (sym) {
68
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
69
+ });
70
+ keys.push.apply(keys, symbols);
71
+ }
72
+
73
+ return keys;
74
+ }
75
+
76
+ function _objectSpread2(target) {
77
+ for (var i = 1; i < arguments.length; i++) {
78
+ var source = arguments[i] != null ? arguments[i] : {};
79
+
80
+ if (i % 2) {
81
+ ownKeys(source, true).forEach(function (key) {
82
+ _defineProperty(target, key, source[key]);
83
+ });
84
+ } else if (Object.getOwnPropertyDescriptors) {
85
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
86
+ } else {
87
+ ownKeys(source).forEach(function (key) {
88
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
89
+ });
90
+ }
91
+ }
92
+
93
+ return target;
94
+ }
95
+
47
96
  var DEFAULTS = {
48
97
  /**
49
98
  * Enable a modal backdrop, specify `static` for a backdrop
@@ -244,7 +293,7 @@ var DEFAULTS = {
244
293
 
245
294
  var TEMPLATE = '<div class="viewer-container" touch-action="none">' + '<div class="viewer-canvas"></div>' + '<div class="viewer-footer">' + '<div class="viewer-title"></div>' + '<div class="viewer-toolbar"></div>' + '<div class="viewer-navbar">' + '<ul class="viewer-list"></ul>' + '</div>' + '</div>' + '<div class="viewer-tooltip"></div>' + '<div role="button" class="viewer-button" data-viewer-action="mix"></div>' + '<div class="viewer-player"></div>' + '</div>';
246
295
 
247
- var IS_BROWSER = typeof window !== 'undefined';
296
+ var IS_BROWSER = typeof window !== 'undefined' && typeof window.document !== 'undefined';
248
297
  var WINDOW = IS_BROWSER ? window : {};
249
298
  var IS_TOUCH_DEVICE = IS_BROWSER ? 'ontouchstart' in WINDOW.document.documentElement : false;
250
299
  var HAS_POINTER_EVENT = IS_BROWSER ? 'PointerEvent' in WINDOW : false;
@@ -442,6 +491,15 @@ function setStyle(element, styles) {
442
491
  style[property] = value;
443
492
  });
444
493
  }
494
+ /**
495
+ * Escape a string for using in HTML.
496
+ * @param {String} value - The string to escape.
497
+ * @returns {String} Returns the escaped string.
498
+ */
499
+
500
+ function escapeHTMLEntities(value) {
501
+ 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;
502
+ }
445
503
  /**
446
504
  * Check if the given element has a special class.
447
505
  * @param {Element} element - The element to check.
@@ -450,6 +508,10 @@ function setStyle(element, styles) {
450
508
  */
451
509
 
452
510
  function hasClass(element, value) {
511
+ if (!element || !value) {
512
+ return false;
513
+ }
514
+
453
515
  return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1;
454
516
  }
455
517
  /**
@@ -459,7 +521,7 @@ function hasClass(element, value) {
459
521
  */
460
522
 
461
523
  function addClass(element, value) {
462
- if (!value) {
524
+ if (!element || !value) {
463
525
  return;
464
526
  }
465
527
 
@@ -490,7 +552,7 @@ function addClass(element, value) {
490
552
  */
491
553
 
492
554
  function removeClass(element, value) {
493
- if (!value) {
555
+ if (!element || !value) {
494
556
  return;
495
557
  }
496
558
 
@@ -774,7 +836,7 @@ function getTransforms(_ref) {
774
836
  */
775
837
 
776
838
  function getImageNameFromURL(url) {
777
- return isString(url) ? url.replace(/^.*\//, '').replace(/[?&#].*$/, '') : '';
839
+ return isString(url) ? decodeURIComponent(url.replace(/^.*\//, '').replace(/[?&#].*$/, '')) : '';
778
840
  }
779
841
  var IS_SAFARI = WINDOW.navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(WINDOW.navigator.userAgent);
780
842
  /**
@@ -840,7 +902,8 @@ function getResponsiveClass(type) {
840
902
  */
841
903
 
842
904
  function getMaxZoomRatio(pointers) {
843
- var pointers2 = assign({}, pointers);
905
+ var pointers2 = _objectSpread2({}, pointers);
906
+
844
907
  var ratios = [];
845
908
  forEach(pointers, function (pointer, pointerId) {
846
909
  delete pointers2[pointerId];
@@ -874,7 +937,7 @@ function getPointer(_ref2, endOnly) {
874
937
  endX: pageX,
875
938
  endY: pageY
876
939
  };
877
- return endOnly ? end : assign({
940
+ return endOnly ? end : _objectSpread2({
878
941
  timeStamp: Date.now(),
879
942
  startX: pageX,
880
943
  startY: pageY
@@ -948,8 +1011,10 @@ var render = {
948
1011
  var element = this.element,
949
1012
  options = this.options,
950
1013
  list = this.list;
951
- var items = [];
952
- forEach(this.images, function (image, i) {
1014
+ var items = []; // initList may be called in this.update, so should keep idempotent
1015
+
1016
+ list.innerHTML = '';
1017
+ forEach(this.images, function (image, index) {
953
1018
  var src = image.src;
954
1019
  var alt = image.alt || getImageNameFromURL(src);
955
1020
  var url = options.url;
@@ -961,12 +1026,21 @@ var render = {
961
1026
  }
962
1027
 
963
1028
  if (src || url) {
964
- items.push('<li>' + '<img' + " src=\"".concat(src || url, "\"") + ' role="button"' + ' data-viewer-action="view"' + " data-index=\"".concat(i, "\"") + " data-original-url=\"".concat(url || src, "\"") + " alt=\"".concat(alt, "\"") + '>' + '</li>');
1029
+ var item = document.createElement('li');
1030
+ var img = document.createElement('img');
1031
+ img.src = src || url;
1032
+ img.alt = alt;
1033
+ img.setAttribute('data-index', index);
1034
+ img.setAttribute('data-original-url', url || src);
1035
+ img.setAttribute('data-viewer-action', 'view');
1036
+ img.setAttribute('role', 'button');
1037
+ item.appendChild(img);
1038
+ list.appendChild(item);
1039
+ items.push(item);
965
1040
  }
966
1041
  });
967
- list.innerHTML = items.join('');
968
- this.items = list.getElementsByTagName('li');
969
- forEach(this.items, function (item) {
1042
+ this.items = items;
1043
+ forEach(items, function (item) {
970
1044
  var image = item.firstElementChild;
971
1045
  setData(image, 'filled', true);
972
1046
 
@@ -1423,10 +1497,10 @@ var handlers = {
1423
1497
  var buttons = event.buttons,
1424
1498
  button = event.button;
1425
1499
 
1426
- if (!this.viewed || this.showing || this.viewing || this.hiding // No primary button (Usually the left button)
1427
- // Note that touch events have no `buttons` or `button` property
1428
- || isNumber(buttons) && buttons !== 1 || isNumber(button) && button !== 0 // Open context menu
1429
- || event.ctrlKey) {
1500
+ if (!this.viewed || this.showing || this.viewing || this.hiding // Handle mouse event and pointer event and ignore touch event
1501
+ || (event.type === 'mousedown' || event.type === 'pointerdown' && event.pointerType === 'mouse') && ( // No primary button (Usually the left button)
1502
+ isNumber(buttons) && buttons !== 1 || isNumber(button) && button !== 0 // Open context menu
1503
+ || event.ctrlKey)) {
1430
1504
  return;
1431
1505
  } // Prevent default behaviours as page zooming in touch devices.
1432
1506
 
@@ -1708,10 +1782,13 @@ var methods = {
1708
1782
  var hidden = this.hidden.bind(this);
1709
1783
 
1710
1784
  var hide = function hide() {
1711
- addListener(viewer, EVENT_TRANSITION_END, hidden, {
1712
- once: true
1713
- });
1714
- removeClass(viewer, CLASS_IN);
1785
+ // XXX: It seems the `event.stopPropagation()` method does not work here
1786
+ setTimeout(function () {
1787
+ addListener(viewer, EVENT_TRANSITION_END, hidden, {
1788
+ once: true
1789
+ });
1790
+ removeClass(viewer, CLASS_IN);
1791
+ }, 0);
1715
1792
  };
1716
1793
 
1717
1794
  this.transitioning = {
@@ -1751,15 +1828,15 @@ var methods = {
1751
1828
  var index = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.options.initialViewIndex;
1752
1829
  index = Number(index) || 0;
1753
1830
 
1831
+ if (this.hiding || this.played || index < 0 || index >= this.length || this.viewed && index === this.index) {
1832
+ return this;
1833
+ }
1834
+
1754
1835
  if (!this.isShown) {
1755
1836
  this.index = index;
1756
1837
  return this.show();
1757
1838
  }
1758
1839
 
1759
- if (this.hiding || this.played || index < 0 || index >= this.length || this.viewed && index === this.index) {
1760
- return this;
1761
- }
1762
-
1763
1840
  if (this.viewing) {
1764
1841
  this.viewing.abort();
1765
1842
  }
@@ -1812,7 +1889,7 @@ var methods = {
1812
1889
  var onViewed = function onViewed() {
1813
1890
  var imageData = _this.imageData;
1814
1891
  var render = Array.isArray(options.title) ? options.title[1] : options.title;
1815
- title.innerHTML = isFunction(render) ? render.call(_this, image, imageData) : "".concat(alt, " (").concat(imageData.naturalWidth, " \xD7 ").concat(imageData.naturalHeight, ")");
1892
+ title.innerHTML = escapeHTMLEntities(isFunction(render) ? render.call(_this, image, imageData) : "".concat(alt, " (").concat(imageData.naturalWidth, " \xD7 ").concat(imageData.naturalHeight, ")"));
1816
1893
  };
1817
1894
 
1818
1895
  var onLoad;