132 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			132 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<link rel="prefetch" href="{{root}}search-index.json" />
 | 
						|
<link rel="prefetch" href="{{root}}search-metadata.json" />
 | 
						|
 | 
						|
<div id="search_placeholder">
 | 
						|
  <p>Search is loading. If you cannot see any results after a few seconds, check that JavaScript is enabled in your browser.</p>
 | 
						|
</div>
 | 
						|
 | 
						|
<div id="search_noquery">
 | 
						|
  <p>Enter a few words into the box above to start the search.</p>
 | 
						|
  <p>You may use <code>*</code> for wildcard search, and prefixes <code>+</code> for required terms and <code>-</code> for unwanted terms.</p>
 | 
						|
  <p><strong>Example:</strong> <code>laboratory noteb* +red -code</code> will find cards about <em>laboratory notebooks</em> that must also describe something <em>red</em>, but do not contain any mention of <em>code</em>.</p>
 | 
						|
</div>
 | 
						|
 | 
						|
<div id="search_success" style="display: none">
 | 
						|
  <h1>Search results</h1>
 | 
						|
  <ul id="search_results" class="search-results">
 | 
						|
  </ul>
 | 
						|
</div>
 | 
						|
 | 
						|
<div id="search_fail" style="display: none">
 | 
						|
  <h1>No results found</h1>
 | 
						|
  <p>You may try a simpler search query, or find the page <a href="{{root}}tag">by the categories</a>.</p>
 | 
						|
</div>
 | 
						|
 | 
						|
<div id="search_error" style="display: none">
 | 
						|
  <h1>Search error</h1>
 | 
						|
  <p>Search failed; this is likely caused by a badly formatted query string. Try a different query.</p>
 | 
						|
  <p>The error description is: <span style="color: red" id="search_error_text"></span></p>
 | 
						|
</div>
 | 
						|
 | 
						|
<script src="{{root}}static/lunr.min.js"></script>
 | 
						|
 | 
						|
<script>
 | 
						|
  var el_query = document.getElementById('search_query');
 | 
						|
  var el_placeholder = document.getElementById('search_placeholder');
 | 
						|
  var el_noquery = document.getElementById('search_noquery');
 | 
						|
  var el_success = document.getElementById('search_success');
 | 
						|
  var el_fail = document.getElementById('search_fail');
 | 
						|
  var el_error = document.getElementById('search_error');
 | 
						|
  var el_error_text = document.getElementById('search_error_text');
 | 
						|
  var el_results = document.getElementById('search_results');
 | 
						|
 | 
						|
  function run_search(q) {
 | 
						|
    el_placeholder.style.display = 'none';
 | 
						|
 | 
						|
    if(q.length === 0) {
 | 
						|
      el_noquery.style.display = 'block';
 | 
						|
      el_success.style.display = 'none';
 | 
						|
      el_fail.style.display = 'none';
 | 
						|
      el_error.style.display = 'none';
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    var results = []
 | 
						|
 | 
						|
    try {
 | 
						|
      results = window.search_index.search(q)
 | 
						|
    } catch (err) {
 | 
						|
      console.log("search error: " + err);
 | 
						|
      el_error_text.innerHTML = '';
 | 
						|
      el_error_text.appendChild(document.createTextNode(err.message));
 | 
						|
 | 
						|
      el_noquery.style.display = 'none';
 | 
						|
      el_success.style.display = 'none';
 | 
						|
      el_fail.style.display = 'none';
 | 
						|
      el_error.style.display = 'block';
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    el_results.innerHTML = ''
 | 
						|
    for(var ri=0; ri<results.length; ++ri) {
 | 
						|
      if (ri>=100) {
 | 
						|
        var out = document.createElement("p")
 | 
						|
        out.innerHTML = "Displaying only 100 top matches. Try searching for more specific terms to refine the search."
 | 
						|
        el_results.appendChild(out)
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      const r = results[ri]
 | 
						|
      const m = window.search_metadata[r.ref]
 | 
						|
      var out = document.createElement("li")
 | 
						|
      var a = document.createElement("a")
 | 
						|
      a.className = "search-result"
 | 
						|
      a.appendChild(document.createTextNode(m.title))
 | 
						|
      a.href = r.ref
 | 
						|
      out.appendChild(a)
 | 
						|
      for(var ti=0; ti<m.tags.length; ++ti) {
 | 
						|
        t = document.createElement("div")
 | 
						|
        t.className = "search-tag"
 | 
						|
        t.appendChild(document.createTextNode(m.tags[ti].join(" » ")));
 | 
						|
        out.appendChild(t);
 | 
						|
      }
 | 
						|
      el_results.appendChild(out)
 | 
						|
    }
 | 
						|
 | 
						|
    if(results.length === 0) {
 | 
						|
      el_noquery.style.display = 'none';
 | 
						|
      el_success.style.display = 'none';
 | 
						|
      el_fail.style.display = 'block';
 | 
						|
      el_error.style.display = 'none';
 | 
						|
    } else {
 | 
						|
      el_noquery.style.display = 'none';
 | 
						|
      el_success.style.display = 'block';
 | 
						|
      el_fail.style.display = 'none';
 | 
						|
      el_error.style.display = 'none';
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  function handle_search_input(ev) {
 | 
						|
    run_search(ev.target.value)
 | 
						|
    window.history.pushState("", "",
 | 
						|
      window.location.pathname + '?search_query='+encodeURIComponent(ev.target.value)
 | 
						|
    )
 | 
						|
    // This reinstalls the listener only _after_ the original event is done,
 | 
						|
    // preventing infinite events and CPU boils if a cat steps on the keyboard.
 | 
						|
    el_query.addEventListener('input', handle_search_input)
 | 
						|
  }
 | 
						|
 | 
						|
  Promise.all([
 | 
						|
    fetch('{{root}}search-index.json').then(response => response.text()).then(text => {
 | 
						|
      window.search_index = lunr.Index.load(JSON.parse(text))
 | 
						|
    }),
 | 
						|
    fetch('{{root}}search-metadata.json').then(response => response.text()).then(text => {
 | 
						|
      window.search_metadata = JSON.parse(text)
 | 
						|
    })
 | 
						|
  ]).then(() => {
 | 
						|
    var search_term = (new URLSearchParams(window.location.search)).get('search_query') || "";
 | 
						|
    el_query.value = search_term
 | 
						|
    handle_search_input({target: {value: search_term}})
 | 
						|
  })
 | 
						|
</script>
 |