Passed
Pull Request — master (#99)
by Daniel
34:06
created

js/admin.js   B

Complexity

Total Complexity 49
Complexity/F 1.36

Size

Lines of Code 399
Function Count 36

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
wmc 49
eloc 185
c 0
b 0
f 0
dl 0
loc 399
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) {
114
				throw signature + ': No valid system item template given';
115
			}
116
			if (!this.$customTemplate.length) {
117
				throw signature + ': No valid custom item template given';
118
			}
119
120
			this._initStaticItems();
121
		},
122
123
		/**
124
		 * @protected
125
		 */
126
		_initStaticItems: function () {
127
			var $content = this.$staticTemplate.octemplate() || $(),
128
				filter = this.$staticTemplate.data('filter') || '*',
129
				that = this;
130
131
			this.staticItems = [];
132
			$content.filter(filter).each(function () {
133
				var $itemTemplate = $(this),
134
					itemData = {};
135
136
				if (that.$staticTemplate.data('replaces')) {
137
					$itemTemplate.data('replaces', that.$staticTemplate.data('replaces'));
138
				}
139
				if (that.$staticTemplate.data('appendTo')) {
140
					$itemTemplate.data('appendTo', that.$staticTemplate.data('appendTo'));
141
				}
142
143
				$.each($itemTemplate.data(), function (key, value) {
144
					if (key.substr(0, 4) === 'item') {
145
						key = key[4].toLowerCase() + key.substr(5);
146
						itemData[key] = value;
147
					}
148
				});
149
150
				that.staticItems.push({
151
					'$itemTemplate': $itemTemplate,
152
					'itemData': itemData
153
				});
154
			});
155
		},
156
157
		/**
158
		 * @public
159
		 *
160
		 * @param {Object}            data
161
		 * @param {Object[]|string[]} data.systemItems
162
		 * @param {Object[]|string[]} data.customItems
163
		 * @param {Object[]|string[]} data.newItems
164
		 */
165
		update: function (data) {
166
			var that = this;
167
168
			this.systemItems = data.systemItems;
169
			this.customItems = data.customItems;
170
			this.newItems = data.newItems;
171
172
			this._content(this.$template);
173
174
			$.each(this.staticItems, function (_, data) {
175
				var $item = that._content(data.$itemTemplate, data.itemData);
176
				that._setupItem($item, data.itemData);
177
			});
178
179
			$.each(this.systemItems, function (_, value) {
180
				var itemData = (typeof value === 'object') ? value : { name: value },
181
					$item = that._content(that.$systemTemplate, itemData);
182
				that._setupItem($item, itemData);
183
			});
184
185
			$.each(this.customItems, function (_, value) {
186
				var itemData = (typeof value === 'object') ? value : { name: value },
187
					$item = that._content(that.$customTemplate, itemData);
188
				that._setupItem($item, itemData);
189
			});
190
191
			$.each(this.newItems, function (_, value) {
192
				var itemData = (typeof value === 'object') ? value : { name: value },
193
					$item = that._content(that.$newTemplate, itemData);
194
				that._setupItem($item, itemData);
195
			});
196
197
			this._setup();
198
		},
199
200
		/**
201
		 * @protected
202
		 */
203
		_setup: function () {
204
			var $newItem = this.$element.find('.action-new-item'),
205
				$newItemButton = this.$element.find('.action-new'),
206
				that = this;
207
208
			if ($newItem.val()) {
209
				$newItemButton.on('click.CMSPicoAdminList', function (event) {
210
					event.preventDefault();
211
					that._api('POST', '', { item: $newItem.val() });
212
				});
213
			} else {
214
				$newItemButton.add($newItem).prop('disabled', true);
215
			}
216
217
			this.$element.find('.action-reload').on('click.CMSPicoAdminList', function (event) {
218
				event.preventDefault();
219
				that.reload();
220
			});
221
		},
222
223
		/**
224
		 * @protected
225
		 *
226
		 * @param {jQuery}  $item
227
		 * @param {Object}  itemData
228
		 * @param {string}  itemData.name
229
		 * @param {boolean} [itemData.compat]
230
		 * @param {string}  [itemData.compatReason]
231
		 * @param {Object}  [itemData.compatReasonData]
232
		 */
233
		_setupItem: function ($item, itemData) {
234
			var that = this;
235
236
			$item.find('.info-compat').each(function () {
237
				var $this = $(this),
238
					$icon = $this.find('[class^="icon-"], [class*=" icon-"]'),
239
					compat = (itemData.compat === undefined) || !!itemData.compat;
240
241
				$this.data('value', compat);
242
243
				$icon
244
					.addClass(compat ? 'icon-checkmark' : 'icon-error-color')
245
					.removeClass(compat ? 'icon-error-color' : 'icon-checkmark');
246
247
				if ($icon.hasClass('has-tooltip')) {
248
					var compatReason = $icon.prop('title') || '';
249
					if (itemData.compatReason) {
250
						var rawCompatReason = OCA.CMSPico.Util.unescape(itemData.compatReason);
251
						compatReason = t('cms_pico', rawCompatReason, itemData.compatReasonData);
252
					}
253
254
					$icon
255
						.tooltip('dispose')
256
						.attr('title', compatReason)
257
						.tooltip();
258
				}
259
			});
260
261
			$item.find('.action-sync').on('click.CMSPicoAdminList', function (event) {
262
				event.preventDefault();
263
				that._api('POST', itemData.name);
264
			});
265
266
			$item.find('.action-copy').each(function () {
267
				var $this = $(this);
268
269
				var dialog = new OCA.CMSPico.Dialog(that.$copyTemplate, {
270
					title: $this.data('originalTitle') || $this.prop('title') || $this.text(),
271
					templateData: { source: itemData.name },
272
					buttons: [
273
						{ type: OCA.CMSPico.Dialog.BUTTON_ABORT },
274
						{
275
							type: OCA.CMSPico.Dialog.BUTTON_SUBMIT,
276
							text: t('cms_pico', 'Copy')
277
						}
278
					]
279
				});
280
281
				dialog.on('open.CMSPicoAdminList', function () {
282
					this.$element.find('.input-name').focus();
283
				});
284
285
				dialog.on('submit.CMSPicoAdminList', function () {
286
					var value = this.$element.find('.input-name').val();
287
					that._api('CLONE', itemData.name, { name: value });
288
				});
289
290
				$this.on('click.CMSPicoAdminList', function (event) {
291
					event.preventDefault();
292
					dialog.open();
293
				});
294
			});
295
296
			$item.find('.action-delete').on('click.CMSPicoAdminList', function (event) {
297
				event.preventDefault();
298
				that._api('DELETE', itemData.name);
299
			});
300
		}
301
	});
302
303
	$('.picocms-admin-list').each(function () {
304
		var $this = $(this),
305
			adminList = new OCA.CMSPico.AdminList($this);
306
307
		$this.data('CMSPicoAdminList', adminList);
308
		adminList.reload();
309
	});
310
311
	/**
312
	 * @class
313
	 * @extends OCA.CMSPico.Form
314
	 *
315
	 * @param {jQuery} $element
316
	 * @param {Object} [options]
317
	 * @param {string} [options.route]
318
	 */
319
	OCA.CMSPico.LimitGroupsForm = function ($element, options) {
320
		this.initialize($element, options);
321
	};
322
323
	/**
324
	 * @lends OCA.CMSPico.LimitGroupsForm.prototype
325
	 */
326
	OCA.CMSPico.LimitGroupsForm.prototype = $.extend({}, OCA.CMSPico.Form.prototype, {
327
		/**
328
		 * @public
329
		 */
330
		prepare: function () {
331
			var that = this,
332
				$input = this.$element.find('input');
333
334
			// loading order is crucial - and Nextcloud loads its own JS settings files last... m(
335
			$(function () {
336
				OC.Settings.setupGroupsSelect($input);
337
338
				$input.on('change.CMSPicoLimitGroupsForm', function (event) {
339
					that.submit();
340
				});
341
			});
342
		},
343
344
		/**
345
		 * @public
346
		 */
347
		submit: function () {
348
			var $input = this.$element.find(':input'),
349
				data = this.$element.serialize();
350
351
			$input.prop('disabled', true);
352
353
			$.ajax({
354
				method: 'POST',
355
				url: OC.generateUrl(this.route),
356
				data: data
357
			}).done(function (data, textStatus, jqXHR) {
358
				$input.prop('disabled', false);
359
			});
360
		}
361
	});
362
363
	$('.picocms-limit_groups-form').each(function () {
364
		var $this = $(this),
365
			limitGroupsForm = new OCA.CMSPico.LimitGroupsForm($this);
366
367
		$this.data('CMSPicoLimitGroupsForm', limitGroupsForm);
368
		limitGroupsForm.prepare();
369
	});
370
371
	/**
372
	 * @class
373
	 * @extends OCA.CMSPico.Form
374
	 *
375
	 * @param {jQuery} $element
376
	 * @param {Object} [options]
377
	 * @param {string} [options.route]
378
	 */
379
	OCA.CMSPico.LinkModeForm = function ($element, options) {
380
		this.initialize($element, options);
381
	};
382
383
	/**
384
	 * @lends OCA.CMSPico.LinkModeForm.prototype
385
	 */
386
	OCA.CMSPico.LinkModeForm.prototype = $.extend({}, OCA.CMSPico.Form.prototype, {
387
		/**
388
		 * @public
389
		 */
390
		prepare: function () {
391
			var that = this,
392
				$input = this.$element.find('input[type="radio"]');
393
394
			$input.on('change.CMSPicoLinkModeForm', function (event) {
395
				that.submit();
396
			});
397
		},
398
399
		/**
400
		 * @public
401
		 */
402
		submit: function () {
403
			var $input = this.$element.find(':input'),
404
				data = this.$element.serialize();
405
406
			$input.prop('disabled', true);
407
408
			$.ajax({
409
				method: 'POST',
410
				url: OC.generateUrl(this.route),
411
				data: data
412
			}).done(function (data, textStatus, jqXHR) {
413
				$input.prop('disabled', false);
414
			});
415
		}
416
	});
417
418
	$('.picocms-link_mode-form').each(function () {
419
		var $this = $(this),
420
			linkModeForm = new OCA.CMSPico.LinkModeForm($this);
421
422
		$this.data('CMSPicoLinkModeForm', linkModeForm);
423
		linkModeForm.prepare();
424
	});
425
})(document, jQuery, OC, OCA);
426