viewerjs 1.11.9 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +223 -51
- package/dist/viewer.common.js +500 -114
- package/dist/viewer.css +111 -2
- package/dist/viewer.esm.js +500 -114
- package/dist/viewer.js +500 -114
- package/dist/viewer.min.css +3 -3
- package/dist/viewer.min.js +3 -3
- package/package.json +8 -9
- package/src/css/viewer.css +107 -1
- package/src/css/viewer.scss +107 -1
- package/src/js/constants.js +5 -0
- package/src/js/defaults.js +46 -4
- package/src/js/events.js +29 -2
- package/src/js/handlers.js +197 -7
- package/src/js/methods.js +89 -62
- package/src/js/others.js +48 -3
- package/src/js/render.js +83 -15
- package/src/js/template.js +7 -0
- package/src/js/utilities.js +70 -14
- package/src/js/viewer.js +82 -11
- package/types/index.d.ts +91 -55
package/src/js/methods.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
EVENT_CLICK,
|
|
13
13
|
EVENT_ERROR,
|
|
14
14
|
EVENT_HIDE,
|
|
15
|
+
EVENT_KEY_DOWN,
|
|
15
16
|
EVENT_LOAD,
|
|
16
17
|
EVENT_MOVE,
|
|
17
18
|
EVENT_MOVED,
|
|
@@ -40,9 +41,11 @@ import {
|
|
|
40
41
|
getOffset,
|
|
41
42
|
getPointersCenter,
|
|
42
43
|
hasClass,
|
|
44
|
+
inheritAttributes,
|
|
43
45
|
isFunction,
|
|
44
46
|
isNumber,
|
|
45
47
|
isPlainObject,
|
|
48
|
+
isTransitionEnabled,
|
|
46
49
|
isUndefined,
|
|
47
50
|
removeClass,
|
|
48
51
|
removeListener,
|
|
@@ -97,7 +100,7 @@ export default {
|
|
|
97
100
|
viewer.setAttribute('aria-modal', true);
|
|
98
101
|
viewer.removeAttribute('aria-hidden');
|
|
99
102
|
|
|
100
|
-
if (options
|
|
103
|
+
if (isTransitionEnabled(options, 'show') && !immediate) {
|
|
101
104
|
const shown = this.shown.bind(this);
|
|
102
105
|
|
|
103
106
|
this.transitioning = {
|
|
@@ -141,7 +144,7 @@ export default {
|
|
|
141
144
|
});
|
|
142
145
|
}
|
|
143
146
|
|
|
144
|
-
if (dispatchEvent(element, EVENT_HIDE) === false) {
|
|
147
|
+
if (dispatchEvent(element, EVENT_HIDE) === false || this.destroyed) {
|
|
145
148
|
return this;
|
|
146
149
|
}
|
|
147
150
|
|
|
@@ -163,7 +166,7 @@ export default {
|
|
|
163
166
|
this.hidden();
|
|
164
167
|
};
|
|
165
168
|
|
|
166
|
-
if (options
|
|
169
|
+
if (isTransitionEnabled(options, 'hide') && !immediate) {
|
|
167
170
|
const onViewerTransitionEnd = (event) => {
|
|
168
171
|
// Ignore all propagating `transitionend` events (#275).
|
|
169
172
|
if (event && event.target === viewer) {
|
|
@@ -214,10 +217,12 @@ export default {
|
|
|
214
217
|
* @returns {Viewer} this
|
|
215
218
|
*/
|
|
216
219
|
view(index = this.options.initialViewIndex) {
|
|
220
|
+
const previousIndex = this.index;
|
|
221
|
+
|
|
217
222
|
index = Number(index) || 0;
|
|
218
223
|
|
|
219
224
|
if (this.hiding || this.played || index < 0 || index >= this.length
|
|
220
|
-
|| (this.viewed && index ===
|
|
225
|
+
|| (this.viewed && index === previousIndex)) {
|
|
221
226
|
return this;
|
|
222
227
|
}
|
|
223
228
|
|
|
@@ -236,20 +241,19 @@ export default {
|
|
|
236
241
|
title,
|
|
237
242
|
canvas,
|
|
238
243
|
} = this;
|
|
239
|
-
|
|
244
|
+
let item = this.getItem(index);
|
|
245
|
+
|
|
246
|
+
if (!item) {
|
|
247
|
+
this.initList(index);
|
|
248
|
+
item = this.getItem(index);
|
|
249
|
+
}
|
|
250
|
+
|
|
240
251
|
const img = item.querySelector('img');
|
|
241
252
|
const url = getData(img, 'originalUrl');
|
|
242
253
|
const alt = img.getAttribute('alt');
|
|
243
254
|
const image = document.createElement('img');
|
|
244
255
|
|
|
245
|
-
|
|
246
|
-
const value = img.getAttribute(name);
|
|
247
|
-
|
|
248
|
-
if (value !== null) {
|
|
249
|
-
image.setAttribute(name, value);
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
|
|
256
|
+
inheritAttributes(image, img, options.inheritedAttributes);
|
|
253
257
|
image.src = url;
|
|
254
258
|
image.alt = alt;
|
|
255
259
|
|
|
@@ -267,7 +271,9 @@ export default {
|
|
|
267
271
|
return this;
|
|
268
272
|
}
|
|
269
273
|
|
|
270
|
-
|
|
274
|
+
this.hideMagnifier();
|
|
275
|
+
|
|
276
|
+
const activeItem = this.getItem(previousIndex);
|
|
271
277
|
|
|
272
278
|
if (activeItem) {
|
|
273
279
|
removeClass(activeItem, CLASS_ACTIVE);
|
|
@@ -308,6 +314,28 @@ export default {
|
|
|
308
314
|
title.innerHTML = escapeHTMLEntities(isFunction(render)
|
|
309
315
|
? render.call(this, image, imageData)
|
|
310
316
|
: `${alt} (${imageData.naturalWidth} × ${imageData.naturalHeight})`);
|
|
317
|
+
|
|
318
|
+
// Preload the image in the direction of navigation
|
|
319
|
+
if (options.preload) {
|
|
320
|
+
const direction = index < previousIndex ? -1 : 1;
|
|
321
|
+
let nextIndex = index + direction;
|
|
322
|
+
|
|
323
|
+
if (nextIndex < 0 || nextIndex >= this.length) {
|
|
324
|
+
if (options.loop) {
|
|
325
|
+
nextIndex = direction > 0 ? 0 : this.length - 1;
|
|
326
|
+
} else {
|
|
327
|
+
nextIndex = -1;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if (nextIndex !== index) {
|
|
332
|
+
const nextImage = this.images[nextIndex];
|
|
333
|
+
const preloadedImage = document.createElement('img');
|
|
334
|
+
|
|
335
|
+
inheritAttributes(preloadedImage, nextImage, options.inheritedAttributes);
|
|
336
|
+
preloadedImage.src = this.getImageURL(nextImage) || nextImage.src;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
311
339
|
};
|
|
312
340
|
let onLoad;
|
|
313
341
|
let onError;
|
|
@@ -481,6 +509,7 @@ export default {
|
|
|
481
509
|
imageData.y = y;
|
|
482
510
|
imageData.left = x;
|
|
483
511
|
imageData.top = y;
|
|
512
|
+
toggleClass(this.image, CLASS_TRANSITION, isTransitionEnabled(options, 'move'));
|
|
484
513
|
this.moving = true;
|
|
485
514
|
this.renderImage(() => {
|
|
486
515
|
this.moving = false;
|
|
@@ -545,6 +574,7 @@ export default {
|
|
|
545
574
|
}
|
|
546
575
|
|
|
547
576
|
imageData.rotate = degree;
|
|
577
|
+
toggleClass(this.image, CLASS_TRANSITION, isTransitionEnabled(options, 'rotate'));
|
|
548
578
|
this.rotating = true;
|
|
549
579
|
this.renderImage(() => {
|
|
550
580
|
this.rotating = false;
|
|
@@ -636,6 +666,7 @@ export default {
|
|
|
636
666
|
|
|
637
667
|
imageData.scaleX = scaleX;
|
|
638
668
|
imageData.scaleY = scaleY;
|
|
669
|
+
toggleClass(this.image, CLASS_TRANSITION, isTransitionEnabled(options, 'scale'));
|
|
639
670
|
this.scaling = true;
|
|
640
671
|
this.renderImage(() => {
|
|
641
672
|
this.scaling = false;
|
|
@@ -719,8 +750,12 @@ export default {
|
|
|
719
750
|
|
|
720
751
|
if (isNumber(ratio) && this.viewed && !this.played && (_zoomable || options.zoomable)) {
|
|
721
752
|
if (!_zoomable) {
|
|
722
|
-
const minZoomRatio = Math.max(0.01, options.minZoomRatio)
|
|
723
|
-
|
|
753
|
+
const minZoomRatio = Math.max(0.01, isFunction(options.minZoomRatio)
|
|
754
|
+
? options.minZoomRatio.call(this, this.image, imageData)
|
|
755
|
+
: options.minZoomRatio);
|
|
756
|
+
const maxZoomRatio = Math.min(100, isFunction(options.maxZoomRatio)
|
|
757
|
+
? options.maxZoomRatio.call(this, this.image, imageData)
|
|
758
|
+
: options.maxZoomRatio);
|
|
724
759
|
|
|
725
760
|
ratio = Math.min(Math.max(ratio, minZoomRatio), maxZoomRatio);
|
|
726
761
|
}
|
|
@@ -794,6 +829,7 @@ export default {
|
|
|
794
829
|
imageData.height = newHeight;
|
|
795
830
|
imageData.oldRatio = oldRatio;
|
|
796
831
|
imageData.ratio = ratio;
|
|
832
|
+
toggleClass(this.image, CLASS_TRANSITION, isTransitionEnabled(options, 'zoom'));
|
|
797
833
|
this.renderImage(() => {
|
|
798
834
|
this.zooming = false;
|
|
799
835
|
|
|
@@ -856,18 +892,17 @@ export default {
|
|
|
856
892
|
}
|
|
857
893
|
|
|
858
894
|
addClass(player, CLASS_SHOW);
|
|
859
|
-
forEach(this.
|
|
860
|
-
const img = item.querySelector('img');
|
|
895
|
+
forEach(this.images, (originalImage, i) => {
|
|
861
896
|
const image = document.createElement('img');
|
|
862
897
|
|
|
863
|
-
image.src =
|
|
864
|
-
image.alt =
|
|
865
|
-
image.referrerPolicy =
|
|
898
|
+
image.src = this.getImageURL(originalImage) || originalImage.src;
|
|
899
|
+
image.alt = originalImage.alt || '';
|
|
900
|
+
image.referrerPolicy = originalImage.referrerPolicy;
|
|
866
901
|
total += 1;
|
|
867
902
|
addClass(image, CLASS_FADE);
|
|
868
|
-
toggleClass(image, CLASS_TRANSITION, options
|
|
903
|
+
toggleClass(image, CLASS_TRANSITION, isTransitionEnabled(options, 'play'));
|
|
869
904
|
|
|
870
|
-
if (
|
|
905
|
+
if (i === this.index) {
|
|
871
906
|
addClass(image, CLASS_IN);
|
|
872
907
|
index = i;
|
|
873
908
|
}
|
|
@@ -886,7 +921,7 @@ export default {
|
|
|
886
921
|
index -= 1;
|
|
887
922
|
index = index >= 0 ? index : total - 1;
|
|
888
923
|
addClass(list[index], CLASS_IN);
|
|
889
|
-
this.playing.timeout = setTimeout(prev, options.interval);
|
|
924
|
+
this.playing.timeout = options.autoplay ? setTimeout(prev, options.interval) : null;
|
|
890
925
|
};
|
|
891
926
|
const next = () => {
|
|
892
927
|
clearTimeout(this.playing.timeout);
|
|
@@ -894,14 +929,14 @@ export default {
|
|
|
894
929
|
index += 1;
|
|
895
930
|
index = index < total ? index : 0;
|
|
896
931
|
addClass(list[index], CLASS_IN);
|
|
897
|
-
this.playing.timeout = setTimeout(next, options.interval);
|
|
932
|
+
this.playing.timeout = options.autoplay ? setTimeout(next, options.interval) : null;
|
|
898
933
|
};
|
|
899
934
|
|
|
900
935
|
if (total > 1) {
|
|
901
936
|
this.playing = {
|
|
902
937
|
prev,
|
|
903
938
|
next,
|
|
904
|
-
timeout: setTimeout(next, options.interval),
|
|
939
|
+
timeout: options.autoplay ? setTimeout(next, options.interval) : null,
|
|
905
940
|
};
|
|
906
941
|
}
|
|
907
942
|
}
|
|
@@ -959,12 +994,10 @@ export default {
|
|
|
959
994
|
this.open();
|
|
960
995
|
addClass(this.button, CLASS_FULLSCREEN_EXIT);
|
|
961
996
|
|
|
962
|
-
|
|
963
|
-
removeClass(list, CLASS_TRANSITION);
|
|
997
|
+
removeClass(list, CLASS_TRANSITION);
|
|
964
998
|
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
}
|
|
999
|
+
if (this.viewed) {
|
|
1000
|
+
removeClass(image, CLASS_TRANSITION);
|
|
968
1001
|
}
|
|
969
1002
|
|
|
970
1003
|
addClass(viewer, CLASS_FIXED);
|
|
@@ -986,14 +1019,7 @@ export default {
|
|
|
986
1019
|
|
|
987
1020
|
if (this.viewed) {
|
|
988
1021
|
this.initImage(() => {
|
|
989
|
-
this.renderImage(
|
|
990
|
-
if (options.transition) {
|
|
991
|
-
setTimeout(() => {
|
|
992
|
-
addClass(image, CLASS_TRANSITION);
|
|
993
|
-
addClass(list, CLASS_TRANSITION);
|
|
994
|
-
}, 0);
|
|
995
|
-
}
|
|
996
|
-
});
|
|
1022
|
+
this.renderImage();
|
|
997
1023
|
});
|
|
998
1024
|
}
|
|
999
1025
|
|
|
@@ -1017,12 +1043,10 @@ export default {
|
|
|
1017
1043
|
this.close();
|
|
1018
1044
|
removeClass(this.button, CLASS_FULLSCREEN_EXIT);
|
|
1019
1045
|
|
|
1020
|
-
|
|
1021
|
-
removeClass(list, CLASS_TRANSITION);
|
|
1046
|
+
removeClass(list, CLASS_TRANSITION);
|
|
1022
1047
|
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
}
|
|
1048
|
+
if (this.viewed) {
|
|
1049
|
+
removeClass(image, CLASS_TRANSITION);
|
|
1026
1050
|
}
|
|
1027
1051
|
|
|
1028
1052
|
if (options.focus) {
|
|
@@ -1043,14 +1067,7 @@ export default {
|
|
|
1043
1067
|
|
|
1044
1068
|
if (this.viewed) {
|
|
1045
1069
|
this.initImage(() => {
|
|
1046
|
-
this.renderImage(
|
|
1047
|
-
if (options.transition) {
|
|
1048
|
-
setTimeout(() => {
|
|
1049
|
-
addClass(image, CLASS_TRANSITION);
|
|
1050
|
-
addClass(list, CLASS_TRANSITION);
|
|
1051
|
-
}, 0);
|
|
1052
|
-
}
|
|
1053
|
-
});
|
|
1070
|
+
this.renderImage();
|
|
1054
1071
|
});
|
|
1055
1072
|
}
|
|
1056
1073
|
|
|
@@ -1068,7 +1085,7 @@ export default {
|
|
|
1068
1085
|
tooltipBox.textContent = `${Math.round(imageData.ratio * 100)}%`;
|
|
1069
1086
|
|
|
1070
1087
|
if (!this.tooltipping) {
|
|
1071
|
-
if (options
|
|
1088
|
+
if (isTransitionEnabled(options, 'tooltip')) {
|
|
1072
1089
|
if (this.fading) {
|
|
1073
1090
|
dispatchEvent(tooltipBox, EVENT_TRANSITION_END);
|
|
1074
1091
|
}
|
|
@@ -1090,7 +1107,7 @@ export default {
|
|
|
1090
1107
|
}
|
|
1091
1108
|
|
|
1092
1109
|
this.tooltipping = setTimeout(() => {
|
|
1093
|
-
if (options
|
|
1110
|
+
if (isTransitionEnabled(options, 'tooltip')) {
|
|
1094
1111
|
addListener(tooltipBox, EVENT_TRANSITION_END, () => {
|
|
1095
1112
|
removeClass(tooltipBox, CLASS_SHOW);
|
|
1096
1113
|
removeClass(tooltipBox, CLASS_FADE);
|
|
@@ -1139,10 +1156,18 @@ export default {
|
|
|
1139
1156
|
return this;
|
|
1140
1157
|
},
|
|
1141
1158
|
|
|
1142
|
-
|
|
1143
|
-
|
|
1159
|
+
/**
|
|
1160
|
+
* Update the viewer when images or options changed.
|
|
1161
|
+
* @param {Object} [updateOptions] - The options to update.
|
|
1162
|
+
* @returns {Viewer} this
|
|
1163
|
+
*/
|
|
1164
|
+
update(updateOptions) {
|
|
1144
1165
|
const { element, options, isImg } = this;
|
|
1145
1166
|
|
|
1167
|
+
if (isPlainObject(updateOptions)) {
|
|
1168
|
+
assign(options, updateOptions);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1146
1171
|
// Destroy viewer if the target image was deleted
|
|
1147
1172
|
if (isImg && !element.parentNode) {
|
|
1148
1173
|
return this.destroy();
|
|
@@ -1170,9 +1195,10 @@ export default {
|
|
|
1170
1195
|
if (this.ready) {
|
|
1171
1196
|
const changedIndexes = [];
|
|
1172
1197
|
|
|
1173
|
-
forEach(this.items, (item
|
|
1198
|
+
forEach(this.items, (item) => {
|
|
1174
1199
|
const img = item.querySelector('img');
|
|
1175
|
-
const
|
|
1200
|
+
const index = Number(getData(item, 'index'));
|
|
1201
|
+
const image = images[index];
|
|
1176
1202
|
|
|
1177
1203
|
if (image && img) {
|
|
1178
1204
|
if (
|
|
@@ -1181,10 +1207,10 @@ export default {
|
|
|
1181
1207
|
// Title changed (#408)
|
|
1182
1208
|
|| image.alt !== img.alt
|
|
1183
1209
|
) {
|
|
1184
|
-
changedIndexes.push(
|
|
1210
|
+
changedIndexes.push(index);
|
|
1185
1211
|
}
|
|
1186
1212
|
} else {
|
|
1187
|
-
changedIndexes.push(
|
|
1213
|
+
changedIndexes.push(index);
|
|
1188
1214
|
}
|
|
1189
1215
|
});
|
|
1190
1216
|
|
|
@@ -1203,7 +1229,7 @@ export default {
|
|
|
1203
1229
|
this.viewed = false;
|
|
1204
1230
|
this.view(Math.max(Math.min(this.index - changedIndex, this.length - 1), 0));
|
|
1205
1231
|
} else {
|
|
1206
|
-
const activeItem = this.
|
|
1232
|
+
const activeItem = this.getItem(this.index);
|
|
1207
1233
|
|
|
1208
1234
|
// Reactivate the current viewing item after reset the list.
|
|
1209
1235
|
addClass(activeItem, CLASS_ACTIVE);
|
|
@@ -1277,7 +1303,8 @@ export default {
|
|
|
1277
1303
|
}
|
|
1278
1304
|
|
|
1279
1305
|
if (!options.inline) {
|
|
1280
|
-
removeListener(element, EVENT_CLICK, this.
|
|
1306
|
+
removeListener(element, EVENT_CLICK, this.onElementClick);
|
|
1307
|
+
removeListener(element, EVENT_KEY_DOWN, this.onElementKeyDown);
|
|
1281
1308
|
}
|
|
1282
1309
|
|
|
1283
1310
|
element[NAMESPACE] = undefined;
|
package/src/js/others.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ACTION_MOVE,
|
|
3
|
+
ACTION_ROTATE,
|
|
3
4
|
ACTION_SWITCH,
|
|
5
|
+
ACTION_TRANSFORM,
|
|
4
6
|
ACTION_ZOOM,
|
|
5
7
|
CLASS_HIDE,
|
|
6
8
|
CLASS_OPEN,
|
|
@@ -13,6 +15,7 @@ import {
|
|
|
13
15
|
addListener,
|
|
14
16
|
dispatchEvent,
|
|
15
17
|
forEach,
|
|
18
|
+
getMaxRotateDegree,
|
|
16
19
|
getMaxZoomRatio,
|
|
17
20
|
isFunction,
|
|
18
21
|
isPlainObject,
|
|
@@ -117,6 +120,12 @@ export default {
|
|
|
117
120
|
|
|
118
121
|
hidden() {
|
|
119
122
|
const { element, options, viewer } = this;
|
|
123
|
+
const { activeElement } = viewer.ownerDocument;
|
|
124
|
+
|
|
125
|
+
// Avoid keeping focus inside the dialog before setting `aria-hidden`.
|
|
126
|
+
if (activeElement && viewer.contains(activeElement) && isFunction(activeElement.blur)) {
|
|
127
|
+
activeElement.blur();
|
|
128
|
+
}
|
|
120
129
|
|
|
121
130
|
if (options.focus) {
|
|
122
131
|
this.clearEnforceFocus();
|
|
@@ -150,7 +159,7 @@ export default {
|
|
|
150
159
|
},
|
|
151
160
|
|
|
152
161
|
requestFullscreen(options) {
|
|
153
|
-
const document = this
|
|
162
|
+
const { ownerDocument: document } = this;
|
|
154
163
|
|
|
155
164
|
if (this.fulled && !(
|
|
156
165
|
document.fullscreenElement
|
|
@@ -179,7 +188,7 @@ export default {
|
|
|
179
188
|
},
|
|
180
189
|
|
|
181
190
|
exitFullscreen() {
|
|
182
|
-
const document = this
|
|
191
|
+
const { ownerDocument: document } = this;
|
|
183
192
|
|
|
184
193
|
if (this.fulled && (
|
|
185
194
|
document.fullscreenElement
|
|
@@ -223,7 +232,43 @@ export default {
|
|
|
223
232
|
|
|
224
233
|
// Zoom the current image
|
|
225
234
|
case ACTION_ZOOM:
|
|
226
|
-
|
|
235
|
+
if (options.zoomable && options.zoomOnTouch) {
|
|
236
|
+
const zoomRatio = getMaxZoomRatio(pointers);
|
|
237
|
+
|
|
238
|
+
if (zoomRatio !== 0) {
|
|
239
|
+
this.zoom(zoomRatio, false, null, event);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
break;
|
|
243
|
+
|
|
244
|
+
// Rotate the current image
|
|
245
|
+
case ACTION_ROTATE:
|
|
246
|
+
if (options.rotatable && options.rotateOnTouch) {
|
|
247
|
+
const rotateDegree = getMaxRotateDegree(pointers);
|
|
248
|
+
|
|
249
|
+
if (rotateDegree !== 0) {
|
|
250
|
+
this.rotate(rotateDegree, event);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
break;
|
|
254
|
+
|
|
255
|
+
// Transform the current image
|
|
256
|
+
case ACTION_TRANSFORM:
|
|
257
|
+
if (options.zoomable && options.zoomOnTouch) {
|
|
258
|
+
const zoomRatio = getMaxZoomRatio(pointers);
|
|
259
|
+
|
|
260
|
+
if (zoomRatio !== 0) {
|
|
261
|
+
this.zoom(zoomRatio, false, null, event);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (options.rotatable && options.rotateOnTouch) {
|
|
266
|
+
const rotateDegree = getMaxRotateDegree(pointers);
|
|
267
|
+
|
|
268
|
+
if (rotateDegree !== 0) {
|
|
269
|
+
this.rotate(rotateDegree, event);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
227
272
|
break;
|
|
228
273
|
|
|
229
274
|
case ACTION_SWITCH: {
|
package/src/js/render.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
CLASS_ACTIVE,
|
|
2
3
|
CLASS_LOADING,
|
|
3
4
|
CLASS_TRANSITION,
|
|
4
5
|
EVENT_ERROR,
|
|
@@ -11,11 +12,15 @@ import {
|
|
|
11
12
|
addListener,
|
|
12
13
|
assign,
|
|
13
14
|
forEach,
|
|
15
|
+
getData,
|
|
14
16
|
getImageNameFromURL,
|
|
15
17
|
getImageNaturalSizes,
|
|
16
18
|
getTransforms,
|
|
17
19
|
hasClass,
|
|
20
|
+
inheritAttributes,
|
|
18
21
|
isNumber,
|
|
22
|
+
isPlainObject,
|
|
23
|
+
isTransitionEnabled,
|
|
19
24
|
removeClass,
|
|
20
25
|
removeListener,
|
|
21
26
|
setData,
|
|
@@ -31,7 +36,7 @@ export default {
|
|
|
31
36
|
},
|
|
32
37
|
|
|
33
38
|
initBody() {
|
|
34
|
-
const { ownerDocument } = this
|
|
39
|
+
const { ownerDocument } = this;
|
|
35
40
|
const body = ownerDocument.body || ownerDocument.documentElement;
|
|
36
41
|
|
|
37
42
|
this.body = body;
|
|
@@ -73,14 +78,41 @@ export default {
|
|
|
73
78
|
}
|
|
74
79
|
},
|
|
75
80
|
|
|
76
|
-
initList() {
|
|
81
|
+
initList(viewIndex = this.index) {
|
|
77
82
|
const { element, options, list } = this;
|
|
78
83
|
const items = [];
|
|
84
|
+
const navbarOptions = isPlainObject(options.navbar) ? options.navbar : {};
|
|
85
|
+
const probe = document.createElement('li');
|
|
86
|
+
|
|
87
|
+
list.appendChild(probe);
|
|
88
|
+
const itemWidth = probe.offsetWidth + parseInt(window.getComputedStyle(probe).marginLeft, 10);
|
|
89
|
+
|
|
90
|
+
list.removeChild(probe);
|
|
91
|
+
|
|
92
|
+
let visibleItemCount = isNumber(navbarOptions.visibleItemCount)
|
|
93
|
+
? Math.floor(navbarOptions.visibleItemCount)
|
|
94
|
+
: Math.floor(this.containerData.width / itemWidth);
|
|
95
|
+
|
|
96
|
+
visibleItemCount = Math.min(visibleItemCount, this.length);
|
|
97
|
+
|
|
98
|
+
const start = visibleItemCount > 0
|
|
99
|
+
? Math.min(
|
|
100
|
+
Math.max(0, viewIndex - Math.floor(visibleItemCount / 2)),
|
|
101
|
+
Math.max(0, this.length - visibleItemCount),
|
|
102
|
+
)
|
|
103
|
+
: 0;
|
|
104
|
+
const end = visibleItemCount > 0
|
|
105
|
+
? Math.min(this.length, start + visibleItemCount)
|
|
106
|
+
: this.length;
|
|
79
107
|
|
|
80
108
|
// initList may be called in this.update, so should keep idempotent
|
|
81
109
|
list.innerHTML = '';
|
|
82
110
|
|
|
83
111
|
forEach(this.images, (image, index) => {
|
|
112
|
+
if (visibleItemCount > 0 && (index < start || index >= end)) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
84
116
|
const { src } = image;
|
|
85
117
|
const alt = image.alt || getImageNameFromURL(src);
|
|
86
118
|
const url = this.getImageURL(image);
|
|
@@ -89,13 +121,7 @@ export default {
|
|
|
89
121
|
const item = document.createElement('li');
|
|
90
122
|
const img = document.createElement('img');
|
|
91
123
|
|
|
92
|
-
|
|
93
|
-
const value = image.getAttribute(name);
|
|
94
|
-
|
|
95
|
-
if (value !== null) {
|
|
96
|
-
img.setAttribute(name, value);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
124
|
+
inheritAttributes(img, image, options.inheritedAttributes);
|
|
99
125
|
|
|
100
126
|
if (options.navbar) {
|
|
101
127
|
img.src = src || url;
|
|
@@ -119,6 +145,15 @@ export default {
|
|
|
119
145
|
|
|
120
146
|
this.items = items;
|
|
121
147
|
|
|
148
|
+
if (this.viewed) {
|
|
149
|
+
const activeItem = this.getItem(this.index);
|
|
150
|
+
|
|
151
|
+
if (activeItem) {
|
|
152
|
+
addClass(activeItem, CLASS_ACTIVE);
|
|
153
|
+
activeItem.setAttribute('aria-selected', true);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
122
157
|
forEach(items, (item) => {
|
|
123
158
|
const image = item.firstElementChild;
|
|
124
159
|
let onLoad;
|
|
@@ -152,7 +187,7 @@ export default {
|
|
|
152
187
|
});
|
|
153
188
|
});
|
|
154
189
|
|
|
155
|
-
if (options
|
|
190
|
+
if (isTransitionEnabled(options, 'view')) {
|
|
156
191
|
addListener(element, EVENT_VIEWED, () => {
|
|
157
192
|
addClass(list, CLASS_TRANSITION);
|
|
158
193
|
}, {
|
|
@@ -161,9 +196,24 @@ export default {
|
|
|
161
196
|
}
|
|
162
197
|
},
|
|
163
198
|
|
|
199
|
+
getItem(index) {
|
|
200
|
+
let item;
|
|
201
|
+
|
|
202
|
+
forEach(this.items, (candidate) => {
|
|
203
|
+
if (Number(getData(candidate, 'index')) === index) {
|
|
204
|
+
item = candidate;
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return true;
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
return item;
|
|
212
|
+
},
|
|
213
|
+
|
|
164
214
|
renderList() {
|
|
165
215
|
const { index } = this;
|
|
166
|
-
const item = this.
|
|
216
|
+
const item = this.getItem(index);
|
|
167
217
|
|
|
168
218
|
if (!item) {
|
|
169
219
|
return;
|
|
@@ -176,9 +226,9 @@ export default {
|
|
|
176
226
|
|
|
177
227
|
// Place the active item in the center of the screen
|
|
178
228
|
setStyle(this.list, assign({
|
|
179
|
-
width: outerWidth * this.length - gutter,
|
|
229
|
+
width: outerWidth * this.items.length - gutter,
|
|
180
230
|
}, getTransforms({
|
|
181
|
-
translateX: ((this.viewerData.width - offsetWidth) / 2) -
|
|
231
|
+
translateX: ((this.viewerData.width - offsetWidth) / 2) - item.offsetLeft,
|
|
182
232
|
})));
|
|
183
233
|
},
|
|
184
234
|
|
|
@@ -277,9 +327,27 @@ export default {
|
|
|
277
327
|
marginTop: imageData.y,
|
|
278
328
|
}, getTransforms(imageData)));
|
|
279
329
|
|
|
330
|
+
if (this.magnifierPoint) {
|
|
331
|
+
this.renderMagnifier();
|
|
332
|
+
}
|
|
333
|
+
|
|
280
334
|
if (done) {
|
|
281
|
-
|
|
282
|
-
|
|
335
|
+
let action = false;
|
|
336
|
+
|
|
337
|
+
if (this.viewing) {
|
|
338
|
+
action = 'view';
|
|
339
|
+
} else if (this.moving) {
|
|
340
|
+
action = 'move';
|
|
341
|
+
} else if (this.rotating) {
|
|
342
|
+
action = 'rotate';
|
|
343
|
+
} else if (this.scaling) {
|
|
344
|
+
action = 'scale';
|
|
345
|
+
} else if (this.zooming) {
|
|
346
|
+
action = 'zoom';
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (action
|
|
350
|
+
&& isTransitionEnabled(this.options, action)
|
|
283
351
|
&& hasClass(image, CLASS_TRANSITION)) {
|
|
284
352
|
const onTransitionEnd = () => {
|
|
285
353
|
this.imageRendering = false;
|
package/src/js/template.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
export default (
|
|
2
2
|
'<div class="viewer-container" tabindex="-1" touch-action="none">'
|
|
3
3
|
+ '<div class="viewer-canvas"></div>'
|
|
4
|
+
+ '<div class="viewer-magnifier" aria-hidden="true">'
|
|
5
|
+
+ '<img class="viewer-magnifier-image" alt="">'
|
|
6
|
+
+ '</div>'
|
|
7
|
+
+ '<div class="viewer-navigation">'
|
|
8
|
+
+ '<div class="viewer-prev" data-viewer-action="prev" role="button" aria-label="Previous"></div>'
|
|
9
|
+
+ '<div class="viewer-next" data-viewer-action="next" role="button" aria-label="Next"></div>'
|
|
10
|
+
+ '</div>'
|
|
4
11
|
+ '<div class="viewer-footer">'
|
|
5
12
|
+ '<div class="viewer-title"></div>'
|
|
6
13
|
+ '<div class="viewer-toolbar"></div>'
|