Issues (263)

js/galleryutility.js (1 issue)

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 DOMPurify, oc_requesttoken, Gallery */
13
14
// The Utility class can also be loaded by the Files app
15
window.Gallery = window.Gallery || {};
16
17
(function ($, OC, t, oc_requesttoken, Gallery) {
18
	"use strict";
19
	/**
20
	 * Contains utility methods
21
	 *
22
	 * @fixme OC.generateUrl, OC.buildQueryString, OC.Notification are private APIs
23
	 *
24
	 * @constructor
25
	 */
26
	var Utility = function () {
27
	};
28
29
	Utility.prototype = {
30
		/**
31
		 * Detects if the browser is a recent or an old version of Internet Explorer
32
		 *
33
		 * @returns {string|boolean}
34
		 */
35
		getIeVersion: function () {
36
			// Blocking IE8
37
			if ($('html').is('.ie8')) {
38
				return 'unsupportedIe';
39
			} else if (navigator.userAgent.indexOf("MSIE") > 0) {
40
				return 'unsupportedIe';
41
			} else if (!!navigator.userAgent.match(/Trident.*rv[ :]*11\./)) {
42
				return 'modernIe';
43
			} else if (navigator.userAgent.indexOf("Edge/") > 0) {
44
				return 'edge';
45
			}
46
47
			return false;
48
		},
49
50
		/**
51
		 * Shows a notification to IE users, letting them know that they should use another browser
52
		 * in order to get the best experience
53
		 *
54
		 * @param {string} version
55
		 */
56
		showIeWarning: function (version) {
57
			var line1 = t('gallery', 'This application may not work properly on your browser.');
58
			var line2 = t('gallery',
59
				'For an improved experience, please install one of the following alternatives');
60
			var timeout = 15;
61
			if (version === 'unsupportedIe') {
62
				line1 = t('gallery', 'Your browser is not supported!');
63
				line2 = t('gallery', 'please install one of the following alternatives');
64
				timeout = 60;
65
			}
66
67
			var recommendedBrowsers = '</br>' +
68
				'<a href="http://www.getfirefox.com"><strong>Mozilla Firefox</strong></a> or ' +
69
				'<a href="https://www.google.com/chrome/"><strong>Google Chrome</strong></a>' +
70
				'</br>';
71
72
			var text = '<strong>' + line1 + '</strong></br>' + line2 + recommendedBrowsers;
73
			this.showHtmlNotification(text, timeout);
74
		},
75
76
		/**
77
		 * Shows a notification at the top of the screen
78
		 *
79
		 * @param {string} text
80
		 * @param {int} timeout
81
		 */
82
		showHtmlNotification: function (text, timeout) {
83
			var options = {
84
				timeout: timeout,
85
				isHTML: true
86
			};
87
			OC.Notification.showTemporary(text, options);
88
		},
89
90
		/**
91
		 * Returns the token allowing access to files shared via link
92
		 *
93
		 * @returns {string}
94
		 */
95
		getPublicToken: function () {
96
			var element = $('#gallery');
97
			var token;
98
99
			if (element.data('token')) {
100
				token = element.data('token');
101
			}
102
103
			if (element.data('requesttoken')) {
104
				/* jshint camelcase: false */
105
				oc_requesttoken = element.data('requesttoken');
106
			}
107
108
			return token;
109
		},
110
111
		/**
112
		 * Returns the host we can use for WebDAV
113
		 * 
114
		 * On public galleries, we need to provide the token as authorization
115
		 *
116
		 * @returns {string}
117
		 */
118
		getWebdavHost: function () {
119
			var host = OC.getHost();
120
			if (Gallery.token) {
121
				host = Gallery.token + '@' + host;
122
			}
123
124
			return host;
125
		},
126
127
		/**
128
		 * Returns the WebDAV endpoint we can use for files operations
129
		 *
130
		 * @returns {string}
131
		 */
132
		getWebdavRoot: function () {
133
			var root = OC.linkToRemoteBase('webdav');
134
			if (Gallery.token) {
135
				root = root.replace('remote.php', 'public.php');
136
			}
137
138
			return root;
139
		},
140
141
		/**
142
		 * Builds the URL which will retrieve a large preview of the file
143
		 *
144
		 * @fixme we cannot get rid of oc_requesttoken parameter as it's missing from the headers
145
		 *
146
		 * @param {number} fileId
147
		 * @param {number} etag
148
		 *
149
		 * @return {string}
150
		 */
151
		getPreviewUrl: function (fileId, etag) {
152
			var width = Math.ceil(screen.width * window.devicePixelRatio);
0 ignored issues
show
The variable screen seems to be never declared. If this is a global, consider adding a /** global: screen */ 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...
153
			var height = Math.ceil(screen.height * window.devicePixelRatio);
154
155
			/* Find value of longest edge. */
156
			var longEdge = Math.max(width, height);
157
158
			/* Find the next larger image size. */
159
			if (longEdge % 100 !== 0) {
160
				longEdge = ( longEdge + 100 ) - ( longEdge % 100 );
161
			}
162
163
			/* jshint camelcase: false */
164
			var params = {
165
				width: longEdge,
166
				height: longEdge,
167
			};
168
			return this.buildGalleryUrl('preview', '/' + fileId, params);
169
		},
170
171
		/**
172
		 * Builds a URL pointing to one of the app's controllers
173
		 *
174
		 * @param {string} endPoint
175
		 * @param {undefined|string} path
176
		 * @param params
177
		 *
178
		 * @returns {string}
179
		 */
180
		buildGalleryUrl: function (endPoint, path, params) {
181
			if (path === undefined) {
182
				path = '';
183
			}
184
			var extension = '';
185
			if (Gallery.token) {
186
				params.token = Gallery.token;
187
				extension = '.public';
188
			}
189
			var query = OC.buildQueryString(params);
190
			return OC.generateUrl('apps/' + Gallery.appName + '/' + endPoint + extension + path,
191
					null) +
192
				'?' +
193
				query;
194
		},
195
196
		/**
197
		 * Builds a URL pointing to one of the files' controllers
198
		 *
199
		 * @param {string} path
200
		 * @param {string} files
201
		 *
202
		 * @returns {string}
203
		 */
204
		buildFilesUrl: function (path, files) {
205
			var subUrl = '';
206
			var params = {
207
				path: path,
208
				files: files
209
			};
210
211
			if (Gallery.token) {
212
				params.token = Gallery.token;
213
				subUrl = 's/{token}/download?dir={path}&files={files}';
214
			} else {
215
				subUrl = 'apps/files/ajax/download.php?dir={path}&files={files}';
216
			}
217
218
			return OC.generateUrl(subUrl, params);
219
		},
220
221
		/**
222
		 * Sorts arrays based on name or date
223
		 *
224
		 * @param {string} sortType
225
		 * @param {string} sortOrder
226
		 *
227
		 * @returns {Function}
228
		 */
229
		sortBy: function (sortType, sortOrder) {
230
			if (sortType === 'name') {
231
				if (sortOrder === 'asc') {
232
					//sortByNameAsc
233
					return function (a, b) {
234
						return OC.Util.naturalSortCompare(a.path, b.path);
235
					};
236
				}
237
				//sortByNameDes
238
				return function (a, b) {
239
					return -OC.Util.naturalSortCompare(a.path, b.path);
240
				};
241
			}
242
			if (sortType === 'date') {
243
				if (sortOrder === 'asc') {
244
					//sortByDateAsc
245
					return function (a, b) {
246
						return b.mTime - a.mTime;
247
					};
248
				}
249
				//sortByDateDes
250
				return function (a, b) {
251
					return a.mTime - b.mTime;
252
				};
253
			}
254
		},
255
256
		/**
257
		 * Adds hooks to DOMPurify
258
		 */
259
		addDomPurifyHooks: function () {
260
			// allowed URI schemes
261
			var whitelist = ['http', 'https'];
262
263
			// build fitting regex
264
			var regex = new RegExp('^(' + whitelist.join('|') + '):', 'gim');
265
266
			DOMPurify.addHook('afterSanitizeAttributes', function (node) {
267
				// This hook enforces URI scheme whitelist
268
				// @link
269
				// https://github.com/cure53/DOMPurify/blob/master/demos/hooks-scheme-whitelist.html
270
271
				// build an anchor to map URLs to
272
				var anchor = document.createElement('a');
273
274
				// check all href attributes for validity
275
				if (node.hasAttribute('href')) {
276
					anchor.href = node.getAttribute('href');
277
					if (anchor.protocol && !anchor.protocol.match(regex)) {
278
						node.removeAttribute('href');
279
					}
280
				}
281
				// check all action attributes for validity
282
				if (node.hasAttribute('action')) {
283
					anchor.href = node.getAttribute('action');
284
					if (anchor.protocol && !anchor.protocol.match(regex)) {
285
						node.removeAttribute('action');
286
					}
287
				}
288
				// check all xlink:href attributes for validity
289
				if (node.hasAttribute('xlink:href')) {
290
					anchor.href = node.getAttribute('xlink:href');
291
					if (anchor.protocol && !anchor.protocol.match(regex)) {
292
						node.removeAttribute('xlink:href');
293
					}
294
				}
295
296
				// This hook restores the proper, standard namespace in SVG files
297
				var encodedXmlns, decodedXmlns;
298
299
				// Restores namespaces which were put in the DOCTYPE by Illustrator
300
				if (node.hasAttribute('xmlns') && node.getAttribute('xmlns') === '&ns_svg;') {
301
					encodedXmlns = node.getAttribute('xmlns');
302
					decodedXmlns = encodedXmlns.replace('&ns_svg;', 'http://www.w3.org/2000/svg');
303
					node.setAttribute('xmlns', decodedXmlns);
304
				}
305
				if (node.hasAttribute('xmlns:xlink') &&
306
					node.getAttribute('xmlns:xlink') === '&ns_xlink;') {
307
					encodedXmlns = node.getAttribute('xmlns:xlink');
308
					decodedXmlns =
309
						encodedXmlns.replace('&ns_xlink;', 'http://www.w3.org/1999/xlink');
310
					node.setAttribute('xmlns:xlink', decodedXmlns);
311
				}
312
			});
313
		}
314
	};
315
316
	Gallery.Utility = Utility;
317
})(jQuery, OC, t, oc_requesttoken, Gallery);
318