Completed
Push — master ( dd0888...3b0b80 )
by Maxence
07:17
created

nav.generateDivProvider   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 83

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 83
rs 8.4888
cc 4
nc 8
nop 2

3 Functions

Rating   Name   Duplication   Size   Complexity  
A 0 14 2
A 0 14 2
A 0 3 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
/*
2
 * FullTextSearch - Full text search framework for Nextcloud
3
 *
4
 * This file is licensed under the Affero General Public License version 3 or
5
 * later. See the COPYING file.
6
 *
7
 * @author Maxence Lange <[email protected]>
8
 * @copyright 2018
9
 * @license GNU AGPL version 3 or any later version
10
 *
11
 * This program is free software: you can redistribute it and/or modify
12
 * it under the terms of the GNU Affero General Public License as
13
 * published by the Free Software Foundation, either version 3 of the
14
 * License, or (at your option) any later version.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU Affero General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU Affero General Public License
22
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
 *
24
 */
25
26
/** global: OCA */
27
/** global: api */
28
/** global: search */
29
/** global: result */
30
/** global: settings */
31
32
33
34
var curr = {
35
	providerResult: [],
36
	page: 1,
37
	lastRequest: '',
38
	lastRequestTimer: null,
39
	lastRequestTimerQueued: false,
40
	lastRequestTimerForcing: false,
41
42
	setProviderResult: function (id, value) {
43
		curr.providerResult[id] = value;
44
	},
45
46
	getProviderResult: function (id) {
47
		var current = curr.providerResult[id];
48
		if (!current) {
49
			current = [];
50
		}
51
52
		return current;
53
	}
54
55
};
56
57
58
var nav = {
59
		manageDivProviderNavigation: function (divProviderNavigation, request, meta) {
60
61
			var maxPage = Math.ceil(meta.total / request.size);
62
63
			divProviderNavigation.attr('data-time', meta.time);
64
			divProviderNavigation.attr('data-page', request.page);
65
			divProviderNavigation.attr('data-options', JSON.stringify(request.options));
66
			divProviderNavigation.attr('data-search', request.search);
67
			divProviderNavigation.attr('data-max-page', maxPage);
68
			divProviderNavigation.attr('data-size', request.size);
69
			divProviderNavigation.attr('data-total', meta.total);
70
71
			var providerTitle = divProviderNavigation.attr('data-provider-title');
72
			var left = "the search in " + providerTitle + " for '" + request.search + "' returned " +
73
				meta.total + " results in " + meta.time + "ms";
74
			divProviderNavigation.find('.provider_navigation_left').text(left);
75
76
			if (maxPage > 1) {
77
				divProviderNavigation.find('.provider_navigation_curr').text(request.page + ' / ' +
78
					maxPage).stop().fadeTo(200, 1);
79
80
				divProviderNavigation.find('.provider_navigation_prev').stop().fadeTo(200,
81
					(request.page > 1) ? 1 : 0);
82
				divProviderNavigation.find('.provider_navigation_next').stop().fadeTo(200,
83
					(request.page < maxPage) ? 1 : 0);
84
			} else {
85
				divProviderNavigation.find('.provider_navigation_prev').stop().fadeTo(200, 0);
86
				divProviderNavigation.find('.provider_navigation_curr').stop().fadeTo(200, 0);
87
				divProviderNavigation.find('.provider_navigation_next').stop().fadeTo(200, 0);
88
			}
89
		},
90
91
92
		manageDivProviderResult: function (divProviderResult, newResult, oldResult) {
93
			//replaceWith();
94
			nav.divProviderResultAddItems(divProviderResult, newResult, oldResult);
95
			if (oldResult) {
96
				nav.divProviderResultRemoveItems(divProviderResult, newResult, oldResult);
97
				nav.divProviderResultMoveItems(divProviderResult, newResult, oldResult);
98
			}
99
		},
100
101
102
		divProviderResultAddItems: function (divProviderResult, newResult, oldResult) {
103
104
			var precItem = null;
105
			for (var i = 0; i < newResult.length; i++) {
106
				var entry = newResult[i];
107
				if (result.getResultIndex(entry.id, oldResult) > -1) {
108
					precItem = nav.getDivEntry(entry.id, divProviderResult);
109
					nav.fillDivEntry(precItem, entry);
110
					continue;
111
				}
112
113
				var divResult = nav.generateDivEntry(entry, nav.generateTemplateEntry(entry));
114
				if (precItem === null) {
115
					divProviderResult.prepend(divResult);
116
				} else {
117
					precItem.after(divResult);
118
				}
119
120
				divResult.slideDown(settings.delay_result, function () {
0 ignored issues
show
Bug introduced by
It is generally not recommended to make functions within a loop.

While making functions in a loop will not lead to any runtime error, the code might not behave as you expect as the variables in the scope are not imported by value, but by reference. Let’s take a look at an example:

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(function() {
        alert(i);
    });
}

funcs[0](); // alert(10);
funcs[1](); // alert(10);
/// ...
funcs[9](); // alert(10);

If you would instead like to bind the function inside the loop to the value of the variable during that specific iteration, you can create the function from another function:

var createFunc = function(i) {
    return function() {
        alert(i);
    };
};

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(createFunc(i));
}

funcs[0](); // alert(0)
funcs[1](); // alert(1)
// ...
funcs[9](); // alert(9)
Loading history...
121
					$(this).children('.result_template').fadeTo(settings.delay_result, 1);
122
				});
123
124
				precItem = divResult;
125
			}
126
127
		},
128
129
130
		divProviderResultRemoveItems: function (divProviderResult, newResult, oldResult) {
131
			for (var i = 0; i < oldResult.length; i++) {
132
				var entry = oldResult[i];
133
				if (result.getResultIndex(entry.id, newResult) === -1) {
134
					var divResult = nav.getDivEntry(entry.id, divProviderResult);
135
					divResult.fadeTo(settings.delay_result, 0, function () {
0 ignored issues
show
Bug introduced by
It is generally not recommended to make functions within a loop.

While making functions in a loop will not lead to any runtime error, the code might not behave as you expect as the variables in the scope are not imported by value, but by reference. Let’s take a look at an example:

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(function() {
        alert(i);
    });
}

funcs[0](); // alert(10);
funcs[1](); // alert(10);
/// ...
funcs[9](); // alert(10);

If you would instead like to bind the function inside the loop to the value of the variable during that specific iteration, you can create the function from another function:

var createFunc = function(i) {
    return function() {
        alert(i);
    };
};

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(createFunc(i));
}

funcs[0](); // alert(0)
funcs[1](); // alert(1)
// ...
funcs[9](); // alert(9)
Loading history...
136
						$(this).slideUp(settings.delay_result, function () {
137
							$(this).remove();
138
						});
139
					});
140
				}
141
			}
142
		},
143
144
145
		divProviderResultMoveItems: function (divProviderResult, newResult, oldResult) {
146
147
			var precId = '';
148
149
			oldResult = result.recalibrateResult(oldResult, newResult);
150
			newResult = result.recalibrateResult(newResult, oldResult);
151
			for (var i = 0; i < newResult.length; i++) {
152
				var entry = newResult[i];
153
154
				var pos = result.getResultIndex(entry.id, oldResult);
155
				if (pos > -1 && pos !== i) {
156
					nav.animateMoveDivResult(entry.id, divProviderResult, precId);
157
				}
158
159
				precId = newResult[i].id;
160
			}
161
		},
162
163
164
		animateMoveDivResult: function (entryId, divProviderResult, precId) {
165
166
			var divResult = nav.getDivEntry(entryId, divProviderResult);
167
168
			if (precId === '') {
169
				divResult.fadeTo(settings.delay_result, 0.35, function () {
170
					$(this).prependTo(divProviderResult).fadeTo(100, 1);
171
				});
172
			} else {
173
				var precItem = nav.getDivEntry(precId, divProviderResult);
174
				divResult.fadeTo(settings.delay_result, 0.35, function () {
175
					$(this).insertAfter(precItem).fadeTo(100, 1);
176
				});
177
			}
178
179
		},
180
181
182
		getDivProvider: function (providerId, providerName) {
183
			var ret = null;
184
			settings.resultContainer.children('.provider_header').each(function () {
185
				if ($(this).attr('data-id') === providerId) {
186
					ret = $(this);
187
				}
188
			});
189
190
			if (ret === null) {
191
				ret = nav.generateDivProvider(providerId, providerName);
192
				settings.resultContainer.append(ret);
193
			}
194
195
			return ret;
196
		},
197
198
199
		getDivEntry: function (resultId, divProviderResult) {
200
			var ret = null;
201
202
			divProviderResult.children('.result_entry').each(function () {
203
				if ($(this).attr('data-id') === resultId) {
204
					ret = $(this);
205
				}
206
			});
207
208
			return ret;
209
		},
210
211
212
		fillDivEntry: function (divEntry, entry) {
213
			divEntry.find('#title').text(entry.title);
214
215
			divEntry.find('#source').html('&nbsp;');
216
			if (entry.info.source !== '') {
217
				divEntry.find('#source').text(entry.info.source);
218
			}
219
220
			if (settings.options.show_hash === '1') {
221
				divEntry.find('#source').text(entry.hash);
222
			}
223
224
			nav.fillDivResultExcepts(divEntry, entry);
225
226
			if (entry.link !== '') {
227
				divEntry.off('click').on('click', function (event) {
228
					if (nav.onEntrySelect($(this), event)) {
229
						return;
230
					}
231
232
					window.open(entry.link);
233
				});
234
				divEntry.find('div').each(function () {
235
					$(this).css('cursor', 'pointer');
236
				});
237
			}
238
239
			nav.onEntryGenerated(divEntry, entry);
240
		},
241
242
243
		/**
244
		 * @namespace entry.excerpts
245
		 */
246
		fillDivResultExcepts: function (divResult, entry) {
247
			if (entry.excerpts === null) {
248
				return;
249
			}
250
251
			if (entry.excerpts.length > 0) {
252
				divResult.find('#extract').text(entry.excerpts[0]);
253
			} else {
254
				divResult.find('#extract').text('');
255
			}
256
		},
257
258
259
		onEntryGenerated: function (divEntry, entry) {
260
			if (settings.parentHasMethod('onEntryGenerated')) {
261
				settings.parent.onEntryGenerated(divEntry, entry);
262
			}
263
		},
264
265
266
		onEntrySelect: function (divEntry, event) {
267
			return !!(settings.parentHasMethod('onEntrySelect') &&
268
				settings.parent.onEntrySelect(divEntry, event));
269
		},
270
271
272
		onSearchRequest: function (data) {
273
			if (settings.parentHasMethod('onSearchRequest')) {
274
				settings.parent.onSearchRequest(data);
275
			}
276
		},
277
278
279
		onSearchReset: function () {
280
			if (settings.parentHasMethod('onSearchReset')) {
281
				settings.parent.onSearchReset();
282
			}
283
		},
284
285
286
		onResultDisplayed: function (data) {
287
			if (settings.parentHasMethod('onResultDisplayed')) {
288
				settings.parent.onResultDisplayed(data);
289
			}
290
		},
291
292
		onResultClose: function () {
293
			if (settings.parentHasMethod('onResultClose')) {
294
				settings.parent.onResultClose();
295
			}
296
		},
297
298
		onError: function (data) {
299
			if (settings.parentHasMethod('onError')) {
300
				settings.parent.onError(data);
301
			}
302
		},
303
304
		// deleteEmptyDiv: function (entry, divId) {
305
		// 	var div = entry.find(divId);
306
		// 	if (div.text() === '') {
307
		// 		div.remove();
308
		// 	}
309
		// },
310
311
312
		generateTemplateEntry: function () {
313
			var divTemplate = settings.entryTemplate;
314
			if (divTemplate === null) {
315
				divTemplate = settings.generateDefaultTemplate();
316
			}
317
318
			if (!divTemplate.length) {
319
				console.log('FullTextSearch Error: entryTemplate is not defined');
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
320
				return;
321
			}
322
323
			var tmpl = divTemplate.html();
324
			// var divNavToggle = $('<div>', {
325
			// 	id: 'app-navigation-toggle',
326
			// 	class: 'icon-menu'
327
			// });
328
			//
329
			var div = $('<div>', {class: 'result_template'});
330
			div.html(tmpl).fadeTo(0);
331
332
			return div;
333
		},
334
335
336
		generateDivEntry: function (entry, divResultContent) {
337
			var divEntry = $('<div>', {class: 'result_entry'});
338
339
			divEntry.hide();
340
			divEntry.attr('data-id', entry.id);
341
			divEntry.attr('data-link', entry.link);
342
			divEntry.attr('data-source', entry.source);
343
			divEntry.attr('data-info', JSON.stringify(entry.info));
344
			divEntry.attr('data-result', JSON.stringify(entry));
345
			divEntry.append(divResultContent);
346
347
			nav.fillDivEntry(divEntry, entry);
348
349
			return divEntry;
350
		},
351
352
353
		generateDivProvider: function (providerId, providerName) {
354
355
			var divProviderNavigation = $('<div>', {class: 'provider_navigation'});
356
			divProviderNavigation.attr('data-provider-id', providerId);
357
			divProviderNavigation.attr('data-provider-title', providerName);
358
359
			var divProviderLeftNav = $('<div>', {class: 'provider_navigation_left'});
360
			if (settings.searchProviderId !== '') {
361
				console.log('--- !!');
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
362
				var divProviderPaginationClose = $('<div>',
363
					{class: 'icon-close provider_navigation_close'});
364
				divProviderPaginationClose.on('click', function () {
365
					nav.onResultClose();
366
				});
367
				divProviderNavigation.append(divProviderPaginationClose);
368
			}
369
370
			divProviderNavigation.append(divProviderLeftNav);
371
372
373
			var divProviderPagination = $('<div>', {class: 'provider_navigation_right'});
374
			var divProviderPaginationPrev = $('<div>', {class: 'provider_navigation_prev'}).append(
375
				$('<div>', {class: 'provider_navigation_page'}).text('previous page'));
376
377
			divProviderPaginationPrev.on('click', function () {
378
				var prevPage = Number(divProviderNavigation.attr('data-page')) - 1;
379
				if (prevPage < 1) {
380
					return;
381
				}
382
383
				fullTextSearch.search({
0 ignored issues
show
Bug introduced by
The variable fullTextSearch seems to be never declared. If this is a global, consider adding a /** global: fullTextSearch */ 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...
384
					providers: providerId,
385
					options: JSON.parse(divProviderNavigation.attr('data-options')),
386
					search: divProviderNavigation.attr('data-search'),
387
					page: prevPage,
388
					size: divProviderNavigation.attr('data-size')
389
				});
390
			});
391
			divProviderPagination.append(divProviderPaginationPrev);
392
393
			divProviderPagination.append($('<div>', {class: 'provider_navigation_curr'}));
394
395
			var divProviderPaginationNext = $('<div>',
396
				{class: 'provider_navigation_next'}).append(
397
				$('<div>', {class: 'provider_navigation_page'}).text('next page'));
398
399
			divProviderPaginationNext.on('click', function () {
400
				var nextPage = Number(divProviderNavigation.attr('data-page')) + 1;
401
				if (nextPage > Number(divProviderNavigation.attr('data-max-page'))) {
402
					return;
403
				}
404
405
				fullTextSearch.search({
0 ignored issues
show
Bug introduced by
The variable fullTextSearch seems to be never declared. If this is a global, consider adding a /** global: fullTextSearch */ 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...
406
					providers: providerId,
407
					options: JSON.parse(divProviderNavigation.attr('data-options')),
408
					search: divProviderNavigation.attr('data-search'),
409
					page: nextPage,
410
					size: divProviderNavigation.attr('data-size')
411
				});
412
			});
413
			divProviderPagination.append(divProviderPaginationNext);
414
415
			divProviderNavigation.append(divProviderPagination);
416
417
			var divProviderResult = $('<div>', {class: 'provider_result'});
418
419
			var divProvider = $('<div>', {class: 'provider_header'});
420
			divProvider.hide();
421
			divProvider.attr('data-id', providerId);
422
			divProvider.append(divProviderNavigation);
423
424
			if (settings.resultHeader !== null) {
425
				divProvider.append(settings.resultHeader);
426
			}
427
428
			divProvider.append(divProviderResult);
429
430
			if (settings.resultFooter !== null) {
431
				divProvider.append(settings.resultFooter);
432
			}
433
434
			return divProvider;
435
		}
436
437
	}
438
;
439