js/slideshowzoomablepreview.js   A
last analyzed

Complexity

Total Complexity 38
Complexity/F 2

Size

Lines of Code 256
Function Count 19

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 136
dl 0
loc 256
rs 9.36
c 0
b 0
f 0
wmc 38
mnd 19
bc 19
fnc 19
bpm 1
cpm 2
noi 0
1
/**
2
 * Nextcloud - Gallery
3
 *
4
 *
5
 * This file is licensed under the Affero General Public License version 3 or
6
 * later. See the COPYING file.
7
 *
8
 * @author Olivier Paroz <[email protected]>
9
 *
10
 * @copyright Olivier Paroz 2017
11
 */
12
/* global SlideShow, bigshot*/
13
(function ($, SlideShow, bigshot) {
14
	"use strict";
15
	/**
16
	 * Creates a zoomable preview
17
	 *
18
	 * @param {*} container
19
	 * @constructor
20
	 */
21
	var ZoomablePreview = function (container) {
22
		this.container = container;
23
		this.element = this.container.get(0);
24
		var bigshotContainer = container.find('.bigshotContainer');
25
		this.bigshotElement = bigshotContainer.get(0);
26
27
		this._detectFullscreen();
28
		this._setupControls();
29
30
		$(window).resize(function () {
31
			this._zoomDecider();
32
		}.bind(this));
33
	};
34
35
	ZoomablePreview.prototype = {
36
		container: null,
37
		element: null,
38
		bigshotContainer: null,
39
		bigshotElement: null,
40
		zoomable: null,
41
		fullScreen: null,
42
		canFullScreen: false,
43
		currentImage: null,
44
		mimeType: null,
45
		maxZoom: 3,
46
		smallImageDimension: 200 / window.devicePixelRatio,
47
		smallImageScale: 2,
48
49
		/**
50
		 * Launches the Bigshot zoomable preview
51
		 *
52
		 * @param {*} image
53
		 * @param {number} currentImage
54
		 * @param {string} mimeType
55
		 */
56
		startBigshot: function (image, currentImage, mimeType) {
57
			this.currentImage = currentImage;
58
			this.mimeType = mimeType;
59
			if (this.zoomable !== null) {
60
				this.zoomable.dispose();
61
				this.zoomable = null;
62
			}
63
			var maxZoom = this.maxZoom;
64
			var imgWidth = image.naturalWidth / window.devicePixelRatio;
65
			var imgHeight = image.naturalHeight / window.devicePixelRatio;
66
			// Set arbitrary image dimension when we have a SVG
67
			if (imgWidth === 0 && mimeType === 'image/svg+xml') {
68
				imgWidth = 2048;
69
				imgHeight = 2048;
70
			}
71
72
			if (imgWidth < this.smallImageDimension &&
73
				imgHeight < this.smallImageDimension &&
74
				this.mimeType !== 'image/svg+xml') {
75
				maxZoom += 3;
76
				this.currentImage.isSmallImage = true;
77
			}
78
			this.zoomable = new bigshot.SimpleImage(new bigshot.ImageParameters({
79
				container: this.bigshotElement,
80
				maxZoom: maxZoom,
81
				minZoom: 0,
82
				touchUI: false,
83
				width: imgWidth,
84
				height: imgHeight
85
			}), image);
86
87
			// Reset our zoom based on image and window dimensions.
88
			this._resetZoom();
89
90
			// prevent zoom-on-doubleClick
91
			this.zoomable.addEventListener('dblclick', function (ie) {
92
				ie.preventDefault();
93
			});
94
			// Reset image position and size on orientation change
95
			var self = this;
96
			$(window).bind('orientationchange resize', function () {
97
				self._resetZoom();
98
			});
99
		},
100
101
		/**
102
		 * Resets the element for the next image to be displayed
103
		 */
104
		reset: function () {
105
			if (this.zoomable !== null) {
106
				this.zoomable.stopFlying();
107
				this._resetZoom();
108
			}
109
		},
110
111
		/**
112
		 * Throws away the zoomable preview
113
		 */
114
		stop: function () {
115
			if (this.fullScreen !== null) {
116
				this._fullScreenExit();
117
			}
118
			if (this.zoomable !== null) {
119
				this.zoomable.dispose();
120
				this.zoomable = null;
121
			}
122
		},
123
124
		/**
125
		 * Launches fullscreen mode if the browser supports it
126
		 */
127
		fullScreenToggle: function () {
128
			if (this.zoomable === null) {
129
				return;
130
			}
131
			if (this.fullScreen !== null) {
132
				this._fullScreenExit();
133
			} else {
134
				this._fullScreenStart();
135
			}
136
		},
137
138
		/**
139
		 * Resizes the image to its original size
140
		 */
141
		zoomToOriginal: function () {
142
			if (this.zoomable === null) {
143
				return;
144
			}
145
			if (this.currentImage.isSmallImage) {
146
				this.zoomable.flyTo(0, 0, this.smallImageScale, true);
147
			} else if ($(window).width() < this.zoomable.width ||
148
				$(window).height() < this.zoomable.height) {
149
				// The image is larger than the window.
150
				// Set minimum zoom and call flyZoomToFit.
151
				this.zoomable.setMinZoom(this.zoomable.getZoomToFitValue());
152
				this.zoomable.flyZoomToFit();
153
			} else {
154
				this.zoomable.setMinZoom(0);
155
				this.zoomable.flyTo(0, 0, 0, true);
156
			}
157
		},
158
159
		/**
160
		 * Fits the image in the browser window
161
		 */
162
		zoomToFit: function () {
163
			if (this.zoomable !== null) {
164
				this.zoomable.flyZoomToFit();
165
			}
166
		},
167
168
		/**
169
		 * Detect fullscreen capability
170
		 * @private
171
		 */
172
		_detectFullscreen: function () {
173
			this.canFullScreen = this.element.requestFullscreen !== undefined ||
174
				this.element.mozRequestFullScreen !== undefined ||
175
				this.element.webkitRequestFullscreen !== undefined ||
176
				this.element.msRequestFullscreen !== undefined;
177
		},
178
179
		/**
180
		 * Makes UI controls work on touchscreens. Pinch only works on iOS
181
		 * @private
182
		 */
183
		_setupControls: function () {
184
			var browser = new bigshot.Browser();
185
			this.container.children('input').each(function (i, e) {
186
				browser.registerListener(e, 'click', browser.stopEventBubblingHandler(), false);
187
				browser.registerListener(e, 'touchstart', browser.stopEventBubblingHandler(),
188
					false);
189
				browser.registerListener(e, 'touchend', browser.stopEventBubblingHandler(), false);
190
			});
191
		},
192
193
		/**
194
		 * Determines whether the image should be shown at its original size or if it should fill
195
		 * the screen
196
		 *
197
		 * @private
198
		 */
199
		_zoomDecider: function () {
200
			if (this.zoomable !== null) {
201
				if (this.fullScreen === null && this.mimeType !== 'image/svg+xml') {
202
					this.zoomToOriginal();
203
				} else {
204
					this.zoomToFit();
205
				}
206
			}
207
		},
208
209
		/**
210
		 * Resets the image to its original zoomed size
211
		 *
212
		 * @private
213
		 */
214
		_resetZoom: function () {
215
			if (this.zoomable === null) {
216
				return;
217
			}
218
			if (this.currentImage.isSmallImage) {
219
				this.zoomable.setZoom(this.smallImageScale, true);
220
			} else if ($(window).width() < this.zoomable.width ||
221
				$(window).height() < this.zoomable.height ||
222
				this.fullScreen !== null ||
223
				this.mimeType === 'image/svg+xml') {
224
				// The image is larger than the window, or we are fullScreen,
225
				// or this is an SVG. Set minimum zoom and call zoomToFit.
226
				this.zoomable.setMinZoom(this.zoomable.getZoomToFitValue());
227
				this.zoomable.zoomToFit();
228
			} else {
229
				// Zoom to the image size.
230
				this.zoomable.setMinZoom(0);
231
				this.zoomable.setZoom(0, true);
232
			}
233
		},
234
235
		/**
236
		 * Starts the fullscreen previews
237
		 *
238
		 * @private
239
		 */
240
		_fullScreenStart: function () {
241
			if (!this.canFullScreen) {
242
				return;
243
			}
244
			this.fullScreen = new bigshot.FullScreen(this.element);
245
			this.fullScreen.open();
246
			this.fullScreen.addOnClose(function () {
247
				this._fullScreenExit();
248
			}.bind(this));
249
		},
250
251
		/**
252
		 * Stops the fullscreen previews
253
		 *
254
		 * @private
255
		 */
256
		_fullScreenExit: function () {
257
			if (this.fullScreen === null) {
258
				return;
259
			}
260
			this.fullScreen.close();
261
			this.fullScreen = null;
262
			this._zoomDecider();
263
264
		}
265
	};
266
267
	SlideShow.ZoomablePreview = ZoomablePreview;
268
})(jQuery, SlideShow, bigshot);
269