Passed
Pull Request — master (#99)
by Daniel
26:12 queued 03:19
created

js/admin.js   B

Complexity

Total Complexity 49
Complexity/F 1.36

Size

Lines of Code 395
Function Count 36

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 49
eloc 183
c 0
b 0
f 0
dl 0
loc 395
rs 8.48
mnd 13
bc 13
fnc 36
bpm 0.361
cpm 1.3611
noi 0

How to fix   Complexity   

Complexity

Complex classes like js/admin.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
 * CMS Pico - Create websites using Pico CMS for Nextcloud.
3
 *
4
 * @copyright Copyright (c) 2017, Maxence Lange (<[email protected]>)
5
 * @copyright Copyright (c) 2019, Daniel Rudolf (<[email protected]>)
6
 *
7
 * @license GNU AGPL version 3 or any later version
8
 *
9
 * This program is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License as
11
 * published by the Free Software Foundation, either version 3 of the
12
 * License, or (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU Affero General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Affero General Public License
20
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
/** global: OC */
24
/** global: OCA */
25
/** global: jQuery */
26
27
(function (document, $, OC, OCA) {
28
	'use strict';
29
30
	/**
31
	 * @class
32
	 * @extends OCA.CMSPico.List
33
	 *
34
	 * @param {jQuery}        $element
35
	 * @param {Object}        [options]
36
	 * @param {string}        [options.route]
37
	 * @param {jQuery|string} [options.template]
38
	 * @param {jQuery|string} [options.systemTemplate]
39
	 * @param {jQuery|string} [options.customTemplate]
40
	 * @param {jQuery|string} [options.newTemplate]
41
	 * @param {jQuery|string} [options.copyTemplate]
42
	 * @param {jQuery|string} [options.loadingTemplate]
43
	 * @param {jQuery|string} [options.errorTemplate]
44
	 */
45
	OCA.CMSPico.AdminList = function ($element, options) {
46
		this.initialize($element, options);
47
	};
48
49
	/**
50
	 * @lends OCA.CMSPico.AdminList.prototype
51
	 */
52
	OCA.CMSPico.AdminList.prototype = $.extend({}, OCA.CMSPico.List.prototype, {
53
		/** @member {Object[]|string[]} */
54
		staticItems: [],
55
56
		/** @member {Object[]|string[]} */
57
		systemItems: [],
58
59
		/** @member {Object[]|string[]} */
60
		customItems: [],
61
62
		/** @member {Object[]|string[]} */
63
		newItems: [],
64
65
		/** @member {jQuery} */
66
		$staticTemplate: $(),
67
68
		/** @member {jQuery} */
69
		$systemTemplate: $(),
70
71
		/** @member {jQuery} */
72
		$customTemplate: $(),
73
74
		/** @member {jQuery} */
75
		$newTemplate: $(),
76
77
		/** @member {jQuery} */
78
		$copyTemplate: $(),
79
80
		/**
81
		 * @constructs
82
		 *
83
		 * @param {jQuery}        $element
84
		 * @param {Object}        [options]
85
		 * @param {string}        [options.route]
86
		 * @param {jQuery|string} [options.template]
87
		 * @param {jQuery|string} [options.staticTemplate]
88
		 * @param {jQuery|string} [options.systemTemplate]
89
		 * @param {jQuery|string} [options.customTemplate]
90
		 * @param {jQuery|string} [options.newTemplate]
91
		 * @param {jQuery|string} [options.copyTemplate]
92
		 * @param {jQuery|string} [options.loadingTemplate]
93
		 * @param {jQuery|string} [options.errorTemplate]
94
		 */
95
		initialize: function ($element, options) {
96
			OCA.CMSPico.List.prototype.initialize.apply(this, arguments);
97
98
			options = $.extend({
99
				staticTemplate: $element.data('staticTemplate'),
100
				systemTemplate: $element.data('systemTemplate'),
101
				customTemplate: $element.data('customTemplate'),
102
				newTemplate: $element.data('newTemplate'),
103
				copyTemplate: $element.data('copyTemplate')
104
			}, options);
105
106
			this.$staticTemplate = $(options.staticTemplate);
107
			this.$systemTemplate = $(options.systemTemplate);
108
			this.$customTemplate = $(options.customTemplate);
109
			this.$newTemplate = $(options.newTemplate);
110
			this.$copyTemplate = $(options.copyTemplate);
111
112
			var signature = 'OCA.CMSPico.AdminList.initialize()';
113
			if (!this.$systemTemplate.length) throw signature + ': No valid system item template given';
114
			if (!this.$customTemplate.length) throw signature + ': No valid custom item template given';
115
116
			this._initStaticItems();
117
		},
118
119
		/**
120
		 * @protected
121
		 */
122
		_initStaticItems: function () {
123
			var $content = this.$staticTemplate.octemplate() || $(),
124
				filter = this.$staticTemplate.data('filter') || '*',
125
				that = this;
126
127
			this.staticItems = [];
128
			$content.filter(filter).each(function () {
129
				var $itemTemplate = $(this),
130
					itemData = {};
131
132
				if (that.$staticTemplate.data('replaces')) {
133
					$itemTemplate.data('replaces', that.$staticTemplate.data('replaces'));
134
				}
135
				if (that.$staticTemplate.data('appendTo')) {
136
					$itemTemplate.data('appendTo', that.$staticTemplate.data('appendTo'));
137
				}
138
139
				$.each($itemTemplate.data(), function (key, value) {
140
					if (key.substr(0, 4) === 'item') {
141
						key = key[4].toLowerCase() + key.substr(5);
142
						itemData[key] = value;
143
					}
144
				});
145
146
				that.staticItems.push({
147
					'$itemTemplate': $itemTemplate,
148
					'itemData': itemData
149
				});
150
			});
151
		},
152
153
		/**
154
		 * @public
155
		 *
156
		 * @param {Object}            data
157
		 * @param {Object[]|string[]} data.systemItems
158
		 * @param {Object[]|string[]} data.customItems
159
		 * @param {Object[]|string[]} data.newItems
160
		 */
161
		update: function (data) {
162
			var that = this;
163
164
			this.systemItems = data.systemItems;
165
			this.customItems = data.customItems;
166
			this.newItems = data.newItems;
167
168
			this._content(this.$template);
169
170
			$.each(this.staticItems, function (_, data) {
171
				var $item = that._content(data.$itemTemplate, data.itemData);
172
				that._setupItem($item, data.itemData);
173
			});
174
175
			$.each(this.systemItems, function (_, value) {
176
				var itemData = (typeof value === 'object') ? value : { name: value },
177
					$item = that._content(that.$systemTemplate, itemData);
178
				that._setupItem($item, itemData);
179
			});
180
181
			$.each(this.customItems, function (_, value) {
182
				var itemData = (typeof value === 'object') ? value : { name: value },
183
					$item = that._content(that.$customTemplate, itemData);
184
				that._setupItem($item, itemData);
185
			});
186
187
			$.each(this.newItems, function (_, value) {
188
				var itemData = (typeof value === 'object') ? value : { name: value },
189
					$item = that._content(that.$newTemplate, itemData);
190
				that._setupItem($item, itemData);
191
			});
192
193
			this._setup();
194
		},
195
196
		/**
197
		 * @protected
198
		 */
199
		_setup: function () {
200
			var $newItem = this.$element.find('.action-new-item'),
201
				$newItemButton = this.$element.find('.action-new'),
202
				that = this;
203
204
			if ($newItem.val()) {
205
				$newItemButton.on('click.CMSPicoAdminList', function (event) {
206
					event.preventDefault();
207
					that._api('POST', '', { item: $newItem.val() });
208
				});
209
			} else {
210
				$newItemButton.add($newItem).prop('disabled', true);
211
			}
212
213
			this.$element.find('.action-reload').on('click.CMSPicoAdminList', function (event) {
214
				event.preventDefault();
215
				that.reload();
216
			});
217
		},
218
219
		/**
220
		 * @protected
221
		 *
222
		 * @param {jQuery}  $item
223
		 * @param {Object}  itemData
224
		 * @param {string}  itemData.name
225
		 * @param {boolean} [itemData.compat]
226
		 * @param {string}  [itemData.compatReason]
227
		 * @param {Object}  [itemData.compatReasonData]
228
		 */
229
		_setupItem: function ($item, itemData) {
230
			var that = this;
231
232
			$item.find('.info-compat').each(function () {
233
				var $this = $(this),
234
					$icon = $this.find('[class^="icon-"], [class*=" icon-"]'),
235
					compat = (itemData.compat === undefined) || !!itemData.compat;
236
237
				$this.data('value', compat);
238
239
				$icon
240
					.addClass(compat ? 'icon-checkmark' : 'icon-error-color')
241
					.removeClass(compat ? 'icon-error-color' : 'icon-checkmark');
242
243
				if ($icon.hasClass('has-tooltip')) {
244
					var compatReason = $icon.prop('title') || '';
245
					if (itemData.compatReason) {
246
						var rawCompatReason = OCA.CMSPico.Util.unescape(itemData.compatReason);
247
						compatReason = t('cms_pico', rawCompatReason, itemData.compatReasonData);
248
					}
249
250
					$icon
251
						.tooltip('dispose')
252
						.attr('title', compatReason)
253
						.tooltip();
254
				}
255
			});
256
257
			$item.find('.action-sync').on('click.CMSPicoAdminList', function (event) {
258
				event.preventDefault();
259
				that._api('POST', itemData.name);
260
			});
261
262
			$item.find('.action-copy').each(function () {
263
				var $this = $(this);
264
265
				var dialog = new OCA.CMSPico.Dialog(that.$copyTemplate, {
266
					title: $this.data('originalTitle') || $this.prop('title') || $this.text(),
267
					templateData: { source: itemData.name },
268
					buttons: [
269
						{ type: OCA.CMSPico.Dialog.BUTTON_ABORT },
270
						{
271
							type: OCA.CMSPico.Dialog.BUTTON_SUBMIT,
272
							text: t('cms_pico', 'Copy')
273
						}
274
					]
275
				});
276
277
				dialog.on('open.CMSPicoAdminList', function () {
278
					this.$element.find('.input-name').focus();
279
				});
280
281
				dialog.on('submit.CMSPicoAdminList', function () {
282
					var value = this.$element.find('.input-name').val();
283
					that._api('CLONE', itemData.name, { name: value });
284
				});
285
286
				$this.on('click.CMSPicoAdminList', function (event) {
287
					event.preventDefault();
288
					dialog.open();
289
				});
290
			});
291
292
			$item.find('.action-delete').on('click.CMSPicoAdminList', function (event) {
293
				event.preventDefault();
294
				that._api('DELETE', itemData.name);
295
			});
296
		}
297
	});
298
299
	$('.picocms-admin-list').each(function () {
300
		var $this = $(this),
301
			adminList = new OCA.CMSPico.AdminList($this);
302
303
		$this.data('CMSPicoAdminList', adminList);
304
		adminList.reload();
305
	});
306
307
	/**
308
	 * @class
309
	 * @extends OCA.CMSPico.Form
310
	 *
311
	 * @param {jQuery} $element
312
	 * @param {Object} [options]
313
	 * @param {string} [options.route]
314
	 */
315
	OCA.CMSPico.LimitGroupsForm = function ($element, options) {
316
		this.initialize($element, options);
317
	};
318
319
	/**
320
	 * @lends OCA.CMSPico.LimitGroupsForm.prototype
321
	 */
322
	OCA.CMSPico.LimitGroupsForm.prototype = $.extend({}, OCA.CMSPico.Form.prototype, {
323
		/**
324
		 * @public
325
		 */
326
		prepare: function () {
327
			var that = this,
328
				$input = this.$element.find('input');
329
330
			// loading order is crucial - and Nextcloud loads its own JS settings files last... m(
331
			$(function () {
332
				OC.Settings.setupGroupsSelect($input);
333
334
				$input.on('change.CMSPicoLimitGroupsForm', function (event) {
335
					that.submit();
336
				});
337
			});
338
		},
339
340
		/**
341
		 * @public
342
		 */
343
		submit: function () {
344
			var $input = this.$element.find(':input'),
345
				data = this.$element.serialize();
346
347
			$input.prop('disabled', true);
348
349
			$.ajax({
350
				method: 'POST',
351
				url: OC.generateUrl(this.route),
352
				data: data
353
			}).done(function (data, textStatus, jqXHR) {
354
				$input.prop('disabled', false);
355
			});
356
		}
357
	});
358
359
	$('.picocms-limit_groups-form').each(function () {
360
		var $this = $(this),
361
			limitGroupsForm = new OCA.CMSPico.LimitGroupsForm($this);
362
363
		$this.data('CMSPicoLimitGroupsForm', limitGroupsForm);
364
		limitGroupsForm.prepare();
365
	});
366
367
	/**
368
	 * @class
369
	 * @extends OCA.CMSPico.Form
370
	 *
371
	 * @param {jQuery} $element
372
	 * @param {Object} [options]
373
	 * @param {string} [options.route]
374
	 */
375
	OCA.CMSPico.LinkModeForm = function ($element, options) {
376
		this.initialize($element, options);
377
	};
378
379
	/**
380
	 * @lends OCA.CMSPico.LinkModeForm.prototype
381
	 */
382
	OCA.CMSPico.LinkModeForm.prototype = $.extend({}, OCA.CMSPico.Form.prototype, {
383
		/**
384
		 * @public
385
		 */
386
		prepare: function () {
387
			var that = this,
388
				$input = this.$element.find('input[type="radio"]');
389
390
			$input.on('change.CMSPicoLinkModeForm', function (event) {
391
				that.submit();
392
			});
393
		},
394
395
		/**
396
		 * @public
397
		 */
398
		submit: function () {
399
			var $input = this.$element.find(':input'),
400
				data = this.$element.serialize();
401
402
			$input.prop('disabled', true);
403
404
			$.ajax({
405
				method: 'POST',
406
				url: OC.generateUrl(this.route),
407
				data: data
408
			}).done(function (data, textStatus, jqXHR) {
409
				$input.prop('disabled', false);
410
			});
411
		}
412
	});
413
414
	$('.picocms-link_mode-form').each(function () {
415
		var $this = $(this),
416
			linkModeForm = new OCA.CMSPico.LinkModeForm($this);
417
418
		$this.data('CMSPicoLinkModeForm', linkModeForm);
419
		linkModeForm.prepare();
420
	});
421
})(document, jQuery, OC, OCA);
422