mirror of
				https://github.com/BookStackApp/BookStack.git
				synced 2025-10-29 16:09:29 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			82 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			82 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import {htmlToDom} from "../services/dom";
 | |
| import {debounce} from "../services/util";
 | |
| import {KeyboardNavigationHandler} from "../services/keyboard-navigation";
 | |
| import {Component} from "./component";
 | |
| 
 | |
| /**
 | |
|  * Global (header) search box handling.
 | |
|  * Mainly to show live results preview.
 | |
|  */
 | |
| export class GlobalSearch extends Component {
 | |
| 
 | |
|     setup() {
 | |
|         this.container = this.$el;
 | |
|         this.input = this.$refs.input;
 | |
|         this.suggestions = this.$refs.suggestions;
 | |
|         this.suggestionResultsWrap = this.$refs.suggestionResults;
 | |
|         this.loadingWrap = this.$refs.loading;
 | |
|         this.button = this.$refs.button;
 | |
| 
 | |
|         this.setupListeners();
 | |
|     }
 | |
| 
 | |
|     setupListeners() {
 | |
|         const updateSuggestionsDebounced = debounce(this.updateSuggestions.bind(this), 200, false);
 | |
| 
 | |
|         // Handle search input changes
 | |
|         this.input.addEventListener('input', () => {
 | |
|             const value = this.input.value;
 | |
|             if (value.length > 0) {
 | |
|                 this.loadingWrap.style.display = 'block';
 | |
|                 this.suggestionResultsWrap.style.opacity = '0.5';
 | |
|                 updateSuggestionsDebounced(value);
 | |
|             }  else {
 | |
|                 this.hideSuggestions();
 | |
|             }
 | |
|         });
 | |
| 
 | |
|         // Allow double click to show auto-click suggestions
 | |
|         this.input.addEventListener('dblclick', () => {
 | |
|             this.input.setAttribute('autocomplete', 'on');
 | |
|             this.button.focus();
 | |
|             this.input.focus();
 | |
|         });
 | |
| 
 | |
|         new KeyboardNavigationHandler(this.container, () => {
 | |
|             this.hideSuggestions();
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param {String} search
 | |
|      */
 | |
|     async updateSuggestions(search) {
 | |
|         const {data: results} = await window.$http.get('/search/suggest', {term: search});
 | |
|         if (!this.input.value) {
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         const resultDom = htmlToDom(results);
 | |
| 
 | |
|         this.suggestionResultsWrap.innerHTML = '';
 | |
|         this.suggestionResultsWrap.style.opacity = '1';
 | |
|         this.loadingWrap.style.display = 'none';
 | |
|         this.suggestionResultsWrap.append(resultDom);
 | |
|         if (!this.container.classList.contains('search-active')) {
 | |
|             this.showSuggestions();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     showSuggestions() {
 | |
|         this.container.classList.add('search-active');
 | |
|         window.requestAnimationFrame(() => {
 | |
|             this.suggestions.classList.add('search-suggestions-animation');
 | |
|         })
 | |
|     }
 | |
| 
 | |
|     hideSuggestions() {
 | |
|         this.container.classList.remove('search-active');
 | |
|         this.suggestions.classList.remove('search-suggestions-animation');
 | |
|         this.suggestionResultsWrap.innerHTML = '';
 | |
|     }
 | |
| } |