Completed
Push — master ( 361a99...45dc31 )
by Olivier
10:25
created

SlideShow.deleteImage   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
c 0
b 0
f 0
nc 2
nop 2
dl 0
loc 10
rs 9.4285
1
/* global DOMPurify */
2
(function ($, OC, OCA, t) {
3
	"use strict";
4
	/**
5
	 * Slideshow featuring zooming
6
	 *
7
	 * @constructor
8
	 */
9
	var SlideShow = function () {
10
	};
11
12
	SlideShow.prototype = {
13
		slideshowTemplate: null,
14
		container: null,
15
		zoomablePreviewContainer: null,
16
		controls: null,
17
		imageCache: {},
18
		/** {Image} */
19
		currentImage: null,
20
		errorLoadingImage: false,
21
		onStop: null,
22
		zoomablePreview: null,
23
		active: false,
24
		backgroundToggle: false,
25
26
		/**
27
		 * Initialises the slideshow
28
		 *
29
		 * @param {boolean} autoPlay
30
		 * @param {number} interval
31
		 * @param {Array} features
32
		 */
33
		init: function (autoPlay, interval, features) {
34
			if (features.indexOf('background_colour_toggle') > -1) {
35
				this.backgroundToggle = true;
36
			}
37
38
			return $.when(this._getSlideshowTemplate()).then(function ($tmpl) {
39
				// Move the slideshow outside the content so we can hide the content
40
				$('body').append($tmpl);
41
				this.container = $('#slideshow');
42
				this.zoomablePreviewContainer = this.container.find('.bigshotContainer');
43
				this.zoomablePreview = new SlideShow.ZoomablePreview(this.container);
44
				this.controls =
45
					new SlideShow.Controls(
46
						this,
47
						this.container,
48
						this.zoomablePreview,
49
						interval,
50
						features);
51
				this.controls.init();
52
53
				this._initControlsAutoFader();
54
55
				// Replace all Owncloud svg images with png images for ancient browsers
56
				if (!OC.Util.hasSVGSupport()) {
57
					OC.Util.replaceSVG(this.$el);
58
				}
59
60
				// Only modern browsers can manipulate history
61
				if (history && history.pushState) {
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...
62
					// Stop the slideshow when backing out.
63
					$(window).bind('popstate.slideshow', function () {
64
						if (this.active === true) {
65
							this.active = false;
66
							this.controls.stop();
67
						}
68
					}.bind(this));
69
				}
70
			}.bind(this)).fail(function () {
71
				OC.Notification.show(t('core', 'Error loading slideshow template'));
72
			});
73
		},
74
75
		/**
76
		 * Refreshes the slideshow's data
77
		 *
78
		 * @param {{name:string, url: string, path: string, fallBack: string}[]} images
79
		 * @param {boolean} autoPlay
80
		 */
81
		setImages: function (images, autoPlay) {
82
			this._hideImage();
83
			this.images = images;
84
			this.controls.update(images, autoPlay);
85
		},
86
87
		/**
88
		 * Launches the slideshow
89
		 *
90
		 * @param {number} index
91
		 *
92
		 * @returns {*}
93
		 */
94
		show: function (index) {
95
			this.hideErrorNotification();
96
			this.active = true;
97
			this.container.show();
98
			this.container.css('background-position', 'center');
99
			this._hideImage();
100
			var currentImageId = index;
101
			return this.loadImage(this.images[index]).then(function (img) {
102
				this.container.css('background-position', '-10000px 0');
103
104
				// check if we moved along while we were loading
105
				if (currentImageId === index) {
106
					var image = this.images[index];
107
					var transparent = this._isTransparent(image.mimeType);
108
					this.controls.showActionButtons(transparent, Gallery.token, image.permissions);
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...
109
					this.errorLoadingImage = false;
110
					this.currentImage = img;
111
112
					var backgroundColour = '#000';
113
					if (transparent) {
114
						backgroundColour = '#fff';
115
					}
116
					img.setAttribute('alt', image.name);
117
					$(img).css('position', 'absolute');
118
					$(img).css('background-color', backgroundColour);
119
					if (transparent && this.backgroundToggle === true) {
120
						var $border = 30 / window.devicePixelRatio;
121
						$(img).css('outline', $border + 'px solid ' + backgroundColour);
122
					}
123
124
					this.zoomablePreview.startBigshot(img, this.currentImage, image.mimeType);
125
126
					this._setUrl(image.path);
127
					this.controls.show(currentImageId);
128
				}
129
			}.bind(this), function () {
130
				// Don't do anything if the user has moved along while we were loading as it would
131
				// mess up the index
132
				if (currentImageId === index) {
133
					this.errorLoadingImage = true;
134
					this.showErrorNotification(null);
135
					this._setUrl(this.images[index].path);
136
					this.images.splice(index, 1);
137
					this.controls.updateControls(this.images, this.errorLoadingImage);
138
				}
139
			}.bind(this));
140
		},
141
142
		/**
143
		 * Loads the image to show in the slideshow and preloads the next one
144
		 *
145
		 * @param {Object} preview
146
		 *
147
		 * @returns {*}
148
		 */
149
		loadImage: function (preview) {
150
			var url = preview.url;
151
			var mimeType = preview.mimeType;
152
153
			if (!this.imageCache[url]) {
154
				this.imageCache[url] = new $.Deferred();
155
				var image = new Image();
0 ignored issues
show
Bug introduced by
The variable Image seems to be never declared. If this is a global, consider adding a /** global: Image */ 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...
156
157
				image.onload = function () {
158
					if (this.imageCache[url]) {
159
						this.imageCache[url].resolve(image);
160
					}
161
				}.bind(this);
162
				image.onerror = function () {
163
					if (this.imageCache[url]) {
164
						this.imageCache[url].reject(url);
165
					}
166
				}.bind(this);
167
				if (mimeType === 'image/svg+xml') {
168
					image.src = this._getSVG(url);
169
				} else {
170
					image.src = url;
171
				}
172
			}
173
			return this.imageCache[url];
174
		},
175
176
		/**
177
		 * Shows a new image in the slideshow and preloads the next in the list
178
		 *
179
		 * @param {number} current
180
		 * @param {Object} next
181
		 */
182
		next: function (current, next) {
183
			this.show(current).then(function () {
184
				// Preloads the next image in the list
185
				this.loadImage(next);
186
			}.bind(this));
187
		},
188
189
		/**
190
		 * Stops the slideshow
191
		 */
192
		stop: function () {
193
			this.active = false;
194
			this.images = null;
195
			this._hideImage();
196
			if (this.onStop) {
197
				this.onStop();
198
			}
199
		},
200
201
		/**
202
		 * Sends the current image as a download
203
		 *
204
		 * @param {string} downloadUrl
205
		 *
206
		 * @returns {boolean}
207
		 */
208
		getImageDownload: function (downloadUrl) {
209
			OC.redirect(downloadUrl);
210
			return false;
211
		},
212
213
		/**
214
		 * Changes the colour of the background of the image
215
		 */
216
		toggleBackground: function () {
217
			var toHex = function (x) {
218
				return ("0" + parseInt(x).toString(16)).slice(-2);
219
			};
220
			var container = this.zoomablePreviewContainer.children('img');
221
			var rgb = container.css('background-color').match(/\d+/g);
222
			var hex = "#" + toHex(rgb[0]) + toHex(rgb[1]) + toHex(rgb[2]);
223
			var $border = 30 / window.devicePixelRatio;
224
225
			// Grey #363636
226
			if (hex === "#000000") {
227
				container.css('background-color', '#FFF');
228
				if (this.backgroundToggle === true) {
229
					container.css('outline', $border + 'px solid #FFF');
230
				}
231
			} else {
232
				container.css('background-color', '#000');
233
				if (this.backgroundToggle === true) {
234
					container.css('outline', $border + 'px solid #000');
235
				}
236
			}
237
		},
238
239
		/**
240
		 * Shows an error notification
241
		 *
242
		 * @param {string} message
243
		 */
244
		showErrorNotification: function (message) {
245
			if ($.isEmptyObject(message)) {
246
				message = t('gallery',
247
					'<strong>Error!</strong> Could not generate a preview of this file.<br>' +
248
					'Please go to the next slide while we remove this image from the slideshow');
249
			}
250
			this.container.find('.notification').html(message);
251
			this.container.find('.notification').show();
252
			this.controls.hideButton('.changeBackground');
253
		},
254
255
		/**
256
		 * Hides the error notification
257
		 */
258
		hideErrorNotification: function () {
259
			this.container.find('.notification').hide();
260
			this.container.find('.notification').html('');
261
		},
262
263
		/**
264
		 * Removes a specific button from the interface
265
		 *
266
		 * @param button
267
		 */
268
		removeButton: function (button) {
269
			this.controls.removeButton(button);
270
		},
271
272
		/**
273
		 * Deletes an image from the slideshow
274
		 *
275
		 * @param {object} image
276
		 * @param {number} currentIndex
277
		 */
278
		deleteImage: function (image, currentIndex) {
279
			// These are Gallery specific commands to be replaced
280
			// which should sit somewhere else
281
			if (!window.galleryFileAction) {
282
				delete Gallery.imageMap[image.path];
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...
283
				delete Thumbnails.map[image.file];
0 ignored issues
show
Bug introduced by
The variable Thumbnails seems to be never declared. If this is a global, consider adding a /** global: Thumbnails */ 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
Thumbnails does not seem to be defined.
Loading history...
284
				Gallery.albumMap[Gallery.currentAlbum].images.splice(currentIndex, 1);
0 ignored issues
show
Bug introduced by
Gallery does not seem to be defined.
Loading history...
285
				Gallery.view.init(Gallery.currentAlbum);
0 ignored issues
show
Bug introduced by
Gallery does not seem to be defined.
Loading history...
286
			}
287
		},
288
289
		/**
290
		 * Automatically fades the controls after 3 seconds
291
		 *
292
		 * @private
293
		 */
294
		_initControlsAutoFader: function () {
295
			var inactiveCallback = function () {
296
				this.container.addClass('inactive');
297
			}.bind(this);
298
			var inactiveTimeout = setTimeout(inactiveCallback, 3000);
299
300
			this.container.on('mousemove touchstart', function () {
301
				this.container.removeClass('inactive');
302
				clearTimeout(inactiveTimeout);
303
				inactiveTimeout = setTimeout(inactiveCallback, 3000);
304
			}.bind(this));
305
		},
306
307
		/**
308
		 * Simplest way to detect if image is transparent.
309
		 *
310
		 * That's very inaccurate since it doesn't include images which support transparency
311
		 *
312
		 * @param mimeType
313
		 * @returns {boolean}
314
		 * @private
315
		 */
316
		_isTransparent: function (mimeType) {
317
			return !(mimeType === 'image/jpeg'
318
				|| mimeType === 'image/x-dcraw'
319
				|| mimeType === 'application/font-sfnt'
320
				|| mimeType === 'application/x-font'
321
			);
322
		},
323
324
		/**
325
		 * Changes the browser Url, based on the current image
326
		 *
327
		 * @param {string} path
328
		 * @private
329
		 */
330
		_setUrl: function (path) {
331
			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...
332
				history.replaceState('', '', '#' + encodeURI(path));
333
			}
334
		},
335
336
		/**
337
		 * Hides the current image (before loading the next)
338
		 *
339
		 * @private
340
		 */
341
		_hideImage: function () {
342
			this.zoomablePreviewContainer.empty();
343
			this.controls.hideActionButtons();
344
		},
345
346
		/**
347
		 * Retrieves an SVG
348
		 *
349
		 * An SVG can't be simply attached to a src attribute like a bitmap image
350
		 *
351
		 * @param {string} source
352
		 *
353
		 * @returns {*}
354
		 * @private
355
		 */
356
		_getSVG: function (source) {
357
			var svgPreview = null;
358
			// DOMPurify only works with IE10+ and we load SVGs in the IMG tag
359
			if (window.btoa &&
360
				document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image",
361
					"1.1")) {
362
				var xmlHttp = new XMLHttpRequest();
0 ignored issues
show
Bug introduced by
The variable XMLHttpRequest seems to be never declared. If this is a global, consider adding a /** global: XMLHttpRequest */ 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...
363
				xmlHttp.open("GET", source, false);
364
				xmlHttp.send(null);
365
				if (xmlHttp.status === 200) {
366
					var pureSvg = DOMPurify.sanitize(xmlHttp.responseText, {ADD_TAGS: ['filter']});
367
					// Remove XML comment garbage left in the purified data
368
					var badTag = pureSvg.indexOf(']&gt;');
369
					var fixedPureSvg = pureSvg.substring(badTag < 0 ? 0 : 5, pureSvg.length);
370
					svgPreview = "data:image/svg+xml;base64," + window.btoa(fixedPureSvg);
371
				}
372
			}
373
374
			return svgPreview;
375
		},
376
377
		/**
378
		 * Retrieves the slideshow's template
379
		 *
380
		 * @returns {*}
381
		 * @private
382
		 */
383
		_getSlideshowTemplate: function () {
384
			var defer = $.Deferred();
385
			if (!this.$slideshowTemplate) {
386
				var self = this;
387
				var url = OC.generateUrl('apps/galleryplus/slideshow', null);
388
				$.get(url, function (tmpl) {
389
						var template = $(tmpl);
390
						var tmplButton;
391
						var buttonsArray = [
392
							{
393
								el: '.next',
394
								trans: t('gallery', 'Next')
395
							},
396
							{
397
								el: '.play',
398
								trans: t('gallery', 'Play')
399
							},
400
							{
401
								el: '.pause',
402
								trans: t('gallery', 'Pause')
403
							},
404
							{
405
								el: '.previous',
406
								trans: t('gallery', 'Previous')
407
							},
408
							{
409
								el: '.exit',
410
								trans: t('gallery', 'Close')
411
							},
412
							{
413
								el: '.downloadImage',
414
								trans: t('gallery', 'Download'),
415
								toolTip: true
416
							},
417
							{
418
								el: '.changeBackground',
419
								trans: t('gallery', 'Toggle background'),
420
								toolTip: true
421
							},
422
							{
423
								el: '.deleteImage',
424
								trans: t('gallery', 'Delete'),
425
								toolTip: true
426
							}
427
						];
428
						for (var i = 0; i < buttonsArray.length; i++) {
429
							var button = buttonsArray[i];
430
431
							tmplButton = template.find(button.el);
432
							tmplButton.val(button.trans);
433
							if (button.toolTip) {
434
								tmplButton.attr("title", button.trans);
435
							}
436
						}
437
						self.$slideshowTemplate = template;
438
						defer.resolve(self.$slideshowTemplate);
439
					})
440
					.fail(function () {
441
						defer.reject();
442
					});
443
			} else {
444
				defer.resolve(this.$slideshowTemplate);
445
			}
446
			return defer.promise();
447
		}
448
	};
449
450
	window.SlideShow = SlideShow;
451
})(jQuery, OC, OCA, t);
452