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 (#2843)
by Brendan
04:11
created

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

Complexity

Total Complexity 47
Complexity/F 2.35

Size

Lines of Code 397
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 397
rs 8.439
wmc 47
mnd 2
bc 42
fnc 20
bpm 2.1
cpm 2.35
noi 11

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
16
	// Internal Symphony storage
17
	var Storage = {
18
		Context: {},
19
		Dictionary: {},
20
		Support: {}
21
	};
22
23
/*-------------------------------------------------------------------------
24
	Functions
25
-------------------------------------------------------------------------*/
26
27
	// Replace variables in string
28
	function replaceVariables(string, inserts) {
29
		if($.type(string) === 'string' && $.type(inserts) === 'object') {
30
			$.each(inserts, function(index, value) {
31
				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...
32
			});
33
		}
34
		return string;
35
	}
36
37
	// Get localised strings
38
	function translate(strings) {
39
		var env = Symphony.Context.get('env');
40
		if (!env) {
41
			// no env, can't continue
42
			return;
43
		}
44
		var namespace = $.trim(env['page-namespace']),
45
			data = {
46
				'strings': strings
47
			};
48
49
		// Validate and set namespace
50
		if($.type(namespace) === 'string' && namespace !== '') {
51
			data.namespace = namespace;
52
		}
53
54
		// Request translations
55
		$.ajax({
56
			async: false,
57
			type: 'GET',
58
			url: Symphony.Context.get('symphony') + '/ajax/translate/',
59
			data: data,
60
			dataType: 'json',
61
62
			// Add localised strings
63
			success: function(result) {
64
				$.extend(true, Storage.Dictionary, result);
65
			},
66
67
			// Use English strings on error
68
			error: function(jqXHR, textStatus, errorThrown) {
0 ignored issues
show
Unused Code introduced by
The parameter errorThrown is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter textStatus is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter jqXHR is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
69
				$.extend(true, Storage.Dictionary, strings);
70
			}
71
		});
72
	}
73
74
	// request animation frame
75
	var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame ||  
76
		window.webkitRequestAnimationFrame || window.msRequestAnimationFrame ||
77
		window.oRequestAnimationFrame || function (f) { return window.setTimeout(f, 16/1000) };
78
	var craf = window.cancelAnimationFrame || window.webkitCancelRequestAnimationFrame ||
79
		window.mozCancelRequestAnimationFrame || window.oCancelRequestAnimationFrame ||
80
		window.msCancelRequestAnimationFrame  || function (t) { window.clearTimeout(t); };
81
	
82
83
/*-----------------------------------------------------------------------*/
84
85
	// Set browser support information
86
	try {
87
		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...
88
	} catch(e) {
89
		Storage.Support.localStorage = false;
90
	}
91
92
	// Deep copy jQuery.support
93
	$.extend(true, Storage.Support, $.support);
94
95
/*-------------------------------------------------------------------------
96
	Symphony API
97
-------------------------------------------------------------------------*/
98
99
	return {
100
101
		/**
102
		 * Symphony backend view using Crossroads
103
		 *
104
		 * @since Symphony 2.4
105
		 */
106
		View: {
107
108
			/**
109
			 * Add function to view
110
			 *
111
			 * @param {String} pattern
112
			 *  Expression to match the view, using the Symphony URL as base
113
			 * @param {Function} handler
114
			 *  Function that should be applied to a view
115
			 * @param {Integer} priority
116
			 *  Priority of the function
117
			 * @param {Boolean} greedy
118
			 *  If set to `false`, only executes the first matched view, defaults to `true`
119
			 * @return {Route}
120
			 *  Returns a route object
121
			 */
122
			add: function addRoute(pattern, handler, priority, greedy) {
123
				var route;
124
125
				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...
126
				route = crossroads.addRoute(pattern, handler, priority);
127
128
				if(greedy !== false) {
129
					route.greedy = true;
130
				}
131
132
				return route;
133
			},
134
135
			/**
136
			 * Render given URL, defaults to the current backend URL
137
			 *
138
			 * @param {String} url
139
			 *  The URL of the view that should be rendered, optional
140
			 * @param {Boolean} greedy
141
			 *  Determines, if only the first or all matching views are rendered,
142
			 *  defaults to `true (all)
143
			 */
144
			render: function renderRoute(url, greedy) {
145
146
				if(!url) {
147
148
					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...
149
				}
150
151
				if(greedy === false) {
152
					crossroads.greedyEnabled = false;
153
				}
154
155
				crossroads.parse(url);
156
			}
157
158
		},
159
160
		/**
161
		 * Storage for the main Symphony elements`.
162
		 * Symphony automatically adds all main UI areas.
163
		 *
164
		 * @since Symphony 2.4
165
		 */
166
		Elements: {
167
			window: null,
168
			html: null,
169
			body: null,
170
			wrapper: null,
171
			header: null,
172
			nav: null,
173
			session: null,
174
			context: null,
175
			contents: null
176
		},
177
178
		/**
179
		 * The Context object contains general information about the system,
180
		 * the backend, the current user. It includes an add and a get function.
181
		 * This is a private object and can only be accessed via add and get.
182
		 *
183
		 * @class
184
		 */
185
		Context: {
186
187
			/**
188
			 * Add data to the Context object
189
			 *
190
			 * @param {String} group
191
			 *  Name of the data group
192
			 * @param {String|Object} values
193
			 *  Object or string to be stored
194
			 */
195
			add: function addContext(group, values) {
196
197
				// Add multiple groups
198
				if(!group && $.type(values) === 'object') {
199
					$.extend(Storage.Context, values);
200
				}
201
202
				// Add to existing group
203
				else if(Storage.Context[group] && $.type(values) !== 'string') {
204
					$.extend(Storage.Context[group], values);
205
				}
206
207
				// Add new group
208
				else {
209
					Storage.Context[group] = values;
210
				}
211
212
				// Always return
213
				return true;
214
			},
215
216
			/**
217
			 * Get data from the Context object
218
			 *
219
			 * @param {String} group
220
			 *  Name of the group to be returned
221
			 */
222
			get: function getContext(group) {
223
224
				// Return full context, if no group is set
225
				if(!group) {
226
					return Storage.Context;
227
				}
228
229
				// Return false if group does not exist in Storage
230
				if(typeof Storage.Context[group] === 'undefined') {
231
					return false;
232
				}
233
234
				// Default: Return context group
235
				return Storage.Context[group];
236
			}
237
		},
238
239
		/**
240
		 * The Language object stores the dictionary with all needed translations.
241
		 * It offers public functions to add strings and get their translation and
242
		 * it offers private functions to handle variables and get the translations via
243
		 * an synchronous AJAX request.
244
		 * Since Symphony 2.3, it is also possible to define different translations
245
		 * for the same string, by using page namespaces.
246
		 * This is a private object
247
		 *
248
		 * @class
249
		 */
250
		Language: {
251
252
			/**
253
			 * Add strings to the Dictionary
254
			 *
255
			 * @param {Object} strings
256
			 *  Object with English string as key, value should be false
257
			 */
258
			add: function addStrings(strings) {
259
260
				// English system
261
				if(Symphony.Context.get('lang') === 'en') {
262
					$.extend(true, Storage.Dictionary, strings);
263
				}
264
265
				// Localised system
266
				else {
267
268
					// Check if strings have already been translated
269
					$.each(strings, function checkStrings(index, key) {
270
						if(key in Storage.Dictionary) {
271
							delete strings[key];
272
						}
273
					});
274
275
					// Translate strings
276
					if(!$.isEmptyObject(strings)) {
277
						translate(strings);
278
					}
279
				}
280
			},
281
282
			/**
283
			 * Get translated string from the Dictionary.
284
			 * The function replaces variables like {$name} with the a specified value if
285
			 * an object of inserts is passed in the function call.
286
			 *
287
			 * @param {String} string
288
			 *  English string to be translated
289
			 * @param {Object} inserts
290
			 *  Object with variable name and value pairs
291
			 * @return {String}
292
			 *  Returns the translated string
293
			 */
294
			get: function getString(string, inserts) {
295
				var translation = Storage.Dictionary[string];
296
297
				// Validate and set translation
298
				if($.type(translation) === 'string') {
299
					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...
300
				}
301
302
				// Insert variables
303
				string = replaceVariables(string, inserts);
304
305
				// Return translated string
306
				return string;
307
			}
308
		},
309
310
		/**
311
		 * A collection of properties that represent the presence of
312
		 * different browser features and also contains the test results
313
		 * from jQuery.support.
314
		 *
315
		 * @class
316
		 */
317
		Support: Storage.Support,
318
319
		/**
320
		 * A namespace for core interface components
321
		 *
322
		 * @since Symphony 2.6
323
		 */
324
		Interface: {},
325
326
		/**
327
		 * A namespace for extension to store global functions
328
		 *
329
		 * @since Symphony 2.3
330
		 */
331
		Extensions: {},
332
333
		/**
334
		 * Helper functions
335
		 *
336
		 * @since Symphony 2.4
337
		 */
338
		Utilities: {
339
340
			/**
341
			 * Get a jQuery object of all elements within the current viewport
342
			 *
343
			 * @since Symphony 2.4
344
			 */
345
			inSight: function inSight(elements) {
346
				var windowHeight = window.innerHeight,
347
					visibles = $();
348
349
				elements.each(function() {
350
					var context = this.getBoundingClientRect();
351
352
					if(
353
						(context.top >= 0 && context.top <= windowHeight) || // Element top in sight
354
						(context.bottom >= 0 && context.bottom <= windowHeight) || // Element bottom in sight
355
						(context.top <= 0 && context.bottom >= windowHeight) // Element overflowing viewport
356
					) {
357
						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...
358
					}
359
					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...
360
						return false;
361
					}
362
				});
363
364
				return visibles;
365
			},
366
367
			/**
368
			 * Returns the XSRF token for the backend
369
			 *
370
			 * @since Symphony 2.4
371
			 * @param boolean $serialised
372
			 *  If passed as true, this function will return the string as a serialised
373
			 *  form elements, ie. field=value. If omitted, or false, this function
374
			 *  will just return the XSRF token.
375
			 */
376
			getXSRF: function(serialised) {
377
				var xsrf = Symphony.Elements.contents.find('input[name=xsrf]').val();
378
379
				if(serialised === true) {
380
					return 'xsrf=' + encodeURIComponent(xsrf);
381
				}
382
				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...
383
					return xsrf;
384
				}
385
			},
386
387
			/**
388
			 * Cross browser wrapper around requestFrameAnimation
389
			 *
390
			 * @since Symphony 2.5
391
			 * @param function $func
392
			 *  The callback to schedule for frame animation
393
			 */
394
			requestAnimationFrame: function (func) {
395
				return raf.call(window, func);
396
			},
397
398
			/**
399
			 * Cross browser wrapper around cancelAnimationFrame
400
			 *
401
			 * @since Symphony 2.5
402
			 * @param Integer $t
403
			 *  The request id
404
			 */
405
			cancelAnimationFrame: function (t) {
406
				return craf.call(window, t);
407
			}
408
		}
409
	};
410
}(window.jQuery, window.crossroads));
411