PageSourceSearch

https://informe.mariacorredentora.org/core/search/js/search.js?v=90e8d4483fc0da6fe813d4cc1c297189

js mariacorredentora.org collected 2026-10-06 19:19:51 UTC 12,067 bytes, 423 lines download raw bytes

1/**
2 * ownCloud - core
3 *
4 * This file is licensed under the Affero General Public License version 3 or
5 * later. See the COPYING file.
6 *
7 * @author Jörn Friedrich Dreyer <[email protected]>
8 * @copyright Jörn Friedrich Dreyer 2014
9 */
10
11(function () {
12	/**
13	 * @class OCA.Search
14	 * @classdesc
15	 *
16	 * The Search class manages a search queries and their results
17	 *
18	 * @param $searchBox container element with existing markup for the #searchbox form
19	 * @param $searchResults container element for results und status message
20	 */
21	var Search = function($searchBox, $searchResults) {
22		this.initialize($searchBox, $searchResults);
23	};
24	/**
25	 * @memberof OC
26	 */
27	Search.prototype = {
28
29		/**
30		 * Initialize the search box
31		 *
32		 * @param $searchBox container element with existing markup for the #searchbox form
33		 * @param $searchResults container element for results und status message
34		 * @private
35		 */
36		initialize: function($searchBox, $searchResults) {
37
38			var self = this;
39
40			/**
41			 * contains closures that are called to filter the current content
42			 */
43			var filters = {};
44			this.setFilter = function(type, filter) {
45				filters[type] = filter;
46			};
47			this.hasFilter = function(type) {
48				return typeof filters[type] !== 'undefined';
49			};
50			this.getFilter = function(type) {
51				return filters[type];
52			};
53
54			/**
55			 * contains closures that are called to render search results
56			 */
57			var renderers = {};
58			this.setRenderer = function(type, renderer) {
59				renderers[type] = renderer;
60			};
61			this.hasRenderer = function(type) {
62				return typeof renderers[type] !== 'undefined';
63			};
64			this.getRenderer = function(type) {
65				return renderers[type];
66			};
67
68			/**
69			 * contains closures that are called when a search result has been clicked
70			 */
71			var handlers = {};
72			this.setHandler = function(type, handler) {
73				handlers[type] = handler;
74			};
75			this.hasHandler = function(type) {
76				return typeof handlers[type] !== 'undefined';
77			};
78			this.getHandler = function(type) {
79				return handlers[type];
80			};
81
82			var currentResult = -1;
83			var lastQuery = '';
84			var lastInApps = [];
85			var lastPage = 0;
86			var lastSize = 30;
87			var lastResults = [];
88			var timeoutID = null;
89			/* For delaying search*/
90			var timeout = null;                                    
91
92			this.getLastQuery = function() {
93				return lastQuery;
94			};
95
96			/**
97			 * Do a search query and display the results
98			 * @param {string} query the search query
99			 * @param inApps
100			 * @param page
101			 * @param size
102			 */
103			this.search = function(query, inApps, page, size) {
104				if (query) {
105					OC.addStyle('core/search','results');
106					if (typeof page !== 'number') {
107						page = 1;
108					}
109					if (typeof size !== 'number') {
110						size = 30;
111					}
112					if (typeof inApps !== 'object') {
113						var currentApp = getCurrentApp();
114						if(currentApp) {
115							inApps = [currentApp];
116						} else {
117							inApps = [];
118						}
119					}
120					// prevent double pages
121					if ($searchResults && query === lastQuery && page === lastPage && size === lastSize) {
122						return;
123					}
124					window.clearTimeout(timeoutID);
125					timeoutID = window.setTimeout(function() {
126						lastQuery = query;
127						lastInApps = inApps;
128						lastPage = page;
129						lastSize = size;
130
131						//show spinner
132						$searchResults.removeClass('hidden');
133						$status.addClass('status');
134						$status.html(t('core', 'Searching other places')+'<img class="spinner" alt="search in progress" src="'+OC.webroot+'/core/img/loading.gif" />');
135
136						// do the actual search query
137						$.getJSON(OC.generateUrl('core/search'), {query:query, inApps:inApps, page:page, size:size }, function(results) {
138							lastResults = results;
139							if (page === 1) {
140								showResults(results);
141							} else {
142								addResults(results);
143							}
144						});
145					}, 500);
146				}
147			};
148
149			//TODO should be a core method, see https://github.com/owncloud/core/issues/12557
150			function getCurrentApp() {
151				var content = document.getElementById('content');
152				if (content) {
153					var classList = document.getElementById('content').className.split(/\s+/);
154					for (var i = 0; i < classList.length; i++) {
155						if (classList[i].indexOf('app-') === 0) {
156							return classList[i].substr(4);
157						}
158					}
159				}
160				return false;
161			}
162
163			var $status = $searchResults.find('#status');
164			// summaryAndStatusHeight is a constant
165			var summaryAndStatusHeight = 118;
166
167			function isStatusOffScreen() {
168				return $searchResults.position() &&
169					($searchResults.position().top + summaryAndStatusHeight > window.innerHeight);
170			}
171
172			function placeStatus() {
173				if (isStatusOffScreen()) {
174					$status.addClass('fixed');
175				} else {
176					$status.removeClass('fixed');
177				}
178			}
179			function showResults(results) {
180				lastResults = results;
181				$searchResults.find('tr.result').remove();
182				$searchResults.removeClass('hidden');
183				addResults(results);
184			}
185			function addResults(results) {
186				var $template = $searchResults.find('tr.template');
187				jQuery.each(results, function (i, result) {
188					var $row = $template.clone();
189					$row.removeClass('template');
190					$row.addClass('result');
191
192					$row.data('result', result);
193
194					// generic results only have four attributes
195					$row.find('td.info div.name').text(result.name);
196					$row.find('td.info a').attr('href', result.link);
197
198					/**
199					 * Give plugins the ability to customize the search results. see result.js for examples
200					 */
201					if (self.hasRenderer(result.type)) {
202						$row = self.getRenderer(result.type)($row, result);
203					} else {
204						// for backward compatibility add text div
205						$row.find('td.info div.name').addClass('result');
206						$row.find('td.result div.name').after('<div class="text"></div>');
207						$row.find('td.result div.text').text(result.name);
208						if (OC.search.customResults && OC.search.customResults[result.type]) {
209							OC.search.customResults[result.type]($row, result);
210						}
211					}
212					if ($row) {
213						$searchResults.find('tbody').append($row);
214					}
215				});
216				var count = $searchResults.find('tr.result').length;
217				$status.data('count', count);
218				if (count === 0) {
219					$status.addClass('emptycontent').removeClass('status');
220					$status.html('');
221					$status.append('<div class="icon-search"></div>');
222					$status.append('<h2>' + t('core', 'No search results in other folders') + '</h2>');
223				} else {
224					$status.removeClass('emptycontent').addClass('status');
225					$status.text(n('core', '{count} search result in another folder', '{count} search results in other folders', count, {count:count}));
226				}
227			}
228			function renderCurrent() {
229				var result = $searchResults.find('tr.result')[currentResult];
230				if (result) {
231					var $result = $(result);
232					var currentOffset = $('#app-content').scrollTop();
233					$('#app-content').animate({
234						// Scrolling to the top of the new result
235						scrollTop: currentOffset + $result.offset().top - $result.height() * 2
236					}, {
237						duration: 100
238					});
239					$searchResults.find('tr.result.current').removeClass('current');
240					$result.addClass('current');
241				}
242			}
243			this.hideResults = function() {
244				$searchResults.addClass('hidden');
245				$searchResults.find('tr.result').remove();
246				lastQuery = false;
247			};
248			this.clear = function() {
249				self.hideResults();
250				if(self.hasFilter(getCurrentApp())) {
251					self.getFilter(getCurrentApp())('');
252				}
253				$searchBox.val('');
254				$searchBox.blur();
255			};
256
257			/**
258			 * Event handler for when scrolling the list container.
259			 * This appends/renders the next page of entries when reaching the bottom.
260			 */
261			function onScroll() {
262				if ($searchResults && lastQuery !== false && lastResults.length > 0) {
263					var resultsBottom = $searchResults.offset().top + $searchResults.height();
264					var containerBottom = $searchResults.offsetParent().offset().top +
265						$searchResults.offsetParent().height();
266					if ( resultsBottom < containerBottom * 1.2 ) {
267						self.search(lastQuery, lastInApps, lastPage + 1);
268					}
269					placeStatus();
270				}
271			}
272
273			$('#app-content').on('scroll', _.bind(onScroll, this));
274
275			/**
276			 * scrolls the search results to the top
277			 */
278			function scrollToResults() {
279				setTimeout(function() {
280					if (isStatusOffScreen()) {
281						var newScrollTop = $('#app-content').prop('scrollHeight') - $searchResults.height();
282						console.log('scrolling to ' + newScrollTop);
283						$('#app-content').animate({
284							scrollTop: newScrollTop
285						}, {
286							duration: 100,
287							complete: function () {
288								scrollToResults();
289							}
290						});
291					}
292				}, 150);
293			}
294
295			$('form.searchbox').submit(function(event) {
296				event.preventDefault();
297			});
298
299			$searchBox.on('search', function () {
300				if($searchBox.val() === '') {
301					if(self.hasFilter(getCurrentApp())) {
302						self.getFilter(getCurrentApp())('');
303					}
304					self.hideResults();
305				}
306			});
307			$searchBox.keyup(function(event) {
308				if (event.keyCode === 13) { //enter
309					if(currentResult > -1) {
310						var result = $searchResults.find('tr.result a')[currentResult];
311						window.location = $(result).attr('href');
312					}
313				} else if(event.keyCode === 38) { //up
314					if(currentResult > 0) {
315						currentResult--;
316						renderCurrent();
317					}
318				} else if(event.keyCode === 40) { //down
319					if(lastResults.length > currentResult + 1){
320						currentResult++;
321						renderCurrent();
322					}
323				} else {
324					/**
325			 		* Search begins 500 milliseconds after the user stops typing
326			 		*/
327					clearTimeout(timeout);
328					timeout = setTimeout(function () {
329						var query = $searchBox.val();
330						if (lastQuery !== query) {
331							currentResult = -1;
332							if (query.length > 2) {
333								self.search(query);
334							} else {
335								self.hideResults();
336							}
337							if(self.hasFilter(getCurrentApp())) {
338								self.getFilter(getCurrentApp())(query);
339							}
340						}
341    					}, 500);
342				}
343			});
344			$(document).keyup(function(event) {
345				if(event.keyCode === 27) { //esc
346					$searchBox.val('');
347					if(self.hasFilter(getCurrentApp())) {
348						self.getFilter(getCurrentApp())('');
349					}
350					self.hideResults();
351				}
352			});
353
354			$(document).keydown(function(event) {
355				if ((event.ctrlKey || event.metaKey) && // Ctrl or Command (OSX)
356					!event.shiftKey &&
357					event.keyCode === 70 && // F
358					self.hasFilter(getCurrentApp()) && // Search is enabled
359					!$searchBox.is(':focus') // if searchbox is already focused do nothing (fallback to browser default)
360				) {
361					$searchBox.focus();
362					event.preventDefault();
363				}
364			});
365
366			$searchResults.on('click', 'tr.result', function (event) {
367				var $row = $(this);
368				var item = $row.data('result');
369				if(self.hasHandler(item.type)){
370					var result = self.getHandler(item.type)($row, item, event);
371					$searchBox.val('');
372					if(self.hasFilter(getCurrentApp())) {
373						self.getFilter(getCurrentApp())('');
374					}
375					self.hideResults();
376					return result;
377				}
378			});
379			$searchResults.on('click', '#status', function (event) {
380				event.preventDefault();
381				scrollToResults();
382				return false;
383			});
384			placeStatus();
385
386			OC.Plugins.attach('OCA.Search', this);
387
388			// hide search file if search is not enabled
389			if(self.hasFilter(getCurrentApp())) {
390				return;
391			}
392			if ($searchResults.length === 0) {
393				$searchBox.hide();
394			}
395		}
396	};
397	OCA.Search = Search;
398})();
399
400$(document).ready(function() {
401	var $searchResults = $('#searchresults');
402	if ($searchResults.length > 0) {
403		$searchResults.addClass('hidden');
404		$('#app-content')
405			.find('.viewcontainer').css('min-height', 'initial');
406		$searchResults.load(OC.webroot + '/core/search/templates/part.results.html', function () {
407			OC.Search = new OCA.Search($('#searchbox'), $('#searchresults'));
408		});
409	} else {
410		_.defer(function() {
411			OC.Search = new OCA.Search($('#searchbox'), $('#searchresults'));
412		});
413	}
414});
415
416/**
417 * @deprecated use get/setRenderer() instead
418 */
419OC.search.customResults = {};
420/**
421 * @deprecated use get/setRenderer() instead
422 */
423OC.search.resultTypes = {};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.