GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Pull Request — master (#2835)
by
unknown
06:01
created

symphony/assets/js/src/symphony.js   B

Complexity

Total Complexity 47
Complexity/F 2.35

Size

Lines of Code 401
Function Count 20

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 0
c 0
b 0
f 0
nc 1
dl 0
loc 401
rs 8.439
wmc 47
mnd 2
bc 42
fnc 20
bpm 2.1
cpm 2.35
noi 8

13 Functions

Rating   Name   Duplication   Size   Complexity  
A symphony.js ➔ replaceVariables 0 8 3
A symphony.js ➔ ??? 0 1 1
A symphony.js ➔ addRoute 0 12 2
B symphony.js ➔ translate 0 35 4
A Symphony.Utilities.cancelAnimationFrame 0 3 1
A symphony.js ➔ getString 0 14 2
B symphony.js ➔ addContext 0 20 5
A Symphony.Utilities.getXSRF 0 10 2
A symphony.js ➔ addStrings 0 23 3
A symphony.js ➔ inSight 0 21 1
A Symphony.Utilities.requestAnimationFrame 0 3 1
A symphony.js ➔ renderRoute 0 13 3
A symphony.js ➔ getContext 0 15 3

How to fix   Complexity   

Complexity

Complex classes like symphony/assets/js/src/symphony.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*!
2
 * Symphony 2.7.x, https://www.getsymphony.com, MIT license
3
 */
4
5
/**
6
 * @package assets
7
 */
8
9
/**
10
 * The Symphony object provides language, message and context management.
11
 *
12
 * @class
13
 */
14
var Symphony = (function($, crossroads) {
15
	'use strict';
16
17
	// Internal Symphony storage
18
	var Storage = {
19
		Context: {},
20
		Dictionary: {},
21
		Support: {}
22
	};
23
24
/*-------------------------------------------------------------------------
25
	Functions
26
-------------------------------------------------------------------------*/
27
28
	// Replace variables in string
29
	function replaceVariables(string, inserts) {
30
		if($.type(string) === 'string' && $.type(inserts) === 'object') {
31
			$.each(inserts, function(index, value) {
32
				string = string.replace('{$' + index + '}', value);
0 ignored issues
show
Comprehensibility Best Practice introduced by
This re-assigns to the parameter string. Re-assigning to parameters often makes code less readable, consider introducing a new variable instead.
Loading history...
33
			});
34
		}
35
		return string;
36
	}
37
38
	// Get localised strings
39
	function translate(strings) {
40
		var env = Symphony.Context.get('env');
41
		if (!env) {
42
			// no env, can't continue
43
			return;
44
		}
45
		var namespace = $.trim(env['page-namespace']),
46
			data = {
47
				'strings': strings
48
			};
49
50
		// Validate and set namespace
51
		if($.type(namespace) === 'string' && namespace !== '') {
52
			data.namespace = namespace;
53
		}
54
55
		// Request translations
56
		$.ajax({
57
			async: false,
58
			type: 'GET',
59
			url: Symphony.Context.get('symphony') + '/ajax/translate/',
60
			data: data,
61
			dataType: 'json',
62
63
			// Add localised strings
64
			success: function(result) {
65
				$.extend(true, Storage.Dictionary, result);
66
			},
67
68
			// Use English strings on error
69
			error: function() {
70
				$.extend(true, Storage.Dictionary, strings);
71
			}
72
		});
73
	}
74
75
	// request animation frame
76
	var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame ||  
77
		window.webkitRequestAnimationFrame || window.msRequestAnimationFrame ||
78
		window.oRequestAnimationFrame || function (f) { return window.setTimeout(f, 1000/16); };
79
	var craf = window.cancelAnimationFrame || window.webkitCancelRequestAnimationFrame ||
80
		window.mozCancelRequestAnimationFrame || window.oCancelRequestAnimationFrame ||
81
		window.msCancelRequestAnimationFrame  || function (t) { window.clearTimeout(t); };
82
	
83
84
/*-----------------------------------------------------------------------*/
85
86
	// Set browser support information
87
	try {
88
		Storage.Support.localStorage = !!localStorage.getItem;
0 ignored issues
show
Bug introduced by
The variable localStorage seems to be never declared. If this is a global, consider adding a /** global: localStorage */ 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...
89
	} catch(e) {
90
		Storage.Support.localStorage = false;
91
	}
92
93
	// Deep copy jQuery.support
94
	$.extend(true, Storage.Support, $.support);
95
96
	// Turn off migrate trace
97
	jQuery.migrateTrace = undefined;
98
99
/*-------------------------------------------------------------------------
100
	Symphony API
101
-------------------------------------------------------------------------*/
102
103
	return {
104
105
		/**
106
		 * Symphony backend view using Crossroads
107
		 *
108
		 * @since Symphony 2.4
109
		 */
110
		View: {
111
112
			/**
113
			 * Add function to view
114
			 *
115
			 * @param {String} pattern
116
			 *  Expression to match the view, using the Symphony URL as base
117
			 * @param {Function} handler
118
			 *  Function that should be applied to a view
119
			 * @param {Integer} priority
120
			 *  Priority of the function
121
			 * @param {Boolean} greedy
122
			 *  If set to `false`, only executes the first matched view, defaults to `true`
123
			 * @return {Route}
124
			 *  Returns a route object
125
			 */
126
			add: function addRoute(pattern, handler, priority, greedy) {
127
				var route;
128
129
				pattern = Symphony.Context.get('path') + pattern;
0 ignored issues
show
Comprehensibility Best Practice introduced by
This re-assigns to the parameter pattern. Re-assigning to parameters often makes code less readable, consider introducing a new variable instead.
Loading history...
130
				route = crossroads.addRoute(pattern, handler, priority);
131
132
				if(greedy !== false) {
133
					route.greedy = true;
134
				}
135
136
				return route;
137
			},
138
139
			/**
140
			 * Render given URL, defaults to the current backend URL
141
			 *
142
			 * @param {String} url
143
			 *  The URL of the view that should be rendered, optional
144
			 * @param {Boolean} greedy
145
			 *  Determines, if only the first or all matching views are rendered,
146
			 *  defaults to `true (all)
147
			 */
148
			render: function renderRoute(url, greedy) {
149
150
				if(!url) {
151
152
					url = Symphony.Context.get('path') + Symphony.Context.get('route');
0 ignored issues
show
Comprehensibility Best Practice introduced by
This re-assigns to the parameter url. Re-assigning to parameters often makes code less readable, consider introducing a new variable instead.
Loading history...
153
				}
154
155
				if(greedy === false) {
156
					crossroads.greedyEnabled = false;
157
				}
158
159
				crossroads.parse(url);
160
			}
161
162
		},
163
164
		/**
165
		 * Storage for the main Symphony elements`.
166
		 * Symphony automatically adds all main UI areas.
167
		 *
168
		 * @since Symphony 2.4
169
		 */
170
		Elements: {
171
			window: null,
172
			html: null,
173
			body: null,
174
			wrapper: null,
175
			header: null,
176
			nav: null,
177
			session: null,
178
			context: null,
179
			contents: null
180
		},
181
182
		/**
183
		 * The Context object contains general information about the system,
184
		 * the backend, the current user. It includes an add and a get function.
185
		 * This is a private object and can only be accessed via add and get.
186
		 *
187
		 * @class
188
		 */
189
		Context: {
190
191
			/**
192
			 * Add data to the Context object
193
			 *
194
			 * @param {String} group
195
			 *  Name of the data group
196
			 * @param {String|Object} values
197
			 *  Object or string to be stored
198
			 */
199
			add: function addContext(group, values) {
200
201
				// Add multiple groups
202
				if(!group && $.type(values) === 'object') {
203
					$.extend(Storage.Context, values);
204
				}
205
206
				// Add to existing group
207
				else if(Storage.Context[group] && $.type(values) !== 'string') {
208
					$.extend(Storage.Context[group], values);
209
				}
210
211
				// Add new group
212
				else {
213
					Storage.Context[group] = values;
214
				}
215
216
				// Always return
217
				return true;
218
			},
219
220
			/**
221
			 * Get data from the Context object
222
			 *
223
			 * @param {String} group
224
			 *  Name of the group to be returned
225
			 */
226
			get: function getContext(group) {
227
228
				// Return full context, if no group is set
229
				if(!group) {
230
					return Storage.Context;
231
				}
232
233
				// Return false if group does not exist in Storage
234
				if(typeof Storage.Context[group] === 'undefined') {
235
					return false;
236
				}
237
238
				// Default: Return context group
239
				return Storage.Context[group];
240
			}
241
		},
242
243
		/**
244
		 * The Language object stores the dictionary with all needed translations.
245
		 * It offers public functions to add strings and get their translation and
246
		 * it offers private functions to handle variables and get the translations via
247
		 * an synchronous AJAX request.
248
		 * Since Symphony 2.3, it is also possible to define different translations
249
		 * for the same string, by using page namespaces.
250
		 * This is a private object
251
		 *
252
		 * @class
253
		 */
254
		Language: {
255
256
			/**
257
			 * Add strings to the Dictionary
258
			 *
259
			 * @param {Object} strings
260
			 *  Object with English string as key, value should be false
261
			 */
262
			add: function addStrings(strings) {
263
264
				// English system
265
				if(Symphony.Context.get('lang') === 'en') {
266
					$.extend(true, Storage.Dictionary, strings);
267
				}
268
269
				// Localised system
270
				else {
271
272
					// Check if strings have already been translated
273
					$.each(strings, function checkStrings(index, key) {
274
						if(key in Storage.Dictionary) {
275
							delete strings[key];
276
						}
277
					});
278
279
					// Translate strings
280
					if(!$.isEmptyObject(strings)) {
281
						translate(strings);
282
					}
283
				}
284
			},
285
286
			/**
287
			 * Get translated string from the Dictionary.
288
			 * The function replaces variables like {$name} with the a specified value if
289
			 * an object of inserts is passed in the function call.
290
			 *
291
			 * @param {String} string
292
			 *  English string to be translated
293
			 * @param {Object} inserts
294
			 *  Object with variable name and value pairs
295
			 * @return {String}
296
			 *  Returns the translated string
297
			 */
298
			get: function getString(string, inserts) {
299
				var translation = Storage.Dictionary[string];
300
301
				// Validate and set translation
302
				if($.type(translation) === 'string') {
303
					string = translation;
0 ignored issues
show
Comprehensibility Best Practice introduced by
This re-assigns to the parameter string. Re-assigning to parameters often makes code less readable, consider introducing a new variable instead.
Loading history...
304
				}
305
306
				// Insert variables
307
				string = replaceVariables(string, inserts);
308
309
				// Return translated string
310
				return string;
311
			}
312
		},
313
314
		/**
315
		 * A collection of properties that represent the presence of
316
		 * different browser features and also contains the test results
317
		 * from jQuery.support.
318
		 *
319
		 * @class
320
		 */
321
		Support: Storage.Support,
322
323
		/**
324
		 * A namespace for core interface components
325
		 *
326
		 * @since Symphony 2.6
327
		 */
328
		Interface: {},
329
330
		/**
331
		 * A namespace for extension to store global functions
332
		 *
333
		 * @since Symphony 2.3
334
		 */
335
		Extensions: {},
336
337
		/**
338
		 * Helper functions
339
		 *
340
		 * @since Symphony 2.4
341
		 */
342
		Utilities: {
343
344
			/**
345
			 * Get a jQuery object of all elements within the current viewport
346
			 *
347
			 * @since Symphony 2.4
348
			 */
349
			inSight: function inSight(elements) {
350
				var windowHeight = window.innerHeight,
351
					visibles = $();
352
353
				elements.each(function() {
354
					var context = this.getBoundingClientRect();
355
356
					if(
357
						(context.top >= 0 && context.top <= windowHeight) || // Element top in sight
358
						(context.bottom >= 0 && context.bottom <= windowHeight) || // Element bottom in sight
359
						(context.top <= 0 && context.bottom >= windowHeight) // Element overflowing viewport
360
					) {
361
						visibles = visibles.add(this);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
362
					}
363
					else if (visibles.length > 0) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if visibles.length > 0 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
364
						return false;
365
					}
366
				});
367
368
				return visibles;
369
			},
370
371
			/**
372
			 * Returns the XSRF token for the backend
373
			 *
374
			 * @since Symphony 2.4
375
			 * @param boolean $serialised
376
			 *  If passed as true, this function will return the string as a serialised
377
			 *  form elements, ie. field=value. If omitted, or false, this function
378
			 *  will just return the XSRF token.
379
			 */
380
			getXSRF: function(serialised) {
381
				var xsrf = Symphony.Elements.contents.find('input[name=xsrf]').val();
382
383
				if(serialised === true) {
384
					return 'xsrf=' + encodeURIComponent(xsrf);
385
				}
386
				else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
387
					return xsrf;
388
				}
389
			},
390
391
			/**
392
			 * Cross browser wrapper around requestFrameAnimation
393
			 *
394
			 * @since Symphony 2.5
395
			 * @param function $func
396
			 *  The callback to schedule for frame animation
397
			 */
398
			requestAnimationFrame: function (func) {
399
				return raf.call(window, func);
400
			},
401
402
			/**
403
			 * Cross browser wrapper around cancelAnimationFrame
404
			 *
405
			 * @since Symphony 2.5
406
			 * @param Integer $t
407
			 *  The request id
408
			 */
409
			cancelAnimationFrame: function (t) {
410
				return craf.call(window, t);
411
			}
412
		}
413
	};
414
}(window.jQuery, window.crossroads));
415