Completed
Push — master ( f7a2c9...9ebf95 )
by Maxence
02:16
created

Navigate.navigateTimedSearch   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
nc 4
nop 0
dl 0
loc 16
rs 9.4285
c 1
b 0
f 0

1 Function

Rating   Name   Duplication   Size   Complexity  
A 0 3 1
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
27
/** global: OCA */
28
/** global: _ */
29
30
var fullTextSearch = OCA.FullTextSearch.api;
31
32
33
var elements = {
34
	searchTimeout: null,
35
	search_input: null,
36
	search_submit: null,
37
	search_result: null,
38
	search_json: null
39
};
40
41
var Navigate = function () {
42
	this.init();
43
};
44
45
Navigate.prototype = {
46
47
	currentTagsResult: {},
48
	selectedTags: {},
49
50
	init: function () {
51
		var self = this;
52
53
		elements.search_input = $('#search_input');
54
		elements.search_submit = $('#search_submit');
55
		elements.search_result = $('#search_result');
56
		elements.search_panels = $('#search_navigation');
57
//		elements.search_json = $('#search_json');
58
		elements.divHeader = $('#search_header');
59
		box_elements.searchError = $('#search_error');
0 ignored issues
show
Bug introduced by
The variable box_elements seems to be never declared. If this is a global, consider adding a /** global: box_elements */ 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...
60
61
		//	fullTextSearch.setEntryTemplate($('#template_entry'), self);
62
		fullTextSearch.setResultContainer(elements.search_result);
63
64
		elements.search_input.on('input', this.navigateTimedSearch);
65
		// function () {
66
		// 	self.resetSearch();
67
		// 	if (elements.searchTimeout === null && self.initSearch()) {
68
		// 		elements.searchTimeout = _.delay(function () {
69
		// 			self.initSearch();
70
		// 			elements.searchTimeout = null;
71
		// 		}, 3000);
72
		// 	}
73
		// });
74
75
		//
76
		// $(document).keypress(function (e) {
77
		// 	if (e.which === 13) {
78
		// 		self.initSearch(true);
79
		// 	}
80
		// });
81
82
		self.initPanels();
83
	},
84
85
86
	navigateTimedSearch: function () {
87
88
		if (curr.lastSearchTimer !== null) {
0 ignored issues
show
Bug introduced by
The variable curr seems to be never declared. If this is a global, consider adding a /** global: curr */ 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...
89
			window.clearTimeout(curr.lastSearchTimer);
90
		}
91
92
		curr.lastSearchTimer = window.setTimeout(function () {
93
			OCA.FullTextSearch.navigate.initSearch();
94
		}, settings.searchEntryTimer);
0 ignored issues
show
Bug introduced by
The variable settings seems to be never declared. If this is a global, consider adding a /** global: settings */ 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...
95
96
		if (curr.lastRequestTimer === null) {
0 ignored issues
show
Bug introduced by
The variable curr seems to be never declared. If this is a global, consider adding a /** global: curr */ 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...
97
			curr.lastRequestTimer = window.setTimeout(function () {
98
				OCA.FullTextSearch.navigate.initSearch();
99
			}, settings.searchRequestTimer);
0 ignored issues
show
Bug introduced by
The variable settings seems to be never declared. If this is a global, consider adding a /** global: settings */ 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...
100
		}
101
	},
102
103
104
	initPanels: function () {
105
		var self = this;
106
107
		$.ajax({
108
			method: 'GET',
109
			url: OC.generateUrl('/apps/fulltextsearch/navigation/panels')
0 ignored issues
show
Bug introduced by
The variable OC seems to be never declared. If this is a global, consider adding a /** global: OC */ 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...
110
		}).done(function (res) {
111
			self.displayPanels(res);
112
		});
113
	},
114
115
116
	displayPanels: function (data) {
117
		var self = this;
118
119
		var ak = Object.keys(data);
120
		for (var i = 0; i < ak.length; i++) {
121
			var providerAppId = ak[i];
122
			var title = data[ak[i]]['title'];
0 ignored issues
show
Coding Style introduced by
['title'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
123
			var nav = data[ak[i]]['navigation'];
0 ignored issues
show
Coding Style introduced by
['navigation'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
124
			var providerId = data[ak[i]]['provider'];
0 ignored issues
show
Coding Style introduced by
['provider'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
125
126
			if (nav.css !== undefined) {
127
				OC.addStyle(providerAppId, nav.css);
0 ignored issues
show
Bug introduced by
The variable OC seems to be never declared. If this is a global, consider adding a /** global: OC */ 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...
128
			}
129
130
			var li = $('<li>', {class: (nav.options !== undefined) ? 'collapsible open' : ''});
131
			var aIcon = $('<a>', {
132
				href: '#',
133
				class: (nav.icon !== undefined) ? nav.icon : 'search_icon'
134
			});
135
			aIcon.text(title);
136
137
			var ul = $('<ul>');
138
			if (nav.options !== undefined) {
139
140
				aIcon.on('click', 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...
141
					var li = $(this).closest('li');
142
					if (li.hasClass('open')) {
143
						li.removeClass('open');
144
					} else {
145
						li.addClass('open');
146
					}
147
				});
148
149
				for (var j = 0; j < nav.options.length; j++) {
150
					var sub = nav.options[j];
151
					self.displayPanelCheckbox(ul, sub);
152
					self.displayPanelInput(ul, sub);
153
					self.displayPanelTags(ul, sub);
154
					self.displayPanelSearch(providerAppId, ul, sub);
155
					//
156
					// <p id="tag_filter" class="open">
157
					// 		<input value="" style="display: none;" type="text">
158
					// 		<ul class="tagit ui-widget ui-widget-content ui-corner-all">
159
					// 		<li class="tagit-new">
160
					// 		<input class="ui-widget-content ui-autocomplete-input"
161
					// placeholder="Filter by tag" autocomplete="off" type="text"> <span role="status"
162
					// aria-live="polite" class="ui-helper-hidden-accessible"> 1 result is available,
163
					// use up and down arrow keys to navigate.</span></li> <li class="tagit-choice
164
					// ui-widget-content ui-state-default ui-corner-all"> <span
165
					// class="tagit-label">test</span><a class="close"><span class="text-icon">×</span>
166
					// <span class="ui-icon ui-icon-close"></span></a></li> <li class="tagit-choice
167
					// ui-widget-content ui-state-default ui-corner-all"> <span
168
					// class="tagit-label">perdu</span><a class="close"><span class="text-icon">×</span>
169
					// <span class="ui-icon ui-icon-close"></span></a></li></ul> </p>
170
171
172
				}
173
			}
174
175
			li.append(aIcon);
176
			var aInput = $('<input>', {
177
				class: 'search_checkbox',
178
				type: 'checkbox',
179
				'data-provider': ak[i],
180
				'data-provider-id': providerId
181
			});
182
			aInput.change(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...
183
				self.initSearch();
184
			});
185
186
			li.append(aInput);
187
			li.append(ul);
188
189
			elements.search_panels.append(li);
190
		}
191
192
	},
193
194
195
	displayPanelOptionTitle (sub) {
0 ignored issues
show
Backwards Compatibility introduced by
'concise methods' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).
Loading history...
196
		return $('<a>', {
197
			href: '#',
198
			class: 'ulsub',
199
			text: sub.title
200
		});
201
	},
202
203
204
	displayPanelCheckbox: function (ul, sub) {
205
206
		if (sub.type !== 'checkbox') {
207
			return;
208
		}
209
210
		var self = this;
211
		var subA = this.displayPanelOptionTitle(sub);
212
		var subAInput = $('<input>', {
213
			class: 'search_checkbox_sub',
214
			type: 'checkbox',
215
			'data-option': sub.name
216
		});
217
		subAInput.change(function () {
218
			self.initSearch();
219
		});
220
221
		ul.append($('<li>').append(subA).append(subAInput));
222
	},
223
224
225
	displayPanelInput: function (ul, sub) {
226
		if (sub.type !== 'input') {
227
			return;
228
		}
229
230
		var self = this;
231
		var subA = this.displayPanelOptionTitle(sub);
232
		var subAInput = $('<input>', {
233
			class: 'search_input_sub search_input_sub_' + sub.size,
234
			type: 'text',
235
			placeholder: sub.placeholder,
236
			'data-option': sub.name
237
		});
238
		subAInput.on('input', function () {
239
			self.initSearch();
240
		});
241
242
		ul.append($('<li>').append(subA).append(subAInput));
243
	},
244
245
246
	displayPanelTags: function (ul, sub) {
247
		if (sub.type !== 'tags') {
248
			return;
249
		}
250
251
		var self = this;
0 ignored issues
show
Unused Code introduced by
The variable self seems to be never used. Consider removing it.
Loading history...
252
		var subAInput = $('<input>', {
253
			id: sub.name,
254
			class: 'search_tags_sub',
255
			type: 'text',
256
			placeholder: sub.title,
257
			list: sub.name + '_datalist',
258
			'data-option': sub.name
259
		});
260
261
		var subADataList = $('<datalist>', {
262
			id: sub.name + '_datalist'
263
		});
264
265
		sub.list.forEach(function (item) {
266
			subADataList.append($('<option>', {value: item}));
267
		});
268
269
270
		/**
271
		 * <div class="systemTagsInfoView">
272
		 *       <div class="systemTagsInputFieldContainer">
273
		 *           <div id="s2id_autogen15" class="select2-container select2-container-multi
274
		 * systemTagsInputField systemtags-select2-container">
275
		 *               <ul class="select2-choices">
276
		 *                   <li class="select2-search-choice">
277
		 *                       <div>
278
		 *                           <span class="label">dsfsdfds</span>
279
		 *                       </div>
280
		 *                       <a href="#" class="select2-search-choice-close" tabindex="-1"></a>
281
		 *                   </li>
282
		 *               </ul>
283
		 *           </div>
284
		 *           <input class="systemTagsInputField select2-offscreen" name="tags"
285
		 * value="5,4,3,1,2,6" tabindex="-1" type="hidden">
286
		 *       </div>
287
		 * </div>
288
		 */
289
		// subAInput.on('change', function (e) {
290
		// 	var div = $(this);
291
		// 	if (e.which === 13 && div.val() !== '') {
292
		// 		self.selectPanelTags($(this).attr('id'));
293
		// 	}
294
		//
295
		//
296
		// 	var url = '/apps/' + div.attr('data-provider');
297
		// 	var route = JSON.parse(div.attr('data-route'));
298
		//
299
		// 	route.url = url + route.url;
300
		// 	self.quickSearch(route, div.val(), function (res) {
301
		// 		self.resultTagsSearch(div, res);
302
		// 	});
303
		// });
304
305
		ul.append($('<li>').append(subAInput).append(subADataList));
306
	},
307
308
	displayPanelSearch: function (appId, ul, sub) {
309
		var self = this;
310
311
		if (sub.type !== 'search') {
312
			return;
313
		}
314
315
		var subAInput = $('<input>', {
316
			id: sub.name,
317
			class: 'search_tags_sub',
318
			type: 'text',
319
			placeholder: sub.title,
320
			list: sub.name + '_datalist',
321
			'data-option': sub.name,
322
			'data-provider': appId,
323
			'data-route': JSON.stringify(sub.route)
324
		});
325
326
		var subADataList = $('<datalist>', {
327
			id: sub.name + '_datalist'
328
		});
329
330
331
		subAInput.on('keypress', function (e) {
332
			var div = $(this);
333
			if (e.which === 13 && div.val() !== '') {
334
				self.selectPanelTags($(this).attr('id'));
335
			}
336
337
338
			var url = '/apps/' + div.attr('data-provider');
339
			var route = JSON.parse(div.attr('data-route'));
340
341
			route.url = url + route.url;
342
			self.quickSearch(route, div.val(), function (res) {
343
				self.resultTagsSearch(div, res);
344
			});
345
		});
346
347
		ul.append($('<li>').append(subAInput).append(subADataList));
348
	},
349
350
351
	// selectPanelTags: function (panelId) {
352
	// 	if (this.currentTagsResult === undefined) {
353
	// 		return;
354
	// 	}
355
	//
356
	// 	var tags = this.currentTagsResult[panelId];
357
	// 	if (tags.length === 0) {
358
	// 		return;
359
	// 	}
360
	//
361
	// 	if (this.selectedTags[panelId] === undefined)
362
	// 		this.selectedTags[panelId] = [];
363
	// 	this.selectedTags[panelId].push(tags[0]);
364
	//
365
	// 	console.log('etntree' + JSON.stringify(this.selectedTags[panelId]));
366
	// },
367
	//
368
	//
369
	// resultTagsSearch: function (div, res) {
370
	// 	this.currentTagsResult[div.attr('id')] = res;
371
	// 	var datalistId = div.attr('data-option') + '_datalist';
372
	// 	var datalist = $('#' + datalistId);
373
	//
374
	// 	datalist.empty();
375
	// 	res.forEach(function (item) {
376
	// 		datalist.append($('<option>', {value: item}));
377
	// 	});
378
	// },
379
380
381
	getProviders: function () {
382
		var providers = [];
383
		elements.search_panels.find('input').each(function () {
384
			if ($(this).hasClass('search_checkbox') && $(this).is(":checked")) {
385
				providers.push($(this).attr('data-provider-id'));
386
			}
387
		});
388
389
		if (providers.length === 0) {
390
			return 'all';
391
		}
392
393
		return providers;
394
	},
395
396
397
	getOptions: function () {
398
		var options = {};
399
		elements.search_panels.find('input').each(function () {
400
			if ($(this).hasClass('search_checkbox_sub')) {
401
				options[$(this).attr('data-option')] = (($(this).is(':checked')) ? '1' : '0');
402
			}
403
404
			if ($(this).hasClass('search_input_sub')) {
405
				options[$(this).attr('data-option')] = $(this).val();
406
			}
407
		});
408
409
		return options;
410
	},
411
412
413
	initSearch: function () {
414
		var search = elements.search_input.val();
415
416
		if (search.length < 1) {
417
			return false;
418
		}
419
420
		var providers = this.getProviders();
421
		var options = this.getOptions();
422
423
		this.displayProviderResults(providers);
424
425
		var request = {
426
			providers: providers,
427
			options: options,
428
			search: search,
429
			page: curr.page
0 ignored issues
show
Bug introduced by
The variable curr seems to be never declared. If this is a global, consider adding a /** global: curr */ 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...
430
		};
431
432
		fullTextSearch.search(request, this.searchResult);
433
		return true;
434
	},
435
436
437
	quickSearch: function (route, search, callback) {
438
		$.ajax({
439
			method: route.verb,
440
			url: OC.generateUrl(route.url),
0 ignored issues
show
Bug introduced by
The variable OC seems to be never declared. If this is a global, consider adding a /** global: OC */ 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...
441
			data: {
442
				search: search
443
			}
444
		}).done(function (res) {
445
			if (_.has(res, 'error')) {
446
				return;
447
			}
448
449
			callback(res);
450
		});
451
	},
452
453
454
	displayProviderResults: function (providers) {
455
		elements.search_result.children('DIV.provider_header').each(function () {
456
			if (providers === 'all' || providers.indexOf($(this).attr('data-id')) > -1) {
457
				$(this).stop().slideDown(100).fadeTo(settings.delay_provider, 1);
0 ignored issues
show
Bug introduced by
The variable settings seems to be never declared. If this is a global, consider adding a /** global: settings */ 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...
458
			} else if ($(this).css('display') !== 'none') {
459
				$(this).stop().fadeTo(settings.delay_provider, 0).slideUp(100);
460
			}
461
		});
462
	},
463
464
465
	resetSearch: function () {
466
		// if (elements.search_input.val() !== '') {
467
		// 	return;
468
		// }
469
	},
470
471
472
	searchResult: function (result) {
473
474
		if (elements.search_json !== null) {
475
			elements.search_json.text(JSON.stringify(result));
476
		}
477
478
		// console.log(JSON.stringify(result));
479
//			OCA.notification.onFail('Search returned no result');
480
//		OCA.notification.onSuccess('Search returned ' + res.meta.size + ' result(s)');
481
482
	},
483
484
485
	onError: function (message) {
486
		console.log('error while searching: ' + message);
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...
487
	},
488
489
490
	// onEntryGenerated: function (entry) {
491
	// 	this.deleteEmptyDiv(entry, '#line1');
492
	// 	this.deleteEmptyDiv(entry, '#line2');
493
	// },
494
495
496
	deleteEmptyDiv: function (entry, divId) {
497
		var div = entry.find(divId);
498
		if (div.text() === '') {
499
			div.remove();
500
		}
501
	}
502
503
504
};
505
506
OCA.FullTextSearch.Navigate = Navigate;
507
508
509
$(document).ready(function () {
510
	OCA.FullTextSearch.navigate = new Navigate();
511
});
512
513
514
515