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 (#2837)
by
unknown
05:48
created

symphony/assets/js/src/symphony.collapsible.js   C

Complexity

Total Complexity 57
Complexity/F 1.84

Size

Lines of Code 303
Function Count 31

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 0
c 0
b 0
f 0
nc 1152
dl 0
loc 303
rs 5.7222
wmc 57
mnd 2
bc 49
fnc 31
bpm 1.5806
cpm 1.8387
noi 8

2 Functions

Rating   Name   Duplication   Size   Complexity  
B $.fn.symphonyCollapsible 0 264 1
A symphony.collapsible.js ➔ save 0 11 2

How to fix   Complexity   

Complexity

Complex classes like symphony/assets/js/src/symphony.collapsible.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
 * @package assets
3
 */
4
5
(function($, Symphony) {
6
7
	// Saves the value into the local storage at the specified storage key.
8
	var save = function (storage, value) {
9
		// Put in a try/catch in case something goes wrong (no space, privileges etc)
10
		// Always put try/catches into their own function to prevent callers from
11
		// going into un-optimized hell
12
		try {
13
			window.localStorage[storage] = value;
14
		}
15
		catch(e) {
16
			window.onerror(e.message);
17
		}
18
	};
19
20
	/**
21
	 * Create collapsible elements.
22
	 *
23
	 * @name $.symphonyCollapsible
24
	 * @class
25
	 *
26
	 * @param {Object} options An object specifying containing the attributes specified below
27
	 * @param {String} [options.items='.instance'] Selector to find collapsible items within the container
28
	 * @param {String} [options.handles='.header:first'] Selector to find clickable handles to trigger interaction
29
	 * @param {String} [options.content='.content'] Selector to find hideable content area
30
	 * @param {Boolean} [options.save_state=true] Stores states of instances using local storage
31
	 * @param {String} [options.storage='symphony.collapsible.area.page.id'] Namespace used for local storage
32
	 * @param {Integer} [options.delay=250] Time delay for animations
33
	 *
34
	 * @example
35
36
			var collapsible = $('#duplicator').symphonyCollapsible({
37
				items:		'.instance',
38
				handles:	'.header span'
39
			});
40
			collapsible.collapseAll();
41
	 */
42
	$.fn.symphonyCollapsible = function(options) {
43
		var objects = this,
44
			settings = {
45
				items: '.instance',
46
				handles: '.frame-header',
47
				content: '.content',
48
				ignore: '.ignore',
49
				save_state: true,
50
				storage: 'symphony.collapsible.' + Symphony.Context.get('context-id'),
51
				delay: 250
52
			};
53
54
		$.extend(settings, options);
55
56
	/*-----------------------------------------------------------------------*/
57
58
		objects.each(function collapsible(index) {
59
			var object = $(this),
60
				storage = settings.storage + '.' + index + '.collapsed';
61
62
			var getDuration = function (duration) {
63
				return $.isNumeric(duration) ? duration : settings.delay;
64
			};
65
66
		/*---------------------------------------------------------------------
67
			Events
68
		---------------------------------------------------------------------*/
69
70
			var collapseItem = function collapse(item, duration) {
71
				var heightMin = 0;
72
73
				// Customization point
74
				item.trigger('collapsebefore.collapsible', settings);
75
76
				heightMin = item.data('heightMin');
77
78
				// Check duration
79
				if(duration !== 0) {
80
					item.addClass('js-animate');
81
					item.trigger('collapsestart.collapsible');
82
				}
83
84
				// Collapse item
85
				item.addClass('collapsed');
86
				item.css('max-height', heightMin);
87
88
				if(duration !== 0) {
89
					setTimeout(function() {
90
						item.trigger('animationend.collapsible');
91
						item.trigger('animationend.duplicator');
92
					}, duration);
93
				}
94
			};
95
96
			// Collapse item
97
			object.on('collapse.collapsible', settings.items, function collapse(event, duration) {
98
				var item = $(this);
99
				collapseItem(item, getDuration(duration));
100
			});
101
102
			// Collapse all items
103
			object.on('collapseall.collapsible', function collapseAll(event) {
0 ignored issues
show
Unused Code introduced by
The parameter event 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...
104
				var items = object.find(settings.items + ':not(.collapsed)'),
105
					visibles = Symphony.Utilities.inSight(items),
106
					invisibles = $(),
107
					scrollTop = $(window).scrollTop(),
108
					visibleIndex = visibles.eq(0).index(),
109
					visibleCollapsedHeight = 0;
110
111
				// Find items that will be visible after collapse
112
				while (visibleIndex < items.length && visibleCollapsedHeight < window.innerHeight) {
113
					var currentItem = items.eq(visibleIndex);
114
					visibles = visibles.add(currentItem);
115
					visibleCollapsedHeight += currentItem.data('heightMin');
116
					visibleIndex++;
117
				}
118
				visibles.each(function () { collapseItem($(this), settings.delay); });
119
120
				setTimeout(function collapseAllInvisibleEnd() {
121
					var first = visibles.eq(0);
122
					var firstOffset = !first.length ? 0 : first.offset().top;
123
					// update invisible accordingly
124
					invisibles = items.not(visibles);
125
					invisibles.each(function () { collapseItem($(this), 0); });
126
					if (firstOffset > 0 && scrollTop > object.offset().top) {
127
						// scroll back to where we were,
128
						// which is last scroll position + delta of first visible item
129
						$(window).scrollTop(scrollTop + (first.offset().top - firstOffset));
130
					}
131
					invisibles.trigger('animationend.collapsible');
132
				}, settings.delay + 100);
133
			});
134
135
			// Expand item
136
			var expandItem = function (item, duration) {
137
				var heightMax = 0;
138
139
				// Customization point
140
				item.trigger('expandbefore.collapsible', settings);
141
142
				heightMax = item.data('heightMax');
143
144
				// Check duration
145
				if(duration !== 0) {
146
					item.addClass('js-animate');
147
					item.trigger('expandstart.collapsible');
148
				}
149
150
				// Collapse item
151
				item.removeClass('collapsed');
152
				item.css('max-height', heightMax);
153
154
				if(duration !== 0) {
155
					setTimeout(function() {
156
						item.trigger('animationend.collapsible');
157
					}, duration);
158
				}
159
			};
160
161
			object.on('expand.collapsible', settings.items, function expand(event, duration) {
162
				var item = $(this);
163
				expandItem(item, getDuration(duration));
164
			});
165
166
			// Expand all items
167
			object.on('expandall.collapsible', function expandAll(event) {
0 ignored issues
show
Unused Code introduced by
The parameter event 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...
168
				var items = object.find(settings.items + '.collapsed'),
169
					visibles = Symphony.Utilities.inSight(items).filter('*:lt(4)'),
170
					invisibles = items.not(visibles),
171
					scrollTop = $(window).scrollTop();
172
173
				visibles.addClass('js-animate-all'); // prevent focus
174
				visibles.each(function () { expandItem($(this), settings.delay); });
175
				setTimeout(function expandAllInvisible() {
176
					var first = visibles.eq(0);
177
					var firstOffset = !first.length ? 0 : first.offset().top;
178
					invisibles.addClass('js-animate-all'); // prevent focus
179
					invisibles.each(function () { expandItem($(this), 0); });
180
					invisibles.trigger('animationend.collapsible');
181
					// if we are past the first item
182
					if (firstOffset > 0 && scrollTop > object.offset().top) {
183
						// scroll back to where we were,
184
						// which is last scroll position + delta of first visible item
185
						$(window).scrollTop(scrollTop + (first.offset().top - firstOffset));
186
					}
187
				}, settings.delay + 100);
188
			});
189
190
			// Finish animations
191
			object.on('animationend.collapsible', settings.items, function finish(event) {
0 ignored issues
show
Unused Code introduced by
The parameter event 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...
192
				var item = $(this);
193
194
				// Trigger events
195
				if(item.is('.collapsed')) {
196
					item.trigger('collapsestop.collapsible');
197
				}
198
				else {
199
					item.trigger('expandstop.collapsible');
200
				}
201
202
				// clean up
203
				item.removeClass('js-animate js-animate-all');
204
			});
205
206
			// Toggle single item
207
			object.on('click.collapsible', settings.handles, function toggle(event) {
208
				var handle = $(this),
209
					item = handle.closest(settings.items);
210
211
				if(!handle.is(settings.ignore) && !$(event.target).is(settings.ignore) && !item.is('.locked')) {
212
213
					// Expand
214
					if(item.is('.collapsed')) {
215
						expandItem(item, settings.delay);
216
					}
217
218
					// Collapse
219
					else {
220
						collapseItem(item, settings.delay);
221
					}
222
				}
223
			});
224
225
			// Save states
226
			var saveTimer = 0;
227
			object.on('collapsestop.collapsible expandstop.collapsible store.collapsible', settings.items, function saveState(event) {
0 ignored issues
show
Unused Code introduced by
The parameter event 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...
228
				if(settings.save_state === true && Symphony.Support.localStorage === true) {
229
					// save it to local storage, delayed, once
230
					clearTimeout(saveTimer);
231
					saveTimer = setTimeout(function () {
232
						var collapsed = object.find(settings.items).map(function(index) {
233
							if($(this).is('.collapsed')) {
234
								return index;
235
							};
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...
236
						}).get().join(',');
237
238
						save(storage, collapsed);
239
					}, settings.delay);
240
				}
241
			});
242
243
			// Restore states
244
			object.on('restore.collapsible', function restoreState(event) {
0 ignored issues
show
Unused Code introduced by
The parameter event 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...
245
				if(settings.save_state === true && Symphony.Support.localStorage === true && window.localStorage[storage]) {
246
					$.each(window.localStorage[storage].split(','), function(index, value) {
247
						var collapsed = object.find(settings.items).eq(value);
248
						if(collapsed.has('.invalid').length == 0) {
0 ignored issues
show
Best Practice introduced by
Comparing collapsed.has(".invalid").length to 0 using the == operator is not safe. Consider using === instead.
Loading history...
249
							collapseItem(collapsed, 0);
250
						}
251
					});
252
				}
253
			});
254
255
			// Refresh state storage after ordering
256
			object.on('orderstop.orderable', function refreshOrderedState(event) {
0 ignored issues
show
Unused Code introduced by
The parameter event 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...
257
				object.find(settings.items).trigger('store.collapsible');
258
			});
259
260
			// Refresh state storage after deleting and instance
261
			object.on('destructstop.duplicator', settings.items, function refreshState() {
262
				$(this).trigger('store.collapsible');
263
			});
264
265
			// Update sizes
266
			object.on('updatesize.collapsible', settings.items, function updateSizes() {
267
				var item = $(this),
268
					min = item.find(settings.handles).outerHeight(true),
269
					max = min + item.find(settings.content).outerHeight(true);
270
271
				item.data('heightMin', min);
272
				item.data('heightMax', max);
273
			});
274
275
			// Set sizes
276
			object.on('setsize.collapsible', settings.items, function setSizes() {
277
				var item = $(this);
278
				var heightMin = item.data('heightMin');
279
				var heightMax = item.data('heightMax');
280
				item.css({
281
					'min-height': heightMin,
282
					'max-height': heightMax
283
				});
284
			});
285
286
		/*---------------------------------------------------------------------
287
			Initialisation
288
		---------------------------------------------------------------------*/
289
290
			// Prepare interface
291
			object.addClass('collapsible').find(settings.items).each(function() {
292
				var item = $(this);
293
				item.addClass('instance');
294
				item.trigger('updatesize.collapsible');
295
				item.trigger('setsize.collapsible');
296
			});
297
298
			// Restore states
299
			object.trigger('restore.collapsible');
300
		});
301
302
	/*-----------------------------------------------------------------------*/
303
304
		return objects;
305
	};
306
307
})(window.jQuery, window.Symphony);
308