Completed
Pull Request — master (#262)
by Robin
02:45
created

Controls.share   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 0
dl 0
loc 14
rs 9.4285
c 0
b 0
f 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 OC, SlideShow */
13
(function ($, SlideShow) {
14
	"use strict";
15
	/**
16
	 * Button and key controls for the slideshow
17
	 *
18
	 * @param {Object} slideshow
19
	 * @param {*} container
20
	 * @param {Object} zoomablePreview
21
	 * @param {number} interval
22
	 * @param {Array} features
23
	 * @constructor
24
	 */
25
	var Controls = function (slideshow, container, zoomablePreview, interval, features) {
26
		this.slideshow = slideshow;
27
		this.container = container;
28
		this.zoomablePreview = zoomablePreview;
29
		this.progressBar = container.find('.progress');
30
		this.interval = interval || 5000;
31
		if (features.indexOf('background_colour_toggle') > -1) {
32
			this.backgroundToggle = true;
33
		}
34
	};
35
36
	Controls.prototype = {
37
		current: 0,
38
		errorLoadingImage: false,
39
		playTimeout: 0,
40
		playing: false,
41
		active: false,
42
		backgroundToggle: false,
43
44
		/**
45
		 * Initialises the controls
46
		 */
47
		init: function () {
48
			var makeCallBack = function (handler) {
49
				return function (evt) {
50
					if (!this.active) {
51
						return;
52
					}
53
					evt.stopPropagation();
54
					evt.preventDefault();
55
					handler.call(this);
56
				}.bind(this);
57
			}.bind(this);
58
59
			this._buttonSetup(makeCallBack);
60
			this._specialButtonSetup(makeCallBack);
61
			this._keyCodeSetup(makeCallBack);
62
		},
63
64
		/**
65
		 * Updates the controls
66
		 *
67
		 * @param {{name:string, url: string, path: string, fallBack: string}[]} images
68
		 * @param {boolean} autoPlay
69
		 */
70
		update: function (images, autoPlay) {
71
			this.images = images;
72
			this.active = true;
73
			this.showButton('.play');
74
			this.hideButton('.pause, .progress');
75
			this.playing = false;
76
77
			// Hide prev/next and play buttons when we only have one pic
78
			this.container.find('.next, .previous, .play').toggle(this.images.length > 1);
79
80
			// Hide the action buttons until we have something to show
81
			this.hideActionButtons();
82
83
			if (autoPlay) {
84
				this._playPauseToggle();
85
			}
86
		},
87
88
		/**
89
		 * Initialises local variables when the show starts
90
		 *
91
		 * @param {number} currentImageId
92
		 */
93
		show: function (currentImageId) {
94
			var currentImage = this.images[currentImageId];
95
			this.current = currentImageId;
96
			this.errorLoadingImage = false;
97
			if (this.playing) {
98
				this._setTimeout();
99
			}
100
			this._setName(currentImage.name);
101
		},
102
103
		/**
104
		 * Stops and hides the slideshow
105
		 */
106
		stop: function () {
107
			this._setName('');
108
			this.playing = false;
109
			this.slideshow.stop();
110
			this.zoomablePreview.stop();
111
112
			this._clearTimeout();
113
			this.container.hide();
114
			this.active = false;
115
		},
116
117
		/**
118
		 * Updates the private variables in case of problems loading an image
119
		 *
120
		 * @param {Array} images
121
		 * @param {boolean} errorLoadingImage
122
		 */
123
		updateControls: function (images, errorLoadingImage) {
124
			this.images = images;
125
			this.errorLoadingImage = errorLoadingImage;
126
		},
127
128
		/**
129
		 * Shows the action buttons
130
		 *
131
		 * @param {boolean} transparent
132
		 * @param {boolean} isPublic
133
		 * @param {number} permissions
134
		 */
135
		showActionButtons: function (transparent, isPublic, permissions) {
136
			if (transparent) {
137
				this._showBackgroundToggle();
138
			}
139
			this.showButton('.downloadImage');
140
			var canDelete = ((permissions & OC.PERMISSION_DELETE) !== 0);
141
			var canShare = ((permissions & OC.PERMISSION_SHARE) !== 0);
142
			if (!isPublic && canDelete) {
143
				this.showButton('.deleteImage');
144
			}
145
			if (!isPublic && canShare) {
146
				this.showButton('#slideshow-shared-button');
147
			}
148
		},
149
150
		/**
151
		 * Hides the action buttons
152
		 */
153
		hideActionButtons: function () {
154
			this.hideButton('.changeBackground');
155
			this.hideButton('.downloadImage');
156
			this.hideButton('.deleteImage');
157
			this.hideButton('#slideshow-shared-button');
158
		},
159
160
		/**
161
		 * Shows a button which has been hidden
162
		 */
163
		showButton: function (button) {
164
			this.container.find(button).removeClass('hidden');
165
		},
166
167
		/**
168
		 * Hides a button
169
		 *
170
		 * @param button
171
		 */
172
		hideButton: function (button) {
173
			this.container.find(button).addClass('hidden');
174
		},
175
176
		/**
177
		 * Removes a button
178
		 *
179
		 * @param button
180
		 */
181
		removeButton: function (button) {
182
			this.container.find(button).remove();
183
		},
184
185
		/**
186
		 * Sets up the button based navigation
187
		 *
188
		 * @param {Function} makeCallBack
189
		 * @private
190
		 */
191
		_buttonSetup: function (makeCallBack) {
192
			this.container.children('.next').click(makeCallBack(this._next));
193
			this.container.children('.previous').click(makeCallBack(this._previous));
194
			this.container.children('.exit').click(makeCallBack(this._exit));
195
			this.container.children('.pause, .play').click(makeCallBack(this._playPauseToggle));
196
			this.progressBar.click(makeCallBack(this._playPauseToggle));
197
			this.container.children('.previous, .next, .slideshow-menu, .name').on(
198
				'mousewheel DOMMouseScroll mousemove', function (evn) {
199
					this.container.children('.bigshotContainer')[0].dispatchEvent(
200
						new WheelEvent(evn.originalEvent.type, evn.originalEvent));
0 ignored issues
show
Bug introduced by
The variable WheelEvent seems to be never declared. If this is a global, consider adding a /** global: WheelEvent */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
WheelEvent does not seem to be defined.
Loading history...
201
				}.bind(this));
202
		},
203
204
		/**
205
		 * Sets up additional buttons
206
		 *
207
		 * @param {Function} makeCallBack
208
		 * @private
209
		 */
210
		_specialButtonSetup: function (makeCallBack) {
211
			this.container.find('.downloadImage').click(makeCallBack(this._getImageDownload));
212
			this.container.find('.deleteImage').click(makeCallBack(this._deleteImage));
213
			this.container.find('#slideshow-shared-button').click(makeCallBack(this.share));
214
			this.container.find('.slideshow-menu').width = 52;
215
			if (this.backgroundToggle) {
216
				this.container.find('.changeBackground').click(
217
					makeCallBack(this._toggleBackground));
218
				this.container.find('.slideshow-menu').width += 52;
219
			} else {
220
				this.hideButton('.changeBackground');
221
			}
222
		},
223
224
		/**
225
		 * Populates the share dialog with the needed information
226
		 */
227
		share: function () {
228
			var image = this.images[this.current];
229
			if (!Gallery.Share.droppedDown) {
0 ignored issues
show
Bug introduced by
The variable Gallery seems to be never declared. If this is a global, consider adding a /** global: Gallery */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
Gallery does not seem to be defined.
Loading history...
230
231
				$('.slideshow-menu a.share').data('path', image.path)
232
					.data('link', true)
233
					.data('item-source', image.file)
234
					.data('possible-permissions', image.permissions)
235
					.click();
236
				if (!$('#linkCheckbox').is(':checked')) {
237
					$('#linkText').hide();
238
				}
239
			}
240
		},
241
242
		/**
243
		 * Shows the background colour switcher, if activated in the configuration
244
		 */
245
		_showBackgroundToggle: function () {
246
			if (this.backgroundToggle) {
247
				this.showButton('.changeBackground');
248
			}
249
		},
250
251
		/**
252
		 * Sets up the key based controls
253
		 *
254
		 * @param {Function} makeCallBack
255
		 * @private
256
		 */
257
		_keyCodeSetup: function (makeCallBack) {
258
			$(document).keyup(function (evt) {
259
				var escKey = 27;
260
				var leftKey = 37;
261
				var rightKey = 39;
262
				var spaceKey = 32;
263
				var fKey = 70;
264
				var zoomOutKeys = [48, 96, 79, 40]; // zeros, o or down key
265
				var zoomInKeys = [57, 105, 73, 38]; // 9, i or up key
266
				if (evt.keyCode === escKey) {
267
					makeCallBack(this._exit)(evt);
268
				} else if (evt.keyCode === leftKey) {
269
					makeCallBack(this._previous)(evt);
270
				} else if (evt.keyCode === rightKey) {
271
					makeCallBack(this._next)(evt);
272
				} else if (evt.keyCode === spaceKey) {
273
					makeCallBack(this._playPauseToggle)(evt);
274
				} else if (evt.keyCode === fKey) {
275
					makeCallBack(this._fullScreenToggle)(evt);
276
				} else if (this._hasKeyBeenPressed(evt, zoomOutKeys)) {
277
					makeCallBack(this._zoomToOriginal)(evt);
278
				} else if (this._hasKeyBeenPressed(evt, zoomInKeys)) {
279
					makeCallBack(this._zoomToFit)(evt);
280
				}
281
			}.bind(this));
282
		},
283
284
		/**
285
		 * Determines if a key has been pressed by comparing the event and the key
286
		 *
287
		 * @param evt
288
		 * @param {Array} keys
289
		 *
290
		 * @returns {boolean}
291
		 * @private
292
		 */
293
		_hasKeyBeenPressed: function (evt, keys) {
294
			var i, keysLength = keys.length;
295
			for (i = 0; i < keysLength; i++) {
296
				if (evt.keyCode === keys[i]) {
297
					return true;
298
				}
299
			}
300
			return false;
301
		},
302
303
		/**
304
		 * Starts the slideshow timer
305
		 *
306
		 * @private
307
		 */
308
		_setTimeout: function () {
309
			this._clearTimeout();
310
			this.playTimeout = setTimeout(this._next.bind(this), this.interval);
311
			this.progressBar.stop();
312
			this.progressBar.css('height', '6px');
313
			this.progressBar.animate({'height': '26px'}, this.interval, 'linear');
314
		},
315
316
		/**
317
		 * Stops the slideshow timer
318
		 *
319
		 * @private
320
		 */
321
		_clearTimeout: function () {
322
			if (this.playTimeout) {
323
				clearTimeout(this.playTimeout);
324
			}
325
			this.progressBar.stop();
326
			this.progressBar.css('height', '6px');
327
			this.playTimeout = 0;
328
		},
329
330
		/**
331
		 * Starts/stops autoplay and shows/hides the play/pause buttons
332
		 *
333
		 * @private
334
		 */
335
		_playPauseToggle: function () {
336
			if (this.playing === true) {
337
				this.playing = false;
338
				this._clearTimeout();
339
			} else {
340
				this.playing = true;
341
				this._setTimeout();
342
			}
343
344
			this.container.find('.play, .pause, .progress').toggleClass('hidden');
345
		},
346
347
		/**
348
		 * Shows the next slide
349
		 *
350
		 * @private
351
		 */
352
		_next: function () {
353
			Gallery.Share.hideDropDown();
0 ignored issues
show
Bug introduced by
The variable Gallery seems to be never declared. If this is a global, consider adding a /** global: Gallery */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
Gallery does not seem to be defined.
Loading history...
354
			this._setName('');
355
			this.slideshow.hideErrorNotification();
356
			this.zoomablePreview.reset();
357
358
			if (this.errorLoadingImage) {
359
				this.current -= 1;
360
			}
361
			this.current = (this.current + 1) % this.images.length;
362
			var next = (this.current + 1) % this.images.length;
363
			this._updateSlideshow(next);
364
		},
365
366
		/**
367
		 * Shows the previous slide
368
		 *
369
		 * @private
370
		 */
371
		_previous: function () {
372
			Gallery.Share.hideDropDown();
0 ignored issues
show
Bug introduced by
The variable Gallery seems to be never declared. If this is a global, consider adding a /** global: Gallery */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
Gallery does not seem to be defined.
Loading history...
373
			this._setName('');
374
			this.slideshow.hideErrorNotification();
375
			this.zoomablePreview.reset();
376
377
			this.current = (this.current - 1 + this.images.length) % this.images.length;
378
			var previous = (this.current - 1 + this.images.length) % this.images.length;
379
			this._updateSlideshow(previous);
380
		},
381
382
		/**
383
		 * Asks the slideshow for the next image
384
		 *
385
		 * @param {number} imageId
386
		 * @private
387
		 */
388
		_updateSlideshow: function (imageId) {
389
			this.slideshow.next(this.current, this.images[imageId]);
390
		},
391
392
		/**
393
		 * Exits the slideshow by going back in history
394
		 *
395
		 * @private
396
		 */
397
		_exit: function () {
398
399
			// Only modern browsers can manipulate history
400
			if (history && history.replaceState) {
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable history is declared in the current environment, consider using typeof history === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
401
				// We simulate a click on the back button in order to be consistent
402
				window.history.back();
403
			} else {
404
				// For ancient browsers supported in core
405
				this.stop();
406
			}
407
		},
408
409
		/**
410
		 * Launches fullscreen mode if the browser supports it
411
		 *
412
		 * @private
413
		 */
414
		_fullScreenToggle: function () {
415
			this.zoomablePreview.fullScreenToggle();
416
		},
417
418
		/**
419
		 * Resizes the image to its original size
420
		 *
421
		 * @private
422
		 */
423
		_zoomToOriginal: function () {
424
			this.zoomablePreview.zoomToOriginal();
425
		},
426
427
		/**
428
		 * Fits the image in the browser window
429
		 *
430
		 * @private
431
		 */
432
		_zoomToFit: function () {
433
			this.zoomablePreview.zoomToFit();
434
		},
435
436
		/**
437
		 * Sends the current image as a download
438
		 *
439
		 * @returns {boolean}
440
		 * @private
441
		 */
442
		_getImageDownload: function () {
443
			var downloadUrl = this.images[this.current].downloadUrl;
444
445
			return this.slideshow.getImageDownload(downloadUrl);
446
		},
447
448
		/**
449
		 * Changes the colour of the background of the image
450
		 *
451
		 * @private
452
		 */
453
		_toggleBackground: function () {
454
			this.slideshow.toggleBackground();
455
		},
456
457
		/**
458
		 * Shows the filename of the current image
459
		 * @param {string} imageName
460
		 * @private
461
		 */
462
		_setName: function (imageName) {
463
			var nameElement = this.container.find('.title');
464
			nameElement.text(imageName);
465
		},
466
467
		/**
468
		 * Delete the image from the slideshow
469
		 * @private
470
		 */
471
		_deleteImage: function () {
472
			var image = this.images[this.current];
473
			var self = this;
474
			$.ajax({
475
				type: 'DELETE',
476
				url: OC.getRootPath() + '/remote.php/webdav/' + image.path,
477
				success: function () {
478
					self.slideshow.deleteImage(image, self.current);
479
					self.images.splice(self.current, 1);
480
					if (self.images.length === 0) {
481
						self._exit();
482
					}
483
					else {
484
						self.current = self.current % self.images.length;
485
						self._updateSlideshow(self.current);
486
					}
487
				}
488
			});
489
		}
490
	};
491
492
	SlideShow.Controls = Controls;
493
})(jQuery, SlideShow);
494