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/backend.views.js   F

Complexity

Total Complexity 132
Complexity/F 1.67

Size

Lines of Code 875
Function Count 79

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 0
c 0
b 0
f 0
nc 49152
dl 0
loc 875
rs 2.1818
wmc 132
mnd 3
bc 128
fnc 79
bpm 1.6202
cpm 1.6708
noi 8

9 Functions

Rating   Name   Duplication   Size   Complexity  
B Symphony.View.add(ꞌ/system/extensions/:context*:ꞌ) 0 29 1
B Symphony.View.add(ꞌ/publish/:context*:ꞌ) 0 102 1
A Symphony.View.add(ꞌ/blueprints/pages/:action:/:id:/:status:ꞌ) 0 3 1
A Symphony.View.add(ꞌ/blueprints/events/:action:/:name:/:status:/:*:ꞌ) 0 56 1
B Symphony.View.add(ꞌ/:context*:ꞌ) 0 200 2
B Symphony.View.add(ꞌ/blueprints/sections/:action:/:id:/:status:ꞌ) 0 257 4
B Symphony.View.add(ꞌ/blueprints/datasources/:action:/:id:/:status:/:*:ꞌ) 0 143 2
A Symphony.View.add(ꞌ/:context*:/newꞌ) 0 3 1
B Symphony.View.add(ꞌ/system/authors/:action:/:id:/:status:ꞌ) 0 43 5

How to fix   Complexity   

Complexity

Complex classes like symphony/assets/js/src/backend.views.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 backend views
3
 *
4
 * @package assets
5
 */
6
7
(function($, Symphony) {
8
9
/*--------------------------------------------------------------------------
10
	General backend view
11
--------------------------------------------------------------------------*/
12
13
Symphony.View.add('/:context*:', function() {
14
15
	// Initialise core plugins
16
	Symphony.Elements.contents.find('select.picker[data-interactive]').symphonyPickable();
17
	Symphony.Elements.contents.find('ul.orderable[data-interactive]').symphonyOrderable();
18
	Symphony.Elements.contents.find('table.selectable[data-interactive]').symphonySelectable();
19
	Symphony.Elements.wrapper.find('.filters-duplicator[data-interactive]').symphonyDuplicator();
20
	Symphony.Elements.wrapper.find('.tags[data-interactive]').symphonyTags();
21
	Symphony.Elements.wrapper.find('div.drawer').symphonyDrawer();
22
	Symphony.Elements.header.symphonyNotify();
23
24
	// Fix for Webkit browsers to initially show the options. #2127
25
	$('select[multiple=multiple]').scrollTop(0);
26
27
	// Initialise plugins inside duplicators
28
	Symphony.Elements.contents.find('.duplicator').on('constructshow.duplicator', '.instance', function() {
29
		// Enable tag lists inside duplicators
30
		$(this).find('.tags[data-interactive]').symphonyTags();
31
		// Enable parameter suggestions
32
		Symphony.Interface.Suggestions.init($(this), 'input[type="text"]');
33
	});
34
35
	// Navigation sizing
36
	Symphony.Elements.window.on('resize.admin nav.admin', function() {
37
		var content = Symphony.Elements.nav.find('ul.content'),
38
			structure = Symphony.Elements.nav.find('ul.structure'),
39
			width = content.width() + structure.width() + 20;
40
41
		// Compact mode
42
		if(width > window.innerWidth) {
43
			Symphony.Elements.nav.removeClass('wide');
44
		}
45
46
		// Wide mode
47
		else {
48
			Symphony.Elements.nav.addClass('wide');
49
		}
50
	}).trigger('nav.admin');
51
52
	// Accessible navigation
53
	Symphony.Elements.nav.on('focus.admin blur.admin', 'a', function() {
54
		$(this).parents('li').eq(1).toggleClass('current');
55
	});
56
57
	// Notifier sizing
58
	Symphony.Elements.window.on('resize.admin', function() {
59
		Symphony.Elements.header.find('.notifier').trigger('resize.notify');
60
	});
61
62
	// Table sizing
63
	Symphony.Elements.window.on('resize.admin table.admin', function() {
64
		var table = Symphony.Elements.contents.find('table:first');
65
66
		// Fix table size, if width exceeds the visibile viewport area.
67
		if(table.width() > Symphony.Elements.html.width()){
68
			table.addClass('fixed');
69
		}
70
		else {
71
			table.removeClass('fixed');
72
		}
73
	}).trigger('table.admin');
74
75
	// Orderable tables
76
	var oldSorting = null,
77
		orderable = Symphony.Elements.contents.find('table.orderable[data-interactive]');
78
79
	// Ignore tables with less than two rows
80
	orderable = orderable.filter(function() {
81
		return ($(this).find('tbody tr').length > 1);
82
	});
83
84
	// Initalise ordering
85
	orderable.symphonyOrderable({
86
			items: 'tr',
87
			handles: 'td'
88
		})
89
		.on('orderstart.orderable', function() {
90
			// Store current sort order
91
			oldSorting = orderable.find('input').map(function(e) { return this.name + '=' + (e + 1); }).get().join('&');
92
		})
93
		.on('orderstop.orderable', function() {
94
			var newSorting = orderable.find('input').map(function(e) { return this.name + '=' + (e + 1); }).get().join('&');
95
96
			// Store sort order, if changed
97
			if(oldSorting !== null && newSorting !== oldSorting) {
98
				// Update UI
99
				orderable.addClass('busy');
100
101
				// Update items
102
				orderable.trigger('orderupdate.admin');
103
104
				// Update old value
105
				oldSorting = newSorting;
106
107
				// Add XSRF token
108
				newSorting += '&' + Symphony.Utilities.getXSRF(true);
109
110
				// Send request
111
				$.ajax({
112
					type: 'POST',
113
					url: Symphony.Context.get('symphony') + '/ajax/reorder' + Symphony.Context.get('route'),
114
					data: newSorting,
115
					error: function() {
116
						Symphony.Message.post(Symphony.Language.get('Reordering was unsuccessful.'), 'error');
117
					},
118
					complete: function() {
119
						orderable.removeClass('busy').find('tr').removeClass('selected');
120
					}
121
				});
122
			}
123
		});
124
125
	// Suggest
126
	if(orderable.length) {
127
		Symphony.Elements.breadcrumbs.append('<p class="inactive"><span> – ' + Symphony.Language.get('drag to reorder') + '</span></p>');
128
	}
129
130
	// With Selected
131
	Symphony.Elements.contents.find('fieldset.apply').each(function() {
132
		var applicable = $(this),
133
			selection = Symphony.Elements.contents.find('table.selectable'),
134
			select = applicable.find('select'),
135
			button = applicable.find('button');
136
137
		// Set menu status
138
		if(selection.length > 0) {
139
			selection.on('select.selectable deselect.selectable check.selectable', 'tbody tr', function() {
140
141
				// Activate menu
142
				if(selection.has('.selected').length > 0) {
143
					applicable.removeClass('inactive');
144
					select.removeAttr('disabled');
145
				}
146
147
				// Deactivate menu
148
				else {
149
					applicable.addClass('inactive');
150
					select.attr('disabled', 'disabled');
151
				}
152
			});
153
154
			selection.find('tbody tr:first').trigger('check');
155
156
			// Respect menu state
157
			button.on('click.admin', function() {
158
				if(applicable.is('.inactive')) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if applicable.is(".inactive") 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...
159
					return false;
160
				}
161
			});
162
		}
163
	});
164
165
	// Confirm actions
166
	Symphony.Elements.contents.add(Symphony.Elements.context).on('click.admin', 'button.confirm', function() {
167
		var message = $(this).attr('data-message') || Symphony.Language.get('Are you sure you want to proceed?');
168
169
		return confirm(message);
170
	});
171
172
	// Confirm with selected actions
173
	Symphony.Elements.contents.find('> form').on('submit.admin', function() {
174
		var select = $('select[name="with-selected"]'),
175
			option = select.find('option:selected'),
176
			message = option.attr('data-message') ||  Symphony.Language.get('Are you sure you want to proceed?');
177
178
		// Needs confirmation
179
		if(option.is('.confirm')) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if option.is(".confirm") 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...
180
			return confirm(message);
181
		}
182
	});
183
184
	// Timestamp validation overwrite
185
	Symphony.Elements.header.find('.notifier .js-tv-overwrite').on('click.admin', function (e){
186
		var action = $(this).attr('data-action') || 'save';
187
		var hidden = Symphony.Elements.contents.find('input[name="action[ignore-timestamp]"]');
188
		hidden.prop('checked', true);
189
		e.preventDefault();
190
		e.stopPropagation();
191
		e.stopImmediatePropagation();
192
		// Click on the action button:
193
		// This is needed since we need to send the button's data in the POST
194
		Symphony.Elements.contents.find('> form').find('input, button')
195
			.filter('[name="action[' + action + ']"]').first().click();
196
		return false;
197
	});
198
199
	// Catch all JavaScript errors and write them to the Symphony Log
200
	Symphony.Elements.window.on('error.admin', function(event) {
201
		$.ajax({
202
			type: 'POST',
203
			url: Symphony.Context.get('symphony') + '/ajax/log/',
204
			data: {
205
				'error': event.originalEvent.message,
206
				'url': event.originalEvent.filename,
207
				'line': event.originalEvent.lineno,
208
				'xsrf': Symphony.Utilities.getXSRF()
209
			}
210
		});
211
	});
212
});
213
214
Symphony.View.add('/publish/:context*:', function() {
215
216
	// Filtering
217
	Symphony.Interface.Filtering.init();
218
219
	// Pagination
220
	Symphony.Elements.contents.find('.page').each(function() {
221
		var pagination = $(this),
222
			form = pagination.find('form'),
223
			jump = form.find('input'),
224
			active = jump.attr('data-active'),
225
			inactive = jump.attr('data-inactive'),
226
			helper = $('<span />').appendTo(form),
227
			width;
228
229
		// Measure placeholder text
230
		width = Math.max(helper.text(active).width(), helper.text(inactive).width());
231
		jump.width(width + 20);
232
		helper.remove();
233
234
		// Set current page
235
		jump.val(inactive);
236
237
		// Display "Go to page …" placeholder
238
		form.on('mouseover.admin', function() {
239
			if(!form.is('.active') && jump.val() == inactive) {
240
				jump.val(active);
241
			}
242
		});
243
244
		// Display current page placeholder
245
		form.on('mouseout.admin', function() {
246
			if(!form.is('.active') && jump.val() == active) {
247
				jump.val(inactive);
248
			}
249
		});
250
251
		// Edit page number
252
		jump.on('focus.admin', function() {
253
			if(jump.val() == active) {
254
				jump.val('');
255
			}
256
			form.addClass('active');
257
		});
258
259
		// Stop editing page number
260
		jump.on('blur.admin', function() {
261
262
			// Clear errors
263
			if(form.is('.invalid') || jump.val() === '') {
264
				form.removeClass('invalid');
265
				jump.val(inactive);
266
			}
267
268
			// Deactivate
269
			if(jump.val() == inactive) {
270
				form.removeClass('active');
271
			}
272
		});
273
274
		// Validate page number
275
		form.on('submit.admin', function() {
276
			if(parseInt(jump.val(), 10) > parseInt(jump.attr('data-max'), 10)) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if parseInt(jump.val(), 10)...p.attr("data-max"), 10) 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...
277
				form.addClass('invalid');
278
				return false;
279
			}
280
		});
281
	});
282
283
	// Upload field destructors
284
	$('<em />', {
285
		text: Symphony.Language.get('Remove File'),
286
		on: {
287
			click: function(event) {
288
				event.preventDefault();
289
290
				var span = $(this).parent(),
291
					name = span.find('input').attr('name');
292
293
				span.empty().append('<input name="' + name + '" type="file">');
294
			}
295
		}
296
	}).appendTo('label.file:has(a) span.frame');
297
298
	// Calendars
299
	$('.field-date').each(function() {
300
		var field = $(this),
301
			datetime = Symphony.Context.get('datetime'),
302
			calendar;
303
304
		// Add calendar widget
305
		if(field.attr('data-interactive')) {
306
			calendar = new Symphony.Interface.Calendar();
307
			calendar.init(this);
308
		}
309
310
		// Add timezone offset information
311
		if(moment().utcOffset() !== datetime['timezone-offset']) {
312
			field.addClass('show-timezone');
313
		}
314
	});
315
});
316
317
Symphony.View.add('/:context*:/new', function() {
318
	Symphony.Elements.contents.find('input[type="text"], textarea').first().focus();
319
});
320
321
/*--------------------------------------------------------------------------
322
	Blueprints - Pages Editor
323
--------------------------------------------------------------------------*/
324
325
Symphony.View.add('/blueprints/pages/:action:/:id:/:status:', function() {
326
	// No core interactions yet
327
});
328
329
/*--------------------------------------------------------------------------
330
	Blueprints - Sections
331
--------------------------------------------------------------------------*/
332
333
Symphony.View.add('/blueprints/sections/:action:/:id:/:status:', function(action, id, status) {
334
	var duplicator = $('#fields-duplicator'),
335
		legend = $('#fields-legend'),
336
		expand, collapse, toggle;
337
338
	// Create toggle controls
339
	expand = $('<a />', {
340
		'class': 'expand',
341
		'text': Symphony.Language.get('Expand all')
342
	});
343
	collapse = $('<a />', {
344
		'class': 'collapse',
345
		'text': Symphony.Language.get('Collapse all')
346
	});
347
	toggle = $('<p />', {
348
		'class': 'help toggle'
349
	});
350
351
	// Add toggle controls
352
	toggle.append(expand).append('<br />').append(collapse).insertAfter(legend);
353
354
	// Toggle fields
355
	toggle.on('click.admin', 'a.expand, a.collapse', function toggleFields() {
356
357
		// Expand
358
		if($(this).is('.expand')) {
359
			duplicator.trigger('expandall.collapsible');
360
		}
361
362
		// Collapse
363
		else {
364
			duplicator.trigger('collapseall.collapsible');
365
		}
366
	});
367
368
	// Affix for toggle
369
	$('fieldset.settings > legend + .help').symphonyAffix();
370
371
	// Initialise field editor
372
	duplicator.symphonyDuplicator({
373
		orderable: true,
374
		collapsible: true,
375
		preselect: 'input'
376
	});
377
378
	// Load section list
379
	duplicator.on('constructshow.duplicator', '.instance', function() {
380
		var instance = $(this),
381
			sections = instance.find('.js-fetch-sections'),
382
			sectionsParent = sections.parent(),
383
			selected = [],
384
			options;
385
386
		if(sections.length) {
387
			options = sections.find('option').each(function() {
0 ignored issues
show
Unused Code introduced by
The variable options seems to be never used. Consider removing it.
Loading history...
388
				selected.push(this.value);
389
390
				if(!isNaN(this.value)) {
391
					$(this).remove();
392
				}
393
			});
394
395
			$.ajax({
396
				type: 'GET',
397
				dataType: 'json',
398
				url: Symphony.Context.get('symphony') + '/ajax/sections/',
399
				success: function(result) {
400
					// offline DOM manipulation
401
					sections.detach();
402
403
					if(result.sections.length) {
404
						sections.prop('disabled', false);
405
					}
406
					var options = $();
407
408
					if (!sections.attr('data-required')) {
409
						// Allow de-selection, if permitted
410
						options = options.add($('<option />', {
411
							text: Symphony.Language.get('None'),
412
							value: ''
413
						}));
414
					}
415
416
					// Append sections
417
					$.each(result.sections, function(index, section) {
418
						var optgroup = $('<optgroup />', {
419
							label: section.name
420
						});
421
						options = options.add(optgroup);
422
						// Append fields
423
						$.each(section.fields, function(index, field) {
424
							var option = $('<option />', {
425
								value: field.id,
426
								text: field.name
427
							}).appendTo(optgroup);
428
429
							if($.inArray(field.id, selected) > -1) {
430
								option.prop('selected', true);
431
							}
432
						});
433
					});
434
					sections.append(options);
435
					sectionsParent.append(sections);
436
					sections.trigger('change.admin');
437
				}
438
			});
439
		}
440
	});
441
	duplicator.find('.instance').trigger('constructshow.duplicator');
442
443
	// Focus first input
444
	duplicator.on('constructshow.duplicator expandstop.collapsible', '.instance', function() {
445
		var item = $(this);
446
		if (!item.hasClass('js-animate-all')) {
447
			$(this).find('input:visible:first').trigger('focus.admin');
448
		}
449
	});
450
451
	// Update name
452
	duplicator.on('blur.admin input.admin', '.instance input[name*="[label]"]', function() {
453
		var label = $(this),
454
			value = label.val();
455
456
		// Empty label
457
		if(value === '') {
458
			value = Symphony.Language.get('Untitled Field');
459
		}
460
461
		// Update title
462
		label.parents('.instance').find('.frame-header strong').text(value);
463
	});
464
465
	// Update location
466
	duplicator.on('change.admin', '.instance select[name*="[location]"]', function() {
467
		var select = $(this);
468
469
		select.parents('.instance').find('.frame-header').removeClass('main').removeClass('sidebar').addClass(select.val());
470
	});
471
472
	// Update requirements
473
	duplicator.on('change.admin', '.instance input[name*="[required]"]', function() {
474
		var checkbox = $(this),
475
			headline = checkbox.parents('.instance').find('.frame-header h4');
476
477
		// Is required
478
		if(checkbox.is(':checked')) {
479
			$('<span />', {
480
				class: 'required',
481
				text: '— ' + Symphony.Language.get('required')
482
			}).appendTo(headline);
483
		}
484
485
		// Is not required
486
		else {
487
			headline.find('.required').remove();
488
		}
489
	});
490
	duplicator.find('.instance input[name*="[required]"]').trigger('change.admin');
491
492
	// Update select field
493
	duplicator.on('change.admin', '.instance select[name*="[dynamic_options]"]', function() {
494
		$(this).parents('.instance').find('[data-condition=associative]').toggle($.isNumeric(this.value));
495
	}).trigger('change.admin');
496
497
	// Update tag field
498
	duplicator.on('change.admin', '.instance select[name*="[pre_populate_source]"]', function() {
499
		var selected = $(this).val(),
500
			show = false;
501
		
502
		if(selected) {
503
			selected = jQuery.grep(selected, function(value) {
504
				return value != 'existing';
505
			});
506
507
			show = (selected.length > 0);
508
		}
509
510
		$(this).parents('.instance').find('[data-condition=associative]').toggle(show);
511
	}).trigger('change.admin');
512
513
	// Remove field
514
	duplicator.on('destructstart.duplicator', function(event) {
515
		var target = $(event.target),
516
			item = target.clone(),
517
			title = item.find('.frame-header strong').text(),
518
			type = item.find('.frame-header span').text(),
519
			index = target.index(),
520
			id = new Date().getTime();
521
522
		// Offer undo option after removing a field
523
		Symphony.Elements.header.find('div.notifier').trigger('attach.notify', [
524
			Symphony.Language.get('The field “{$title}” ({$type}) has been removed.', {
525
				title: title,
526
				type: type
527
			}) + '<a id="' + id + '">' + Symphony.Language.get('Undo?') + '</a>', 'protected undo']
528
		);
529
530
		// Prepare field recovery
531
		$('#' + id).data('field', item).data('preceding', index - 1).on('click.admin', function() {
532
			var undo = $(this),
533
				message = undo.parent(),
534
				field = undo.data('field').hide(),
535
				list = $('#fields-duplicator');
536
537
			// Add field
538
			list.parent().removeClass('empty');
539
			field.trigger('constructstart.duplicator');
540
			list.find('.instance:eq(' + undo.data('preceding') + ')').after(field);
541
			field.trigger('constructshow.duplicator');
542
			field.slideDown('fast', function() {
543
				field.trigger('constructstop.duplicator');
544
			});
545
546
			// Clear system message
547
			message.trigger('detach.notify');
548
		});
549
	});
550
551
	// Discard undo options because the field context changed
552
	duplicator.on('orderstop.orderable', function() {
553
		Symphony.Elements.header.find('.undo').trigger('detach.notify');
554
	});
555
556
	// Highlight instances with the same location when ordering fields
557
	duplicator.on('orderstart.orderable', function(event, item) {
558
		var duplicator = $(this),
559
			header = item.find('.frame-header'),
560
			position = (header.is('.main') ? 'main' : 'sidebar');
561
562
		duplicator.find('li:has(.' + position + ')').not(item).addClass('highlight');
563
	});
564
565
	duplicator.on('orderstop.orderable', function() {
566
		$(this).find('li.highlight').removeClass('highlight');
567
	});
568
569
	// Restore collapsible states for new sections
570
	if(status === 'created') {
571
		var fields = duplicator.find('.instance'),
572
			storageId = Symphony.Context.get('context-id');
573
574
		storageId = storageId.split('.');
575
		storageId.pop();
576
		storageId = 'symphony.collapsible.' + storageId.join('.') + '.0.collapsed';
577
578
		if(Symphony.Support.localStorage === true && window.localStorage[storageId]) {
579
			$.each(window.localStorage[storageId].split(','), function(index, value) {
580
				var collapsed = duplicator.find('.instance').eq(value);
581
				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...
582
					collapsed.trigger('collapse.collapsible', [0]);
583
				}
584
			});
585
586
			window.localStorage.removeItem(storageId);
587
		}
588
	}
589
});
590
591
/*--------------------------------------------------------------------------
592
	Blueprints - Datasource Editor
593
--------------------------------------------------------------------------*/
594
595
Symphony.View.add('/blueprints/datasources/:action:/:id:/:status:/:*:', function(action) {
596
	if(!action) return;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
597
598
	var context = $('#ds-context'),
599
		source = $('#ds-source'),
600
		name = Symphony.Elements.contents.find('input[name="fields[name]"]').attr('data-updated', 0),
601
		nameChangeCount = 0,
602
		params = Symphony.Elements.contents.find('select[name="fields[param][]"]'),
603
		pagination = Symphony.Elements.contents.find('.pagination'),
604
		paginationInput = pagination.find('input');
605
606
	// Update data source handle
607
	name.on('blur.admin input.admin', function updateDsHandle() {
608
		var current = nameChangeCount = nameChangeCount + 1,
609
		value = name.val();
610
611
		setTimeout(function fetchDsHandle(nameChangeCount, current, value) {
612
			if(nameChangeCount == current) {
613
				$.ajax({
614
					type: 'GET',
615
					data: { 'string': value },
616
					dataType: 'json',
617
					url: Symphony.Context.get('symphony') + '/ajax/handle/',
618
					success: function(result) {
619
						if(nameChangeCount == current) {
620
							name.data('handle', result.handle);
621
							params.trigger('update.admin');
622
						}
623
					}
624
				});
625
			}
626
		}, 500, nameChangeCount, current, value);
627
	})
628
	// Enable the default value for Data Source name
629
	.symphonyDefaultValue({
630
		sourceElement: context
631
	});
632
633
	// Update output parameters
634
	params.on('update.admin', function updateDsParams() {
635
		var handle = name.data('handle') || Symphony.Language.get('untitled');
636
637
		// Process parameters
638
		if(parseInt(name.attr('data-updated')) !== 0) {
639
			params.find('option').each(function updateDsParam() {
640
				var param = $(this),
641
					field = param.attr('data-handle');
642
643
				// Set parameter
644
				param.text('$ds-' + handle + '.' + field);
645
			});
646
		}
647
648
		// Updated
649
		name.attr('data-updated', 1);
650
	}).trigger('update.admin');
651
652
	// Data source manager options
653
	Symphony.Elements.contents.find('.contextual select optgroup').each(function() {
654
		var optgroup = $(this),
655
			select = optgroup.parents('select'),
656
			label = optgroup.attr('data-label'),
657
			options = optgroup.remove().find('option').addClass('optgroup');
658
659
		// Show only relevant options based on context
660
		context.on('change.admin', function() {
661
			var option = $(this).find('option:selected'),
662
				context = option.attr('data-context') || 'section-' + option.val();
663
664
			if(context == label) {
665
				select.find('option.optgroup').remove();
666
				select.append(options.clone(true));
667
			}
668
		});
669
	});
670
671
	// Data source manager context
672
	context.on('change.admin', function() {
673
		var optgroup = context.find('option:selected').parent(),
674
			label = optgroup.attr('data-label') || optgroup.attr('label'),
675
			reference = context.find('option:selected').attr('data-context') || 'section-' + context.val(),
676
			components = Symphony.Elements.contents.find('.contextual');
677
678
		// Store context
679
		source.val(context.val());
680
681
		// Show only relevant interface components based on context
682
		components.addClass('irrelevant');
683
		components.filter('[data-context~=' + label + ']').removeClass('irrelevant');
684
		components.filter('[data-context~=' + reference + ']').removeClass('irrelevant');
685
686
		// Make sure parameter names are up-to-date
687
		Symphony.Elements.contents.find('input[name="fields[name]"]').trigger('blur.admin');
688
	}).trigger('change.admin');
689
690
	// Toggle pagination
691
	Symphony.Elements.contents.find('input[name*=paginate_results]').on('change.admin', function() {
692
		var disabled = !$(this).is(':checked');
693
		paginationInput.prop('disabled', disabled);
694
	}).trigger('change.admin');
695
696
	// Enabled fields on submit
697
	Symphony.Elements.contents.find('> form').on('submit.admin', function() {
698
		paginationInput.prop('disabled', false);
699
	});
700
701
	// Enable parameter suggestions
702
	Symphony.Elements.contents.find('.ds-param').each(function() {
703
		Symphony.Interface.Suggestions.init(this, 'input[type="text"]');
704
	});
705
706
	// Toggle filter help
707
	Symphony.Elements.contents.find('.filters-duplicator').on('input.admin change.admin', 'input', function toggleFilterHelp(event) {
708
		var item = $(event.target).parents('.instance'),
709
			value = event.target.value,
710
			filters = item.data('filters'),
711
			help = item.find('.help');
712
713
		// Handle values that don't contain predicates
714
		var filter = value.search(/:/)
715
			? $.trim(value.split(':')[0])
716
			: $.trim(value);
717
718
		// Store filters
719
		if(!filters) {
720
			filters = {};
721
			item.find('.tags li').each(function() {
722
				var val = $.trim(this.getAttribute('data-value'));
723
				if (val.search(/:/)) {
724
					val = val.slice(0, -1);
725
				}
726
				filters[val] = this.getAttribute('data-help');
727
			});
728
729
			item.data('filters', filters);
730
		}
731
732
		// Filter help
733
		if(filters[filter]) {
734
			help.html(filters[filter]);
735
		}
736
	});
737
});
738
739
/*--------------------------------------------------------------------------
740
	Blueprints - Event Editor
741
--------------------------------------------------------------------------*/
742
743
Symphony.View.add('/blueprints/events/:action:/:name:/:status:/:*:', function() {
744
	var context = $('#event-context'),
745
		source = $('#event-source'),
746
		filters = $('#event-filters'),
747
		form = Symphony.Elements.contents.find('> form'),
0 ignored issues
show
Unused Code introduced by
The variable form seems to be never used. Consider removing it.
Loading history...
748
		name = Symphony.Elements.contents.find('input[name="fields[name]"]').attr('data-updated', 0),
749
		nameChangeCount = 0;
750
751
	// Update event handle
752
	name.on('blur.admin input.admin', function updateEventHandle() {
753
		var current = nameChangeCount = nameChangeCount + 1;
754
755
		setTimeout(function checkEventHandle(nameChangeCount, current) {
756
			if(nameChangeCount == current) {
757
				Symphony.Elements.contents.trigger('update.admin');
758
			}
759
		}, 500, nameChangeCount, current);
760
	})
761
	// Enable the default value for Event name
762
	.symphonyDefaultValue({
763
		sourceElement: context
764
	});
765
766
	// Change context
767
	context.on('change.admin', function changeEventContext() {
768
		source.val(context.val());
769
		Symphony.Elements.contents.trigger('update.admin');
770
	}).trigger('change.admin');
771
772
	// Change filters
773
	filters.on('change.admin', function changeEventFilters() {
774
		Symphony.Elements.contents.trigger('update.admin');
775
	});
776
777
	// Update documentation
778
	Symphony.Elements.contents.on('update.admin', function updateEventDocumentation() {
779
		if(name.val() == '') {
780
			$('#event-documentation').empty();
781
		}
782
		else {
783
			$.ajax({
784
				type: 'GET',
785
				data: {
786
					'section': context.val(),
787
					'filters': filters.serializeArray(),
788
					'name': name.val()
789
				},
790
				dataType: 'html',
791
				url: Symphony.Context.get('symphony') + '/ajax/eventdocumentation/',
792
				success: function(documentation) {
793
					$('#event-documentation').replaceWith(documentation);
794
				}
795
			});
796
		}
797
	});
798
});
799
800
/*--------------------------------------------------------------------------
801
	System - Authors
802
--------------------------------------------------------------------------*/
803
804
Symphony.View.add('/system/authors/:action:/:id:/:status:', function(action, id, status) {
805
	var password = $('#password');
806
807
	// Add change password overlay
808
	if(!password.has('.invalid').length && id && !status) {
809
		var overlay = $('<div class="password" />'),
810
			frame = $('<span class="frame centered" />'),
811
			button = $('<button />', {
812
				text: Symphony.Language.get('Change Password'),
813
				on: {
814
					click: function(event) {
815
						event.preventDefault();
816
						overlay.hide();
817
					}
818
				}
819
			}).attr('type', 'button');
820
821
		frame.append(button);
822
		overlay.append(frame);
823
		overlay.insertBefore(password);
824
	}
825
826
	// Focussed UI for password reset
827
	if(status == 'reset-password') {
828
		var fieldsets = Symphony.Elements.contents.find('fieldset'),
829
			essentials = fieldsets.eq(0),
830
			login = fieldsets.eq(1),
831
			legend = login.find('> legend');
832
833
		essentials.hide();
834
		login.children().not('legend, #password').hide();
835
836
		$('<p />', {
837
			class: 'help',
838
			text: Symphony.Language.get('Please reset your password')
839
		}).insertAfter(legend);
840
	}
841
842
	// Highlight confirmation promt
843
	Symphony.Elements.contents.find('input, select').on('change.admin input.admin', function() {
844
		$('#confirmation').addClass('highlight');
845
	});
846
});
847
848
/*--------------------------------------------------------------------------
849
	System - Extensions
850
--------------------------------------------------------------------------*/
851
Symphony.View.add('/system/extensions/:context*:', function() {
852
	Symphony.Language.add({
853
		'Enable': false,
854
		'Install': false,
855
		'Update': false
856
	});
857
858
	// Update controls contextually
859
	Symphony.Elements.contents.find('.actions select').on('focus.admin', function(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...
860
		var selected = Symphony.Elements.contents.find('tr.selected'),
861
			canUpdate = selected.filter('.extension-can-update').length,
862
			canInstall = selected.filter('.extension-can-install').length,
863
			canEnable = selected.length - canUpdate - canInstall,
864
			control = Symphony.Elements.contents.find('.actions option[value="enable"]'),
865
			label = [];
866
867
		if(canEnable) {
868
			label.push(Symphony.Language.get('Enable'));
869
		}
870
		if(canUpdate) {
871
			label.push(Symphony.Language.get('Update'));
872
		}
873
		if(canInstall) {
874
			label.push(Symphony.Language.get('Install'));
875
		}
876
877
		control.text(label.join('/'));
878
	});
879
});
880
881
})(window.jQuery, window.Symphony);
882