mirror of
				https://github.com/telekom-security/tpotce.git
				synced 2025-10-31 04:22:52 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			415 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			415 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| /**
 | |
|  * ownCloud - core
 | |
|  *
 | |
|  * This file is licensed under the Affero General Public License version 3 or
 | |
|  * later. See the COPYING file.
 | |
|  *
 | |
|  * @author Jörn Friedrich Dreyer <jfd@owncloud.com>
 | |
|  * @copyright Jörn Friedrich Dreyer 2014
 | |
|  */
 | |
| 
 | |
| (function () {
 | |
| 	/**
 | |
| 	 * @class OCA.Search
 | |
| 	 * @classdesc
 | |
| 	 *
 | |
| 	 * The Search class manages a search queries and their results
 | |
| 	 *
 | |
| 	 * @param $searchBox container element with existing markup for the #searchbox form
 | |
| 	 * @param $searchResults container element for results und status message
 | |
| 	 */
 | |
| 	var Search = function($searchBox, $searchResults) {
 | |
| 		this.initialize($searchBox, $searchResults);
 | |
| 	};
 | |
| 	/**
 | |
| 	 * @memberof OC
 | |
| 	 */
 | |
| 	Search.prototype = {
 | |
| 
 | |
| 		/**
 | |
| 		 * Initialize the search box
 | |
| 		 *
 | |
| 		 * @param $searchBox container element with existing markup for the #searchbox form
 | |
| 		 * @param $searchResults container element for results und status message
 | |
| 		 * @private
 | |
| 		 */
 | |
| 		initialize: function($searchBox, $searchResults) {
 | |
| 
 | |
| 			var self = this;
 | |
| 
 | |
| 			/**
 | |
| 			 * contains closures that are called to filter the current content
 | |
| 			 */
 | |
| 			var filters = {};
 | |
| 			this.setFilter = function(type, filter) {
 | |
| 				filters[type] = filter;
 | |
| 			};
 | |
| 			this.hasFilter = function(type) {
 | |
| 				return typeof filters[type] !== 'undefined';
 | |
| 			};
 | |
| 			this.getFilter = function(type) {
 | |
| 				return filters[type];
 | |
| 			};
 | |
| 
 | |
| 			/**
 | |
| 			 * contains closures that are called to render search results
 | |
| 			 */
 | |
| 			var renderers = {};
 | |
| 			this.setRenderer = function(type, renderer) {
 | |
| 				renderers[type] = renderer;
 | |
| 			};
 | |
| 			this.hasRenderer = function(type) {
 | |
| 				return typeof renderers[type] !== 'undefined';
 | |
| 			};
 | |
| 			this.getRenderer = function(type) {
 | |
| 				return renderers[type];
 | |
| 			};
 | |
| 
 | |
| 			/**
 | |
| 			 * contains closures that are called when a search result has been clicked
 | |
| 			 */
 | |
| 			var handlers = {};
 | |
| 			this.setHandler = function(type, handler) {
 | |
| 				handlers[type] = handler;
 | |
| 			};
 | |
| 			this.hasHandler = function(type) {
 | |
| 				return typeof handlers[type] !== 'undefined';
 | |
| 			};
 | |
| 			this.getHandler = function(type) {
 | |
| 				return handlers[type];
 | |
| 			};
 | |
| 
 | |
| 			var currentResult = -1;
 | |
| 			var lastQuery = '';
 | |
| 			var lastInApps = [];
 | |
| 			var lastPage = 0;
 | |
| 			var lastSize = 30;
 | |
| 			var lastResults = [];
 | |
| 			var timeoutID = null;
 | |
| 
 | |
| 			this.getLastQuery = function() {
 | |
| 				return lastQuery;
 | |
| 			};
 | |
| 
 | |
| 			/**
 | |
| 			 * Do a search query and display the results
 | |
| 			 * @param {string} query the search query
 | |
| 			 * @param inApps
 | |
| 			 * @param page
 | |
| 			 * @param size
 | |
| 			 */
 | |
| 			this.search = function(query, inApps, page, size) {
 | |
| 				if (query) {
 | |
| 					OC.addStyle('core/search','results');
 | |
| 					if (typeof page !== 'number') {
 | |
| 						page = 1;
 | |
| 					}
 | |
| 					if (typeof size !== 'number') {
 | |
| 						size = 30;
 | |
| 					}
 | |
| 					if (typeof inApps !== 'object') {
 | |
| 						var currentApp = getCurrentApp();
 | |
| 						if(currentApp) {
 | |
| 							inApps = [currentApp];
 | |
| 						} else {
 | |
| 							inApps = [];
 | |
| 						}
 | |
| 					}
 | |
| 					// prevent double pages
 | |
| 					if ($searchResults && query === lastQuery && page === lastPage && size === lastSize) {
 | |
| 						return;
 | |
| 					}
 | |
| 					window.clearTimeout(timeoutID);
 | |
| 					timeoutID = window.setTimeout(function() {
 | |
| 						lastQuery = query;
 | |
| 						lastInApps = inApps;
 | |
| 						lastPage = page;
 | |
| 						lastSize = size;
 | |
| 
 | |
| 						//show spinner
 | |
| 						$searchResults.removeClass('hidden');
 | |
| 						$status.addClass('status');
 | |
| 						$status.html(t('core', 'Searching other places')+'<img class="spinner" alt="search in progress" src="'+OC.webroot+'/core/img/loading.gif" />');
 | |
| 
 | |
| 						// do the actual search query
 | |
| 						$.getJSON(OC.generateUrl('core/search'), {query:query, inApps:inApps, page:page, size:size }, function(results) {
 | |
| 							lastResults = results;
 | |
| 							if (page === 1) {
 | |
| 								showResults(results);
 | |
| 							} else {
 | |
| 								addResults(results);
 | |
| 							}
 | |
| 						});
 | |
| 					}, 500);
 | |
| 				}
 | |
| 			};
 | |
| 
 | |
| 			//TODO should be a core method, see https://github.com/owncloud/core/issues/12557
 | |
| 			function getCurrentApp() {
 | |
| 				var content = document.getElementById('content');
 | |
| 				if (content) {
 | |
| 					var classList = document.getElementById('content').className.split(/\s+/);
 | |
| 					for (var i = 0; i < classList.length; i++) {
 | |
| 						if (classList[i].indexOf('app-') === 0) {
 | |
| 							return classList[i].substr(4);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			var $status = $searchResults.find('#status');
 | |
| 			// summaryAndStatusHeight is a constant
 | |
| 			var summaryAndStatusHeight = 118;
 | |
| 
 | |
| 			function isStatusOffScreen() {
 | |
| 				return $searchResults.position() &&
 | |
| 					($searchResults.position().top + summaryAndStatusHeight > window.innerHeight);
 | |
| 			}
 | |
| 
 | |
| 			function placeStatus() {
 | |
| 				if (isStatusOffScreen()) {
 | |
| 					$status.addClass('fixed');
 | |
| 				} else {
 | |
| 					$status.removeClass('fixed');
 | |
| 				}
 | |
| 			}
 | |
| 			function showResults(results) {
 | |
| 				lastResults = results;
 | |
| 				$searchResults.find('tr.result').remove();
 | |
| 				$searchResults.removeClass('hidden');
 | |
| 				addResults(results);
 | |
| 			}
 | |
| 			function addResults(results) {
 | |
| 				var $template = $searchResults.find('tr.template');
 | |
| 				jQuery.each(results, function (i, result) {
 | |
| 					var $row = $template.clone();
 | |
| 					$row.removeClass('template');
 | |
| 					$row.addClass('result');
 | |
| 
 | |
| 					$row.data('result', result);
 | |
| 
 | |
| 					// generic results only have four attributes
 | |
| 					$row.find('td.info div.name').text(result.name);
 | |
| 					$row.find('td.info a').attr('href', result.link);
 | |
| 
 | |
| 					/**
 | |
| 					 * Give plugins the ability to customize the search results. see result.js for examples
 | |
| 					 */
 | |
| 					if (self.hasRenderer(result.type)) {
 | |
| 						$row = self.getRenderer(result.type)($row, result);
 | |
| 					} else {
 | |
| 						// for backward compatibility add text div
 | |
| 						$row.find('td.info div.name').addClass('result');
 | |
| 						$row.find('td.result div.name').after('<div class="text"></div>');
 | |
| 						$row.find('td.result div.text').text(result.name);
 | |
| 						if (OC.search.customResults && OC.search.customResults[result.type]) {
 | |
| 							OC.search.customResults[result.type]($row, result);
 | |
| 						}
 | |
| 					}
 | |
| 					if ($row) {
 | |
| 						$searchResults.find('tbody').append($row);
 | |
| 					}
 | |
| 				});
 | |
| 				var count = $searchResults.find('tr.result').length;
 | |
| 				$status.data('count', count);
 | |
| 				if (count === 0) {
 | |
| 					$status.addClass('emptycontent').removeClass('status');
 | |
| 					$status.html('');
 | |
| 					$status.append('<div class="icon-search"></div>');
 | |
| 					$status.append('<h2>' + t('core', 'No search results in other folders') + '</h2>');
 | |
| 				} else {
 | |
| 					$status.removeClass('emptycontent').addClass('status');
 | |
| 					$status.text(n('core', '{count} search result in another folder', '{count} search results in other folders', count, {count:count}));
 | |
| 				}
 | |
| 			}
 | |
| 			function renderCurrent() {
 | |
| 				var result = $searchResults.find('tr.result')[currentResult];
 | |
| 				if (result) {
 | |
| 					var $result = $(result);
 | |
| 					var currentOffset = $('#app-content').scrollTop();
 | |
| 					$('#app-content').animate({
 | |
| 						// Scrolling to the top of the new result
 | |
| 						scrollTop: currentOffset + $result.offset().top - $result.height() * 2
 | |
| 					}, {
 | |
| 						duration: 100
 | |
| 					});
 | |
| 					$searchResults.find('tr.result.current').removeClass('current');
 | |
| 					$result.addClass('current');
 | |
| 				}
 | |
| 			}
 | |
| 			this.hideResults = function() {
 | |
| 				$searchResults.addClass('hidden');
 | |
| 				$searchResults.find('tr.result').remove();
 | |
| 				lastQuery = false;
 | |
| 			};
 | |
| 			this.clear = function() {
 | |
| 				self.hideResults();
 | |
| 				if(self.hasFilter(getCurrentApp())) {
 | |
| 					self.getFilter(getCurrentApp())('');
 | |
| 				}
 | |
| 				$searchBox.val('');
 | |
| 				$searchBox.blur();
 | |
| 			};
 | |
| 
 | |
| 			/**
 | |
| 			 * Event handler for when scrolling the list container.
 | |
| 			 * This appends/renders the next page of entries when reaching the bottom.
 | |
| 			 */
 | |
| 			function onScroll() {
 | |
| 				if ($searchResults && lastQuery !== false && lastResults.length > 0) {
 | |
| 					var resultsBottom = $searchResults.offset().top + $searchResults.height();
 | |
| 					var containerBottom = $searchResults.offsetParent().offset().top +
 | |
| 						$searchResults.offsetParent().height();
 | |
| 					if ( resultsBottom < containerBottom * 1.2 ) {
 | |
| 						self.search(lastQuery, lastInApps, lastPage + 1);
 | |
| 					}
 | |
| 					placeStatus();
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			$('#app-content').on('scroll', _.bind(onScroll, this));
 | |
| 
 | |
| 			/**
 | |
| 			 * scrolls the search results to the top
 | |
| 			 */
 | |
| 			function scrollToResults() {
 | |
| 				setTimeout(function() {
 | |
| 					if (isStatusOffScreen()) {
 | |
| 						var newScrollTop = $('#app-content').prop('scrollHeight') - $searchResults.height();
 | |
| 						console.log('scrolling to ' + newScrollTop);
 | |
| 						$('#app-content').animate({
 | |
| 							scrollTop: newScrollTop
 | |
| 						}, {
 | |
| 							duration: 100,
 | |
| 							complete: function () {
 | |
| 								scrollToResults();
 | |
| 							}
 | |
| 						});
 | |
| 					}
 | |
| 				}, 150);
 | |
| 			}
 | |
| 
 | |
| 			$('form.searchbox').submit(function(event) {
 | |
| 				event.preventDefault();
 | |
| 			});
 | |
| 
 | |
| 			$searchBox.on('search', function () {
 | |
| 				if($searchBox.val() === '') {
 | |
| 					if(self.hasFilter(getCurrentApp())) {
 | |
| 						self.getFilter(getCurrentApp())('');
 | |
| 					}
 | |
| 					self.hideResults();
 | |
| 				}
 | |
| 			});
 | |
| 			$searchBox.keyup(function(event) {
 | |
| 				if (event.keyCode === 13) { //enter
 | |
| 					if(currentResult > -1) {
 | |
| 						var result = $searchResults.find('tr.result a')[currentResult];
 | |
| 						window.location = $(result).attr('href');
 | |
| 					}
 | |
| 				} else if(event.keyCode === 38) { //up
 | |
| 					if(currentResult > 0) {
 | |
| 						currentResult--;
 | |
| 						renderCurrent();
 | |
| 					}
 | |
| 				} else if(event.keyCode === 40) { //down
 | |
| 					if(lastResults.length > currentResult + 1){
 | |
| 						currentResult++;
 | |
| 						renderCurrent();
 | |
| 					}
 | |
| 				} else {
 | |
| 					var query = $searchBox.val();
 | |
| 					if (lastQuery !== query) {
 | |
| 						currentResult = -1;
 | |
| 						if (query.length > 2) {
 | |
| 							self.search(query);
 | |
| 						} else {
 | |
| 							self.hideResults();
 | |
| 						}
 | |
| 						if(self.hasFilter(getCurrentApp())) {
 | |
| 							self.getFilter(getCurrentApp())(query);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			});
 | |
| 			$(document).keyup(function(event) {
 | |
| 				if(event.keyCode === 27) { //esc
 | |
| 					$searchBox.val('');
 | |
| 					if(self.hasFilter(getCurrentApp())) {
 | |
| 						self.getFilter(getCurrentApp())('');
 | |
| 					}
 | |
| 					self.hideResults();
 | |
| 				}
 | |
| 			});
 | |
| 
 | |
| 			$(document).keydown(function(event) {
 | |
| 				if ((event.ctrlKey || event.metaKey) && // Ctrl or Command (OSX)
 | |
| 					!event.shiftKey &&
 | |
| 					event.keyCode === 70 && // F
 | |
| 					self.hasFilter(getCurrentApp()) && // Search is enabled
 | |
| 					!$searchBox.is(':focus') // if searchbox is already focused do nothing (fallback to browser default)
 | |
| 				) {
 | |
| 					$searchBox.focus();
 | |
| 					event.preventDefault();
 | |
| 				}
 | |
| 			});
 | |
| 
 | |
| 			$searchResults.on('click', 'tr.result', function (event) {
 | |
| 				var $row = $(this);
 | |
| 				var item = $row.data('result');
 | |
| 				if(self.hasHandler(item.type)){
 | |
| 					var result = self.getHandler(item.type)($row, item, event);
 | |
| 					$searchBox.val('');
 | |
| 					if(self.hasFilter(getCurrentApp())) {
 | |
| 						self.getFilter(getCurrentApp())('');
 | |
| 					}
 | |
| 					self.hideResults();
 | |
| 					return result;
 | |
| 				}
 | |
| 			});
 | |
| 			$searchResults.on('click', '#status', function (event) {
 | |
| 				event.preventDefault();
 | |
| 				scrollToResults();
 | |
| 				return false;
 | |
| 			});
 | |
| 			placeStatus();
 | |
| 
 | |
| 			OC.Plugins.attach('OCA.Search', this);
 | |
| 
 | |
| 			// hide search file if search is not enabled
 | |
| 			if(self.hasFilter(getCurrentApp())) {
 | |
| 				return;
 | |
| 			}
 | |
| 			if ($searchResults.length === 0) {
 | |
| 				$searchBox.hide();
 | |
| 			}
 | |
| 		}
 | |
| 	};
 | |
| 	OCA.Search = Search;
 | |
| })();
 | |
| 
 | |
| $(document).ready(function() {
 | |
| 	var $searchResults = $('#searchresults');
 | |
| 	if ($searchResults.length > 0) {
 | |
| 		$searchResults.addClass('hidden');
 | |
| 		$('#app-content')
 | |
| 			.find('.viewcontainer').css('min-height', 'initial');
 | |
| 		$searchResults.load(OC.webroot + '/core/search/templates/part.results.html', function () {
 | |
| 			OC.Search = new OCA.Search($('#searchbox'), $('#searchresults'));
 | |
| 		});
 | |
| 	} else {
 | |
| 		_.defer(function() {
 | |
| 			OC.Search = new OCA.Search($('#searchbox'), $('#searchresults'));
 | |
| 		});
 | |
| 	}
 | |
| });
 | |
| 
 | |
| /**
 | |
|  * @deprecated use get/setRenderer() instead
 | |
|  */
 | |
| OC.search.customResults = {};
 | |
| /**
 | |
|  * @deprecated use get/setRenderer() instead
 | |
|  */
 | |
| OC.search.resultTypes = {};
 | 
